Skip to content

Commit

Permalink
begin better documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Wilson committed Aug 22, 2016
1 parent fd98ec1 commit 59f25fc
Show file tree
Hide file tree
Showing 9 changed files with 397 additions and 4 deletions.
40 changes: 40 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Contributing

Contributions are **welcome** and will be fully **credited**.

We accept contributions via Pull Requests on [Github](https://github.com/chrismichaels84/data-manager).

## Pull Requests

- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).

- **Add tests!** - Your patch won't be accepted if it doesn't have tests.

- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.

- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.

- **Create feature branches** - Don't ask us to pull from your master branch.

- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.

- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.

## Running Tests

``` bash
$ phpunit
```

## Branches
The **master** branch always contains the most up-to-date, production ready release. In most cases, this will be the same as the latest release under the "releases" tab.

the **develop** branch holds work in progress for the next release. Any work here should be stable. The idea is that security patches, refactors, and new features are merged into this branch. Once enough patches has been tested here, it will be merged into `master` and released. This branch should always be stable.

**feature-** branches hold in progress work for upcoming features destined for future major or minor releases. These can be unstable.

**patch-** branches hold in progress patches for upcoming point releases, security patches, and refactors. These can be unstable.

Be sure to fetch often so you keep your sources up-to-date!

**Happy coding**!
21 changes: 21 additions & 0 deletions docs/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The MIT License (MIT)

Copyright (c) 2015 Michael Wilson <chrismichaels84@gmail.com>

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
> in the Software without restriction, including without limitation the rights
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> copies of the Software, and to permit persons to whom the Software is
> furnished to do so, subject to the following conditions:
>
> The above copyright notice and this permission notice shall be included in
> all copies or substantial portions of the Software.
>
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> THE SOFTWARE.
24 changes: 24 additions & 0 deletions docs/arrayable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Data Manager: Arrayable Trait
If you include the `Michaels\Manager\ArrayableTrait`, then you can use Manager as an array:

```php
$manager = new Manager([
'one' => 'a',
'two' => [
'three' => 'b'
]
]);

$manager['two']['three']; // 'b'
$manager['four'] = 'c'
isset($manager['one']); // true
unset($manager['one']);
count($manager); // 2
json_encode($manager);

foreach ($manager as $key => $value) {
//...
}
```

Note that this is considered `Traversable`, but will NOT pass an `is_array()` check.
19 changes: 19 additions & 0 deletions docs/chains.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Data Manager: Fluent Chain Access
If you prefer to access data as though they were nested PHP objects, `use Michaels\Manager\ChainsNestedItemsTrait`.

This allows you to
```php
$manager = new Manager([
'some' => [
'starting' => [
'data' => 'here'
]
]
]);

$manager->some()->starting()->data; // 'here'
$manager->some()->item = 'item'; // sets some.item = 'item'
$manager->some()->item()->drop(); // deletes some.item
```

