Skip to content

Commit

Permalink
Merge pull request #7 from chrismichaels84/develop
Browse files Browse the repository at this point in the history
Merge Develop into Master (v0.8.2)
  • Loading branch information
Michael Wilson committed Jun 5, 2015
2 parents 14baf76 + 6edda3c commit 8dcf94a
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 19 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Changelog
All Notable changes to `Manager` will be documented in this file

# V0.8.2 - 2015-6-3
- Allow any value in manager initialization, will be cast to array
- Throw exception if nesting under an existing value that is not an array
- Added CustomizedManager test suite and tests for the above
- ManagesItemsTrait::__toJson() accepts options
- alias all() to getAll()

# V0.8.1 - 2015-5-12
- Use initManager() to initialize Manager when extending the base class or using traits

# v0.8 - 2015-4-19
This was the first public release version

Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Data Manager

[![Latest Version](https://img.shields.io/github/release/chrismichaels84/data-manager.svg?style=flat-square)](https://github.com/chrismichaels84/data-manager/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
[![Build Status](https://img.shields.io/travis/chrismichaels84/data-manager/master.svg?style=flat-square)](https://travis-ci.org/chrismichaels84/data-manager)
Expand Down Expand Up @@ -41,13 +40,15 @@ $manager = new Michaels\Manager\Manager([
]
]
]);
// Note, you may initialze Manager with an array or any instance of Traversable (like Manager itself)

/* Basic Usage. All works with dot notation as well */
$manager->add('name', 'value');
$manager->add('some.nested.data', 3); // Use dot notation for namespacing or nesting
$manager->get('name'); // 'value'
$manager->get('doesntexist', 'fallback'); // 'fallback'
$manager->getAll(); // returns array of all items
$manager->all(); // returns array of all items
$manager->exists('name'); // true
$manager->exists('some.starting.data'); // true
$manager->exists('nope'); // false
Expand Down Expand Up @@ -84,16 +85,16 @@ class MyContainer {
}
```

If you do use a trait, and want to initialize your class at construction, you cannot declare $items in your class (this will throw a fatal error). So, you can assign an array in your constructor like ```$this->items = $items```. I suggest, however, that you use the `initManager()` method. In the future initialization may be more complex than just assigning an array.
If you do use a trait, and want to initialize your class at construction, you cannot declare $items in your class (this will throw a fatal error). Use the `initManager()` method instead.

```php
class MyClass
{
use ManagesItemsTrait;

public function __construct(array $beginningItems)
public function __construct($beginningItems)
{
$this->initManager($beginningItems); // or $this->items = $beginningItems;
$this->initManager($beginningItems);
}
}

Expand All @@ -105,7 +106,12 @@ You may also use the **tests** under `tests/traits` to test your integrated func

## Exceptions
If you try to `get()` an item that doesn't exist, and there is no fallback, an `ItemNotFoundException` will be thrown.


If you try to nest under an existing value that is not an array, an `NestingUnderNonArrayException` will be thrown.
```php
$manager = new Manager(['one' => 1]);
$manager->add("one.two", "two-value"); // exception
```
## Interoperability
Data Manager is [PSR compliant](http://www.php-fig.org/) and [Container Interoperability](https://github.com/container-interop/container-interop) compliant. Any oversights, please let me know.

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "michaels/data-manager",
"description": "Simple data manager for nested data, dot notation access, extendability, and container interoperability.",
"description": "Simple data manager for nested data, dot notation array access, extendability, and container interoperability.",
"keywords": [
"data", "collection", "container", "manager",
"nest", "nested", "array", "dot notation",
Expand Down
11 changes: 9 additions & 2 deletions src/Contracts/ManagesItemsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface ManagesItemsInterface
*
* @param array $items
*/
public function initManager(array $items = []);
public function initManager($items);

/**
* Adds a single item.
Expand Down Expand Up @@ -46,6 +46,13 @@ public function get($alias, $fallback = null);
*/
public function getAll();

/**
* Return all items as array
*
* @return array
*/
public function all();

/**
* Confirm or deny that an item exists
*
Expand Down Expand Up @@ -92,7 +99,7 @@ public function clear();
* @param array $items
* @return mixed
*/
public function reset(array $items);
public function reset($items);

/**
* Returns json serialized representation of array of items
Expand Down
21 changes: 21 additions & 0 deletions src/Exceptions/NestingUnderNonArrayException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
namespace Michaels\Manager\Exceptions;

use Exception;
use Interop\Container\Exception\ContainerException;
use Psr\Log\InvalidArgumentException;

/**
* NestingUnderNonArrayException
*
* Thrown if you try to nest a new value under an existing non-array value
*
* $manager = new Manager(['one' => 1]);
* $manager->add("one.two", "two-value");
*
* @package Michaels\Manager
*/
class NestingUnderNonArrayException extends InvalidArgumentException
{

}
61 changes: 51 additions & 10 deletions src/Traits/ManagesItemsTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
namespace Michaels\Manager\Traits;

use Michaels\Manager\Exceptions\ItemNotFoundException;
use Michaels\Manager\Exceptions\NestingUnderNonArrayException;
use Traversable;

/**
* Manages complex, nested data
Expand All @@ -21,9 +23,9 @@ trait ManagesItemsTrait
* Build a new manager instance
* @param array $items
*/
public function __construct(array $items = [])
public function __construct($items = [])
{
$this->items = $items;
$this->initManager($items);
}

/**
Expand All @@ -34,9 +36,9 @@ public function __construct(array $items = [])
*
* @param array $items
*/
public function initManager(array $items = [])
public function initManager($items = [])
{
$this->items = $items;
$this->items = is_array($items) ? $items : $this->getArrayableItems($items);
}

/**
Expand All @@ -60,8 +62,22 @@ public function add($alias, $item = null)

// No, we are adding a single item
$loc = &$this->items;
foreach (explode('.', $alias) as $step) {

$pieces = explode('.', $alias);
$currentLevel = 1;
$nestLevels = count($pieces) - 1;

foreach ($pieces as $step) {
// Make sure we are not trying to nest under a non-array. This is gross
// https://github.com/chrismichaels84/data-manager/issues/6

// 1. Not at the last (value set) level, 2. The nest level is already set, 3. and is not an array
if ($nestLevels > $currentLevel && isset($loc[$step]) && !is_array($loc[$step])) {
throw new NestingUnderNonArrayException();
}

$loc = &$loc[$step];
$currentLevel++;
}
$loc = $item;

Expand Down Expand Up @@ -109,6 +125,11 @@ public function getAll()
return $this->items;
}

public function all()
{
return $this->getAll();
}

/**
* Confirm or deny that an item exists
*
Expand Down Expand Up @@ -189,18 +210,20 @@ public function clear()
* @param array $items
* @return mixed
*/
public function reset(array $items)
public function reset($items)
{
$this->items = $items;
$this->initManager($items);
}

/**
* Returns json serialized representation of array of items
* Get the collection of items as JSON.
*
* @param int $options
* @return string
*/
public function toJson()
public function toJson($options = 0)
{
return json_encode($this->getAll());
return json_encode($this->getAll(), $options);
}

/**
Expand All @@ -220,4 +243,22 @@ public function __toString()
{
return $this->toJson();
}

/**
* Results array of items from Collection or Arrayable.
*
* @param mixed $items
* @return array
*/
protected function getArrayableItems($items)
{
if ($items instanceof self || $items instanceof ManagesItemsTrait) {
return $items->getAll();

} elseif ($items instanceof Traversable) {
return iterator_to_array($items);
}

return (array) $items;
}
}
24 changes: 24 additions & 0 deletions tests/CustomizedManagerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
namespace Michaels\Manager\Test;

use Michaels\Manager\Manager;
use Michaels\Manager\Test\Stubs\CustomizedManagerStub;

/**
* Tests customized implementations of Manager.
* Does NOT test ManagesItemsTrait api.
*/
class CustomizedManagerTest extends \PHPUnit_Framework_TestCase {

public function testInitManager()
{
$expectedItems = ['one' => 1, 'two' => 2];
$expectedOther = 'other-field';

$manager = new CustomizedManagerStub($expectedItems, $expectedOther);

$this->assertEquals($expectedItems, $manager->getAll(), "failed to return the items from initManager");
$this->assertEquals($expectedOther, $manager->getOther(), "failed to return customized field");
}
}

1 change: 1 addition & 0 deletions tests/Stubs/ChainsNestedItemsTraitStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
class ChainsNestedItemsTraitStub
{
use ManagesItemsTrait, ChainsNestedItemsTrait;

}
22 changes: 22 additions & 0 deletions tests/Stubs/CustomizedManagerStub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
namespace Michaels\Manager\Test\Stubs;
use Michaels\Manager\Manager;

/**
* Class CustomizedManagerStub
* @package Stubs
*/
class CustomizedManagerStub extends Manager
{
protected $other;
public function __construct($items, $other)
{
$this->initManager($items);
$this->other = $other;
}

public function getOther()
{
return $this->other;
}
}
1 change: 1 addition & 0 deletions tests/Stubs/ManagesItemsTraitStub.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
class ManagesItemsTraitStub
{
use ManagesItemsTrait;

}
67 changes: 66 additions & 1 deletion tests/Traits/ManagesItemsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,68 @@ private function assertFullManifest($manifest = null, $message = false)
}

/** Begin Tests **/
public function testInitializeWithData()
public function testInitManagerFromArray()
{
$manager = new Manager($this->testData);

$this->assertEquals($this->testData, $manager->getAll(), "Failed to return identical values set at instantiation");
}

public function testInitManagerFromSingle()
{
$manager = new Manager('foo');
$this->assertEquals(['foo'], $manager->getAll());
}

public function testInitManagerFromNull()
{
$manager = new Manager(null);
$this->assertEquals([], $manager->getAll());
$manager = new Manager();
$this->assertEquals([], $manager->getAll());
}

public function testInitManagerFromManager()
{
$firstManager = new Manager(['foo' => 'bar']);
$secondManager = new Manager($firstManager);
$this->assertEquals(['foo' => 'bar'], $secondManager->getAll());
}

/* ToDo: Figure out how to make nested objects at initialization pass */
/* Use optional flag to flatten objects? */
/*public function testInitManagerWithNestedManagers()
{
$firstManager = new Manager(['five' => 5]);
$secondManager = new Manager(['four' => $firstManager]);
$thirdManager = new Manager(['three' => $secondManager]);
$fourthManager = new Manager(['two' => $thirdManager]);
$topManager = new Manager(['one' => $fourthManager]);
$expected = [
'one' => [
'two' => [
'three' => [
'four' => [
'five' => 5
]
]
]
]
];
$this->assertEquals($expected, $topManager->getAll());
$this->assertEquals(5, $topManager->get("one.two.three.four.five"));
}*/

public function testInitManagerFromObject()
{
$object = new stdClass();
$object->foo = 'bar';
$manager = new Manager($object);
$this->assertEquals(['foo' => 'bar'], $manager->getAll());
}

public function testAddAndGetSingleItem()
{
$this->manager->add('alias', 'value');
Expand Down Expand Up @@ -244,4 +299,14 @@ public function testIsEmpty()
$this->manager->add($this->testData);
$this->assertFalse($this->manager->isEmpty(), "failed to deny an empty manager");
}

/**
* @expectedException \Michaels\Manager\Exceptions\NestingUnderNonArrayException
*/
public function testThrowExceptionIfTryingToNestUnderANonArray()
{
$manager = new Manager(['one' => 1, 'two' => 2]);

$manager->add("one.two.three", "three-value");
}
}

0 comments on commit 8dcf94a

Please sign in to comment.