Note that levels are called as a method with no params. The data is then called, updated, or set as a property.
3 changes: 0 additions & 3 deletions collections.md → docs/collections.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,3 @@ class MyCoolCollection implements ManagesItemsInterface
}
}
```

## Contributing
Any feedback here would be appreciated. Open an issue or PR. See [contributing](contributing.md) for more info.
249 changes: 249 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Data Manager
Simple data manager for nested data, dot notation access, extendability, and container interoperability.

## Goals
* Light weight with a fluent, simple, clear API
* Manage any data type (closure, object, primitives, etc.)
* Manage nested data via dot-notation (one.two.three)
* Manage nested data via magic methods ($manager->one()->two()->three), if desired
* Be composable - integrate into current containers via traits
* Be extensible.
* Allow for protected data (immutable)
* Test coverage, PSR compliant, [container interoperability](https://github.com/container-interop/container-interop), and best practices

## Extras
On top of being a powerful data-manager, there are traits that add features.
Please see [Composing](#composing) for information about mixing and matching features or integrating
different traits into your project.

* [Arrayable](arrayable.md): Use Manager as an array.

* [Chain Access](chains.md): Access data through `$manager->method()->chaining()->for()->value`

* [IoC Container](ioc.md): Use Manager as a simple but powerful Dependency Injection Container. Includes:
* Resolving dependencies from classnames, closures, eager loading, and more.
* Creating singletons.
* Configuring dependencies for dependencies.
* Fallbacks, preparing objects, and more.
* Use Manager as a configuration bank, complete with defaults.
* Load configuration files (php, yaml, json, xml, and custom)

* [Collections](collections.md): Adds extra array-helper methods (based on [Arrayzy](https://github.com/bocharsky-bw/Arrayzy))

* [Load From Files](load-files.md):
Load from various types of files. Json, Php, and Yaml supported by default.
Add your own Custom Decoders easily.
Also allows for namespacing items under a safe file name. Great for a configuration bank.


## Install
Via Composer
``` bash
$ composer require michaels/data-manager
```

## Getting Started
Manager does exactly what you would expect: it *manages* complex items such as config data, arrays, and closures.
The best way to get started is simply instantiate `Michaels\Manager\Manager`

```php
$manager = new Michaels\Manager\Manager([
'some' => [
'starting' => [
'data' => 'here (optional)'
]
]
]);
// Note, you may initialize 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->get('doesntexist') // throws an ItemNotFoundException with no fallback
$manager->getIfHas('doesntexist') // returns a NoItemFoundMessage instead of a script-stopping exception
$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
$manager->has('something'); // alias of exist
$manager->set('name', 'new-value'); // updates item
$manager->remove('some.starting.data');
$manager->isEmpty(); // true or false
$manager->toJson(); // returns json of all items
echo $manager; // returns json string of all items
$manager->reset($array); // rebuild with new items
$manager->clear(); // empty the manager
```

### Protecting Data
You can also guard any item or nest from being changed. Simply,
```php
$manager->protect('some.data'); //now some.data and everything under it cannot be altered
$manager->set('some.data.here', 'new-value'); // throws an exception
```

### Merging Defaults Into Current Dataset
When using Manager to store configuration data, it is important to be able to set defaults.
You can merge an array of defaults into manager via `loadDefaults(array $defaults)`

Imagine your configuration starts like
```php
$manager = new Manager([
'name' => 'My Awesome App',
'site' => [
'url' => 'https://youwishyouwerethiscool.com/',
'protocol' => 'https',
]
]);
```

But your app needs `site.assets` for the assets directory. Simply
```php
$manager->loadDefaults([
'site' => [
'url' => 'http://the_default_url.com/',
'assets' => '/assets',
],
'database' => "mysql"
]);
```

And now, your configuration looks like
```php
'name' => 'My Awesome App',
'site' => [
'url' => 'https://youwishyouwerethiscool.com/'
'protocol' => "https",
'assets' => '/assets'
],
'database' => "mysql"
```

A couple of things to keep in mind:
* This works recursively and as far down as you want.
* If any value is set before loading defaults, that value is preserved
* If a starting value is set to an array (`one.two = []`) and a default lives beneath (`one.two.three = default`), then the default **will** be set.
* On the other hand, if the value exists and is **not** an array, the default will be ignored.
(`one.two = 'something'`) In this case, there is no `one.two.three`, even after loading defaults.

## Using Other Managers
Each feature of Manager is a different trait, but they are all designed to work in whatever combination you want.
You can either [composer your own](#compose) or use one of the build in classes
* **Basic Manager**: Only manages items (what you see above).
* **Manager**: The basic manager with array access and the ability to chain nested items
* **Config Manager**: Manages items like above, loads config files, allows for defaults.
* **IoC Manager**: Manages an IoC (DI) container. You can resolve dependencies, etc.
* **Uber Manager**: Everything in one place. Just for fun, really.


## Composing Features
If you have your own container objects and want to add Manager functionality to them, you may import traits into your class.
This is also a great way to mix and match exactly which feature you want.

The basic trait you always need to start with is `Michaels\Manager\ManagesItemsTrait`.
There is an accompanying interface.

After that, you may add any of the feature traits you like.
It's important to note, however, that all of these feature traits depend on `ManagesItemsTrait`,
so you must include that one FIRST:

```php
use ManagesItemsTrait, ArrayableTrait, CollectionTrait;
```

None of the traits include a constructor. If you want to have your class be initializable with data:

```php
class MyClass
{
use ManagesItemsTrait;

public function __construct($beginningItems)
{
$this->initManager($beginningItems);
}
}
```
initManager() is used so it doesn't conflict with user-defined init() methods.


### Available Traits
1. [`ManagesItemsTrait`](#getting-started) fulfills `ManagesItemsInterface` and adds most functionality. Look at the interface for full list.
2. [`ArrayableTrait`](arrayable.md) makes the class usable as an array (`$manager['some']['data']`) or in loops and such
3. [`ChainsNestedItemsTrait`](chains.md) allows you to use fluent properties to manage data (`$manager->one()->two()->three = 'three`)
4. [`CollectionTrait`](collections.md) returns collections with all sorts of [array helpers](https://github.com/bocharsky-bw/Arrayzy)
5. [`ManagesIocTrait`](ioc.md) turns Manager into a simple, but complete IoC or Dependency Injection manager
6. [`LoadsFilesTrait`](load-files.md) allows Manager to load data from config files.

```php
/* An example for UberManager */
class MyContainer {
use Michaels\Manager\Traits\ManagesItemsTrait;
use Michaels\Manager\Traits\ChainsNestedItemsTrait;
use Michaels\Manager\Traits\ArrayableTrait;
use Michaels\Manager\Traits\CollectionTrait;
use Michaels\Manager\Traits\LoadsFilesTrait;
use Michaels\Manager\Traits\ManagesIocTrait;

// Your stuff here. And you may override anything you like.
// Remember to add a constructor if you want :)
}
```

You may also use the **tests** under `tests/traits` to test your integrated functionality. You may have to grab these through cloning the repo. composer usually won't include tests in your `require`

## Some Advanced Features
By default, Manager stores all the items in an `$items` property.
If you are using the `ManagesItemsTrait` and want to use an internal property besides `$items` to avoid collisions, you have two options:

1. Use `$manager->setItemsName($nameOfProperty)` either in your constructor or before you add anything
2. Set the `$dataItemsName` property to a string of the new property name. Then be sure to call `initManager()` in your constructor.


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

If you do not want an exception, use `getIfHas($alias)` which will return a `NoItemFoundMessage` object, or use a fallback value `get($item, $fallback)`.

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
```

If you try to alter a protected item, a `ModifyingProtectedItemException` will be thrown.

See /exceptions for more


## 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.


## Testing
We try for at least 80% test coverage.
``` bash
$ phpunit
```

You may also use the **tests** under `tests/traits` to test your integrated functionality. You may have to grab these through cloning the repo. composer usually won't include tests in your `require`

## Contributing
Contributions are welcome and will be fully credited. Please see [CONTRIBUTING](CONTRIBUTING.md) for details.


## Security
If you discover any security related issues, please email chrismichaels84@gmail.com instead of using the issue tracker.


## Credits
- [Michael Wilson](https://github.com/chrismichaels84)
- [Scott](https://github.com/smolinari)
- Open an issue to join in!


## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
2 changes: 1 addition & 1 deletion ioc.md → docs/ioc.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Note that fallbacks are not sent through the pipeline.

Also note that you must setup pipelines BEFORE you `fetch()` the first instance of a `share()`d dependency.

## Setting Dependencies Implicitly (Not Yet Implemented)
## Setting Dependencies Implicitly
You can tell Manager how to configure a certain dependency when you register it.
For the example, let's assume:
```php
Expand Down
Loading

0 comments on commit 59f25fc

Please sign in to comment.