├── .gitignore
├── src
├── tests
│ ├── bootstrap.php
│ └── Herrera
│ │ └── Wise
│ │ └── Tests
│ │ ├── Exception
│ │ ├── Exception.php
│ │ └── AbstractExceptionTest.php
│ │ ├── NeverSupportedProcessor.php
│ │ ├── Loader
│ │ ├── ExampleFileLoader.php
│ │ ├── IniFileLoaderTest.php
│ │ ├── YamlFileLoaderTest.php
│ │ ├── PhpFileLoaderTest.php
│ │ ├── JsonFileLoaderTest.php
│ │ ├── XmlFileLoaderTest.php
│ │ ├── LoaderResolverTest.php
│ │ └── AbstractFileLoaderTest.php
│ │ ├── BasicProcessor.php
│ │ ├── Processor
│ │ ├── ExampleProcessor.php
│ │ ├── TestProcessor.php
│ │ ├── AbstractProcessorTest.php
│ │ ├── ProcessorResolverTest.php
│ │ └── DelegatingProcessorTest.php
│ │ ├── Resource
│ │ └── ResourceCollectorTest.php
│ │ ├── Util
│ │ └── ArrayUtilTest.php
│ │ └── WiseTest.php
└── lib
│ └── Herrera
│ └── Wise
│ ├── Exception
│ ├── LogicException.php
│ ├── ExceptionInterface.php
│ ├── ImportException.php
│ ├── LoaderException.php
│ ├── ProcessorException.php
│ ├── InvalidArgumentException.php
│ ├── InvalidReferenceException.php
│ └── AbstractException.php
│ ├── WiseAwareInterface.php
│ ├── Processor
│ ├── ProcessorResolverInterface.php
│ ├── AbstractProcessor.php
│ ├── ProcessorInterface.php
│ ├── DelegatingProcessor.php
│ └── ProcessorResolver.php
│ ├── Resource
│ ├── ResourceAwareInterface.php
│ ├── ResourceCollectorInterface.php
│ └── ResourceCollector.php
│ ├── Loader
│ ├── IniFileLoader.php
│ ├── PhpFileLoader.php
│ ├── YamlFileLoader.php
│ ├── JsonFileLoader.php
│ ├── LoaderResolver.php
│ ├── XmlFileLoader.php
│ └── AbstractFileLoader.php
│ ├── Util
│ └── ArrayUtil.php
│ └── Wise.php
├── .travis.yml
├── doc
├── 00-Installing.md
├── 03-HowToCreateAProcessor.md
├── 02-HowToCreateALoader.md
└── 01-Usage.md
├── phpunit.xml.dist
├── README.md
├── LICENSE
├── composer.json
└── res
└── schema.xsd
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 | /bin/
3 | /coverage/
4 | /src/vendors/
5 |
6 | /composer.lock
--------------------------------------------------------------------------------
/src/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | add(null, __DIR__);
5 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3
5 | - 5.4
6 | - 5.5
7 |
8 | before_script:
9 | - composer self-update
10 | - composer install --dev --no-interaction --prefer-source
11 |
12 | script: bin/phpunit
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Exception/Exception.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class LogicException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/ExceptionInterface.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | interface ExceptionInterface
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/ImportException.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class ImportException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/LoaderException.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class LoaderException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/ProcessorException.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class ProcessorException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/InvalidArgumentException.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class InvalidArgumentException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/InvalidReferenceException.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class InvalidReferenceException extends AbstractException
11 | {
12 | }
13 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/NeverSupportedProcessor.php:
--------------------------------------------------------------------------------
1 | assertEquals(
12 | 'Test message.',
13 | Exception::format('%s message.', 'Test')->getMessage()
14 | );
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/ExampleFileLoader.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | interface WiseAwareInterface
11 | {
12 | /**
13 | * Returns the Wise instance.
14 | *
15 | * @return Wise The instance.
16 | */
17 | public function getWise();
18 |
19 | /**
20 | * Sets a Wise instance.
21 | *
22 | * @param Wise $wise An instance.
23 | */
24 | public function setWise(Wise $wise);
25 | }
26 |
--------------------------------------------------------------------------------
/doc/00-Installing.md:
--------------------------------------------------------------------------------
1 | Installing
2 | ==========
3 |
4 | Composer
5 | --------
6 |
7 | The easiest way to install Wise is by using [Composer][]:
8 |
9 | $ composer require herrera-io/wise=~1.0
10 |
11 | You may then load it by requiring the Composer autoloader:
12 |
13 | ```php
14 | require 'vendor/autoload.php';
15 | ```
16 |
17 | PSR-0
18 | -----
19 |
20 | You may use any class loader that supports [PSR-0][].
21 |
22 | ```php
23 | $loader = new SplClassLoader();
24 | $loader->add('Herrera\\Wise', 'src/lib');
25 | ```
26 |
27 | [Composer]: http://getcomposer.org/
28 | [PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Processor/ProcessorResolverInterface.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | interface ProcessorResolverInterface
11 | {
12 | /**
13 | * Returns the processor able to handle the resource.
14 | *
15 | * @param mixed $resource The resource.
16 | * @param string $type The resource type.
17 | *
18 | * @return ProcessorInterface|boolean The processor, or FALSE if none.
19 | */
20 | public function resolve($resource, $type = null);
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Resource/ResourceAwareInterface.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | interface ResourceAwareInterface
11 | {
12 | /**
13 | * Returns the resource collector.
14 | *
15 | * @return ResourceCollectorInterface The collector.
16 | */
17 | public function getResourceCollector();
18 |
19 | /**
20 | * Sets the resource collector.
21 | *
22 | * @param ResourceCollectorInterface $collector The collector.
23 | */
24 | public function setResourceCollector(ResourceCollectorInterface $collector);
25 | }
26 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/BasicProcessor.php:
--------------------------------------------------------------------------------
1 | root('root');
14 |
15 | $root->children()
16 | ->booleanNode('enabled')
17 | ->defaultFalse()
18 | ->end()
19 | ->integerNode('number')->end()
20 | ->end();
21 |
22 | return $builder;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/IniFileLoader.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class IniFileLoader extends AbstractFileLoader
11 | {
12 | /**
13 | * {@inheritDoc}
14 | */
15 | public function supports($resource, $type = null)
16 | {
17 | return (is_string($resource)
18 | && ('ini' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
19 | && ((null === $type) || ('ini' === $type));
20 | }
21 |
22 | /**
23 | * @override
24 | */
25 | protected function doLoad($file)
26 | {
27 | return parse_ini_file($file, true);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | src/lib/
15 |
16 |
17 |
18 |
19 | src/tests/
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/PhpFileLoader.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class PhpFileLoader extends AbstractFileLoader
11 | {
12 | /**
13 | * {@inheritDoc}
14 | */
15 | public function supports($resource, $type = null)
16 | {
17 | return (is_string($resource)
18 | && ('php' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
19 | && ((null === $type) || ('php' === $type));
20 | }
21 |
22 | /**
23 | * @override
24 | */
25 | protected function doLoad($file)
26 | {
27 | /** @noinspection PhpIncludeInspection */
28 | return require $file;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/YamlFileLoader.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | class YamlFileLoader extends AbstractFileLoader
13 | {
14 | /**
15 | * {@inheritDoc}
16 | */
17 | public function supports($resource, $type = null)
18 | {
19 | return (is_string($resource)
20 | && ('yml' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
21 | && ((null === $type) || ('yaml' === $type));
22 | }
23 |
24 | /**
25 | * @override
26 | */
27 | protected function doLoad($file)
28 | {
29 | return Parser::parse($file);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Processor/ExampleProcessor.php:
--------------------------------------------------------------------------------
1 | root('example');
14 |
15 | $root->children()
16 | ->booleanNode('enabled')
17 | ->defaultFalse()
18 | ->end()
19 | ->end();
20 |
21 | return $builder;
22 | }
23 |
24 | public function supports($resource, $type = null)
25 | {
26 | return is_array($resource)
27 | && ('example' === $type);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Processor/TestProcessor.php:
--------------------------------------------------------------------------------
1 | root('root');
14 |
15 | $root->children()
16 | ->booleanNode('enabled')
17 | ->defaultFalse()
18 | ->end()
19 | ->integerNode('number')->end()
20 | ->end();
21 |
22 | return $builder;
23 | }
24 |
25 | public function supports($resource, $type = null)
26 | {
27 | return ((null === $type) || ('php' === $type));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Exception/AbstractException.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | abstract class AbstractException extends Exception implements ExceptionInterface
13 | {
14 | /**
15 | * Creates an exception using a formatted message.
16 | *
17 | * @param string $format The message format.
18 | * @param mixed $value,... A value.
19 | *
20 | * @return static The exception.
21 | */
22 | public static function format($format, $value = null)
23 | {
24 | if (1 < func_num_args()) {
25 | $format = vsprintf($format, array_slice(func_get_args(), 1));
26 | }
27 |
28 | return new static($format);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Resource/ResourceCollectorInterface.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | interface ResourceCollectorInterface
13 | {
14 | /**
15 | * Adds a resource to the collection.
16 | *
17 | * @param ResourceInterface $resource A resource.
18 | */
19 | public function addResource(ResourceInterface $resource);
20 |
21 | /**
22 | * Removes all resources in the collection.
23 | */
24 | public function clearResources();
25 |
26 | /**
27 | * Returns all of the resources in the collection.
28 | *
29 | * @return ResourceInterface[] The resources.
30 | */
31 | public function getResources();
32 | }
33 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Resource/ResourceCollector.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | class ResourceCollector implements ResourceCollectorInterface
13 | {
14 | /**
15 | * The collection of resources.
16 | *
17 | * @var ResourceInterface[]
18 | */
19 | private $resources = array();
20 |
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public function addResource(ResourceInterface $resource)
25 | {
26 | $this->resources[] = $resource;
27 | }
28 |
29 | /**
30 | * {@inheritDoc}
31 | */
32 | public function clearResources()
33 | {
34 | $this->resources = array();
35 | }
36 |
37 | /**
38 | * {@inheritDoc}
39 | */
40 | public function getResources()
41 | {
42 | return $this->resources;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Wise
2 | ====
3 |
4 | [![Build Status]](http://travis-ci.org/herrera-io/php-wise)
5 |
6 | Wise is a configuration manager built on Symfony [Config][]. It supports data
7 | formats such as INI, JSON, PHP (native), XML, and YAML. You can also normalize
8 | and validate configuration data.
9 |
10 | ```php
11 | $wise = Herrera\Wise\Wise::create('/path/to/config');
12 | $data = $wise->load('example.yml');
13 | ```
14 |
15 | Forks
16 | -----
17 |
18 | As this project is no longer maintained, please see the [Wiki page for maintained forks](https://github.com/kherge-abandoned/php-wise/wiki/Forks).
19 |
20 | Documentation
21 | -------------
22 |
23 | - [Installing][]
24 | - [Usage][]
25 | - [How to Create a Loader][]
26 |
27 | [Build Status]: https://secure.travis-ci.org/herrera-io/php-wise.png?branch=master
28 | [Config]: http://symfony.com/doc/current/components/config/index.html
29 | [How to Create a Loader]: doc/02-HowToCreateALoader.md
30 | [Installing]: doc/00-Installing.md
31 | [Usage]: doc/01-Usage.md
32 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Processor/AbstractProcessor.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | abstract class AbstractProcessor implements ProcessorInterface
13 | {
14 | /**
15 | * The processor resolver.
16 | *
17 | * @var ProcessorResolverInterface
18 | */
19 | private $resolver;
20 |
21 | /**
22 | * {@inheritDoc}
23 | */
24 | public function getResolver()
25 | {
26 | return $this->resolver;
27 | }
28 |
29 | /**
30 | * {@inheritDoc}
31 | */
32 | public function process(array $data)
33 | {
34 | $processor = new Processor();
35 |
36 | return $processor->processConfiguration($this, $data);
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | public function setResolver(ProcessorResolverInterface $resolver)
43 | {
44 | $this->resolver = $resolver;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Kevin Herrera
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/JsonFileLoader.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class JsonFileLoader extends AbstractFileLoader
14 | {
15 | /**
16 | * The JSON parser.
17 | *
18 | * @var Parser
19 | */
20 | private $json;
21 |
22 | /**
23 | * @override
24 | */
25 | public function __construct(FileLocatorInterface $locator)
26 | {
27 | parent::__construct($locator);
28 |
29 | $this->json = new Parser();
30 | }
31 |
32 | /**
33 | * {@inheritDoc}
34 | */
35 | public function supports($resource, $type = null)
36 | {
37 | return (is_string($resource)
38 | && ('json' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
39 | && ((null === $type) || ('json' === $type));
40 | }
41 |
42 | /**
43 | * @override
44 | */
45 | protected function doLoad($file)
46 | {
47 | return $this->json->decodeFile($file, true);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "herrera-io/wise",
3 | "description": "Symfony Config for everyone else.",
4 | "keywords": ["config"],
5 | "homepage": "http://github.com/herrera-io/php-wise",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Kevin Herrera",
10 | "email": "kevin@herrera.io",
11 | "homepage": "http://kevin.herrera.io"
12 | }
13 | ],
14 | "support": {
15 | "issues": "https://github.com/herrera-io/php-wise/issues"
16 | },
17 | "require": {
18 | "php": ">=5.3.3",
19 | "symfony/config": "~2.2"
20 | },
21 | "require-dev": {
22 | "herrera-io/json": "~1.0",
23 | "herrera-io/phpunit-test-case": "1.*",
24 | "phpunit/phpunit": "3.7.*",
25 | "symfony/yaml": "~2.2"
26 | },
27 | "suggest": {
28 | "ext-dom": "For parsing XML files.",
29 | "herrera-io/json": "For parsing JSON files.",
30 | "symfony/yaml": "For parsing YAML files."
31 | },
32 | "autoload": {
33 | "psr-0": {
34 | "Herrera\\Wise": "src/lib"
35 | }
36 | },
37 | "config": {
38 | "bin-dir": "bin",
39 | "vendor-dir": "src/vendors"
40 | },
41 | "extra": {
42 | "branch-alias": {
43 | "dev-master": "1.0-dev"
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Processor/ProcessorInterface.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | interface ProcessorInterface extends ConfigurationInterface
13 | {
14 | /**
15 | * Returns the processor resolver.
16 | *
17 | * @return ProcessorResolverInterface The resolver.
18 | */
19 | public function getResolver();
20 |
21 | /**
22 | * Processes the configuration data.
23 | *
24 | * @param array $data The data.
25 | *
26 | * @return array The processed data.
27 | */
28 | public function process(array $data);
29 |
30 | /**
31 | * Sets the processor resolver.
32 | *
33 | * @param ProcessorResolverInterface $resolver The resolver.
34 | */
35 | public function setResolver(ProcessorResolverInterface $resolver);
36 |
37 | /**
38 | * Checks if a resource is supported by this processor.
39 | *
40 | * @param mixed $resource A resource.
41 | * @param string $type The resource type.
42 | *
43 | * @return boolean TRUE if it is supported, FALSE if not.
44 | */
45 | public function supports($resource, $type = null);
46 | }
47 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Processor/AbstractProcessorTest.php:
--------------------------------------------------------------------------------
1 | setPropertyValue($this->processor, 'resolver', $this->resolver);
24 |
25 | $this->assertSame($this->resolver, $this->processor->getResolver());
26 | }
27 |
28 | public function testProcess()
29 | {
30 | $this->assertSame(
31 | array('enabled' => false),
32 | $this->processor->process(array())
33 | );
34 | }
35 |
36 | /**
37 | * @depends testGetResolver
38 | */
39 | public function testSetResolver()
40 | {
41 | $this->processor->setResolver($this->resolver);
42 |
43 | $this->assertSame($this->resolver, $this->processor->getResolver());
44 | }
45 |
46 | protected function setUp()
47 | {
48 | $this->processor = new ExampleProcessor();
49 | $this->resolver = new ProcessorResolver();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Processor/DelegatingProcessor.php:
--------------------------------------------------------------------------------
1 |
11 | */
12 | class DelegatingProcessor extends AbstractProcessor
13 | {
14 | /**
15 | * The last processor returned by the resolver.
16 | *
17 | * @var ProcessorInterface
18 | */
19 | private $last;
20 |
21 | /**
22 | * Sets the processor resolver.
23 | *
24 | * @param ProcessorResolverInterface $resolver The resolver.
25 | */
26 | public function __construct(ProcessorResolverInterface $resolver)
27 | {
28 | $this->setResolver($resolver);
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | *
34 | * @throws ProcessorException If no processor is set.
35 | */
36 | public function getConfigTreeBuilder()
37 | {
38 | if (null === $this->last) {
39 | throw new ProcessorException(
40 | 'The support() method did not find a processor.'
41 | );
42 | }
43 |
44 | return $this->last->getConfigTreeBuilder();
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | public function supports($resource, $type = null)
51 | {
52 | $this->last = $this->getResolver()->resolve($resource, $type) ?: null;
53 |
54 | return (null !== $this->last);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Processor/ProcessorResolver.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class ProcessorResolver implements ProcessorResolverInterface
11 | {
12 | /**
13 | * The collection of processors.
14 | *
15 | * @var ProcessorInterface[]
16 | */
17 | private $processors = array();
18 |
19 | /**
20 | * Sets processors in the resolver.
21 | *
22 | * @param ProcessorInterface[] $processors The processors.
23 | */
24 | public function __construct(array $processors = array())
25 | {
26 | foreach ($processors as $processor) {
27 | $this->addProcessor($processor);
28 | }
29 | }
30 |
31 | /**
32 | * Adds a processor to the resolve.
33 | *
34 | * @param ProcessorInterface $processor A processor.
35 | */
36 | public function addProcessor(ProcessorInterface $processor)
37 | {
38 | $this->processors[] = $processor;
39 | }
40 |
41 | /**
42 | * Returns the processors in the resolve.
43 | *
44 | * @return ProcessorInterface[] The processors.
45 | */
46 | public function getProcessors()
47 | {
48 | return $this->processors;
49 | }
50 |
51 | /**
52 | * {@inheritDoc}
53 | */
54 | public function resolve($resource, $type = null)
55 | {
56 | foreach ($this->processors as $processor) {
57 | if ($processor->supports($resource, $type)) {
58 | return $processor;
59 | }
60 | }
61 |
62 | return false;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Resource/ResourceCollectorTest.php:
--------------------------------------------------------------------------------
1 | collector->addResource($this->resource);
24 |
25 | $this->assertSame(
26 | array($this->resource),
27 | $this->getPropertyValue($this->collector, 'resources')
28 | );
29 | }
30 |
31 | /**
32 | * @depends testAddResource
33 | */
34 | public function testClearResources()
35 | {
36 | $this->collector->addResource($this->resource);
37 | $this->collector->clearResources();
38 |
39 | $this->assertSame(
40 | array(),
41 | $this->getPropertyValue($this->collector, 'resources')
42 | );
43 | }
44 |
45 | /**
46 | * @depends testAddResource
47 | */
48 | public function testGetResources()
49 | {
50 | $this->collector->addResource($this->resource);
51 |
52 | $this->assertSame(
53 | array($this->resource),
54 | $this->collector->getResources()
55 | );
56 | }
57 |
58 | protected function setUp()
59 | {
60 | $this->collector = new ResourceCollector();
61 | $this->resource = new FileResource(__FILE__);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Util/ArrayUtil.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class ArrayUtil
11 | {
12 | /**
13 | * Flattens an associative array.
14 | *
15 | * @param array $array An array.
16 | * @param string $prefix A key prefix.
17 | * @param string $join The key join character.
18 | *
19 | * @return array The flattened array.
20 | */
21 | public static function flatten(array $array, $prefix = '', $join = '.')
22 | {
23 | $flat = array();
24 |
25 | foreach ($array as $key => $value) {
26 | $key = $prefix ? $prefix . $join . $key : $key;
27 |
28 | if (is_array($value)) {
29 | $flat = array_merge(
30 | $flat,
31 | self::flatten($value, $key, $join)
32 | );
33 | } else {
34 | $flat[$key] = $value;
35 | }
36 | }
37 |
38 | return $flat;
39 | }
40 |
41 | /**
42 | * Similar to `array_walk_recursive()`, but passes the current array too.
43 | *
44 | * @param array &$array An array.
45 | * @param callable $callback The callable.
46 | * @param mixed $data The user data.
47 | */
48 | public static function walkRecursive(&$array, $callback, $data = null)
49 | {
50 | foreach ($array as $key => &$value) {
51 | if (is_array($value)) {
52 | self::walkRecursive($value, $callback, $data);
53 | } else {
54 | $callback($value, $key, $array, $data);
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Processor/ProcessorResolverTest.php:
--------------------------------------------------------------------------------
1 | assertSame(
23 | array($this->processor),
24 | $this->getPropertyValue($this->resolver, 'processors')
25 | );
26 | }
27 |
28 | public function testAddProcessor()
29 | {
30 | $resolver = new ProcessorResolver();
31 | $resolver->addProcessor($this->processor);
32 |
33 | $this->assertSame(
34 | array($this->processor),
35 | $this->getPropertyValue($resolver, 'processors')
36 | );
37 | }
38 |
39 | /**
40 | * @depends testConstruct
41 | */
42 | public function testGetProcessors()
43 | {
44 | $this->assertSame(
45 | array($this->processor),
46 | $this->resolver->getProcessors()
47 | );
48 | }
49 |
50 | /**
51 | * @depends testConstruct
52 | */
53 | public function testResolve()
54 | {
55 | $this->assertFalse($this->resolver->resolve('test'));
56 | $this->assertSame(
57 | $this->processor,
58 | $this->resolver->resolve(array(), 'example')
59 | );
60 | }
61 |
62 | protected function setUp()
63 | {
64 | $this->processor = new ExampleProcessor();
65 | $this->resolver = new ProcessorResolver(array($this->processor));
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/IniFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->loader->supports('test.ini'));
21 | $this->assertTrue($this->loader->supports('test.ini', 'ini'));
22 | }
23 |
24 | public function testDoLoad()
25 | {
26 | file_put_contents(
27 | "{$this->dir}/test.ini",
28 | <<dir}/import.ini",
40 | <<assertSame(
47 | array(
48 | 'imported' => array(
49 | 'value' => 'imported value'
50 | ),
51 | 'imports' => array(
52 | array('resource' => 'import.ini')
53 | ),
54 | 'root' => array(
55 | 'number' => '123',
56 | 'imported' => 'imported value'
57 | ),
58 | ),
59 | $this->loader->load('test.ini')
60 | );
61 | }
62 |
63 | protected function setUp()
64 | {
65 | $this->dir = $this->createDir();
66 | $this->loader = new IniFileLoader(new FileLocator($this->dir));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/YamlFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->loader->supports('test.yml'));
21 | $this->assertTrue($this->loader->supports('test.yml', 'yaml'));
22 | }
23 |
24 | public function testDoLoad()
25 | {
26 | file_put_contents(
27 | "{$this->dir}/test.yml",
28 | <<dir}/import.yml",
40 | <<assertSame(
47 | array(
48 | 'imported' => array(
49 | 'value' => 'imported value'
50 | ),
51 | 'imports' => array(
52 | array('resource' => 'import.yml')
53 | ),
54 | 'root' => array(
55 | 'number' => 123,
56 | 'imported' => 'imported value'
57 | ),
58 | ),
59 | $this->loader->load('test.yml')
60 | );
61 | }
62 |
63 | protected function setUp()
64 | {
65 | $this->dir = $this->createDir();
66 | $this->loader = new YamlFileLoader(new FileLocator($this->dir));
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Util/ArrayUtilTest.php:
--------------------------------------------------------------------------------
1 | assertEquals(
13 | array(
14 | 'one' => 1,
15 | 'sub.two' => 2,
16 | 'sub.sub.three' => 3
17 | ),
18 | ArrayUtil::flatten(
19 | array(
20 | 'one' => 1,
21 | 'sub' => array(
22 | 'two' => 2,
23 | 'sub' => array(
24 | 'three' => 3
25 | )
26 | )
27 | )
28 | )
29 | );
30 | }
31 |
32 | public function testWalkRecursive()
33 | {
34 | $expected = $actual = array(
35 | 'one' => array(
36 | 'two' => array(
37 | 'three' => array(
38 | 'four' => 'eight',
39 | 'twelve' => 'thirteen',
40 | ),
41 | 'five' => 'nine',
42 | ),
43 | 'six' => 'ten',
44 | ),
45 | 'seven' => 'eleven',
46 | );
47 |
48 | ArrayUtil::walkRecursive(
49 | $actual,
50 | function (&$value, $key, &$array) {
51 | if ('four' === $key) {
52 | unset($array[$key]);
53 |
54 | $array['changed'] = $value;
55 | }
56 | }
57 | );
58 |
59 | unset($expected['one']['two']['three']['four']);
60 |
61 | $expected['one']['two']['three']['changed'] = 'eight';
62 |
63 | $this->assertSame($expected, $actual);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/res/schema.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Processor/DelegatingProcessorTest.php:
--------------------------------------------------------------------------------
1 | assertNotNull(
19 | $this->getPropertyValue($this->processor, 'resolver')
20 | );
21 |
22 | $this->assertSame(
23 | $this->processor->getResolver(),
24 | $this->getPropertyValue($this->processor, 'resolver')
25 | );
26 | }
27 |
28 | /**
29 | * @expectedException \Herrera\Wise\Exception\ProcessorException
30 | * @expectedExceptionMessage The support() method did not find a processor.
31 | */
32 | public function testGetConfigTreeBuilderNoneAvailable()
33 | {
34 | $this->processor->getConfigTreeBuilder();
35 | }
36 |
37 | public function testGetConfigTreeBuilder()
38 | {
39 | $this->setPropertyValue(
40 | $this->processor,
41 | 'last',
42 | new ExampleProcessor()
43 | );
44 |
45 | $this->assertInstanceOf(
46 | 'Symfony\\Component\\Config\\Definition\\Builder\\TreeBuilder',
47 | $this->processor->getConfigTreeBuilder()
48 | );
49 | }
50 |
51 | public function testSupports()
52 | {
53 | $this->assertFalse($this->processor->supports('test'));
54 | $this->assertTrue($this->processor->supports(array(), 'example'));
55 | }
56 |
57 | protected function setUp()
58 | {
59 | $this->processor = new DelegatingProcessor(
60 | new ProcessorResolver(array(new ExampleProcessor()))
61 | );
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/PhpFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->loader->supports('test.php'));
21 | $this->assertTrue($this->loader->supports('test.php', 'php'));
22 | }
23 |
24 | public function testDoLoad()
25 | {
26 | file_put_contents(
27 | "{$this->dir}/test.php",
28 | << array(
31 | array('resource' => 'import.php')
32 | ),
33 | 'root' => array(
34 | 'number' => 123,
35 | 'imported' => '%imported.value%'
36 | )
37 | );
38 | DATA
39 | );
40 |
41 | file_put_contents(
42 | "{$this->dir}/import.php",
43 | << array(
46 | 'value' => 'imported value'
47 | )
48 | );
49 | DATA
50 | );
51 |
52 | $this->assertSame(
53 | array(
54 | 'imported' => array(
55 | 'value' => 'imported value'
56 | ),
57 | 'imports' => array(
58 | array('resource' => 'import.php')
59 | ),
60 | 'root' => array(
61 | 'number' => 123,
62 | 'imported' => 'imported value'
63 | ),
64 | ),
65 | $this->loader->load('test.php')
66 | );
67 | }
68 |
69 | protected function setUp()
70 | {
71 | $this->dir = $this->createDir();
72 | $this->loader = new PhpFileLoader(new FileLocator($this->dir));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/JsonFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->loader->supports('test.json'));
21 | $this->assertTrue($this->loader->supports('test.json', 'json'));
22 | }
23 |
24 | public function testDoLoad()
25 | {
26 | file_put_contents(
27 | "{$this->dir}/test.json",
28 | <<dir}/import.json",
46 | <<assertSame(
56 | array(
57 | 'imported' => array(
58 | 'value' => 'imported value'
59 | ),
60 | 'imports' => array(
61 | array('resource' => 'import.json')
62 | ),
63 | 'root' => array(
64 | 'number' => 123,
65 | 'imported' => 'imported value'
66 | ),
67 | ),
68 | $this->loader->load('test.json')
69 | );
70 | }
71 |
72 | protected function setUp()
73 | {
74 | $this->dir = $this->createDir();
75 | $this->loader = new JsonFileLoader(new FileLocator($this->dir));
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/XmlFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->loader->supports('test.xml'));
21 | $this->assertTrue($this->loader->supports('test.xml', 'xml'));
22 | }
23 |
24 | public function testDoLoad()
25 | {
26 | file_put_contents(
27 | "{$this->dir}/test.xml",
28 | <<
30 |
31 |
32 | import.xml
33 |
34 |
35 |
36 | 123
37 | %imported.value%
38 | 1
39 | 1.23
40 |
41 |
42 | DATA
43 | );
44 |
45 | file_put_contents(
46 | "{$this->dir}/import.xml",
47 | <<
49 |
50 | imported value
51 |
52 |
53 | DATA
54 | );
55 |
56 | $this->assertSame(
57 | array(
58 | 'imported' => array(
59 | 'value' => 'imported value'
60 | ),
61 | 'imports' => array(
62 | array('resource' => 'import.xml')
63 | ),
64 | 'root' => array(
65 | 'number' => 123,
66 | 'imported' => 'imported value',
67 | 'enabled' => true,
68 | 'unit' => 1.23
69 | ),
70 | ),
71 | $this->loader->load('test.xml')
72 | );
73 | }
74 |
75 | protected function setUp()
76 | {
77 | $this->dir = $this->createDir();
78 | $this->loader = new XmlFileLoader(new FileLocator($this->dir));
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/doc/03-HowToCreateAProcessor.md:
--------------------------------------------------------------------------------
1 | How to Create a Processor
2 | =========================
3 |
4 | To normalize and validate configuration data, you will need to create a
5 | processor that provides a [configuration definition][]. You must have a solid
6 | understanding on how the [Config][] component generates those definitions in
7 | order to create a processor.
8 |
9 | Creating a Processor
10 | --------------------
11 |
12 | To create a processing class, you will need to extend the `AbstractProcessor`
13 | class and implement the `getConfigTreeBuilder()` method:
14 |
15 | ```php
16 | class MyProcessor implement Herrera\Wise\Processor\AbstractProcessor
17 | {
18 | public function getConfigTreeBuilder()
19 | {
20 | // return definition tree builder
21 | }
22 |
23 | public function supports($resource, $type = null)
24 | {
25 | // returns true if $resource and $type are supported
26 | }
27 | }
28 | ```
29 |
30 | You will then need to register it with `Wise`:
31 |
32 | ```php
33 | $wise->setProcessor(new MyProcessor());
34 | ```
35 |
36 | Any configuration resource that is loaded, and is supported by the processor,
37 | will be normalized and validated according to the definition you have provided.
38 |
39 | Using Multiple Processors
40 | -------------------------
41 |
42 | To use more than one processor, you will need to use both a delegating processor
43 | and a processor resolver. The delegating processor will use the processor
44 | resolver to find the correct processor to use:
45 |
46 | ```php
47 | $resolver = new Herrera\Wise\Processor\ProcessorResolver();
48 |
49 | $wise->setProcessor(
50 | new Herrera\Wise\Processor\DelegatingProcessor($resolver)
51 | );
52 | ```
53 |
54 | With the processor registered with `Wise`, you can then add all processors you
55 | need using the resolver's `addPrococessor()` method:
56 |
57 | ```php
58 | $resolver->addProcessor(new MyProcessorOne());
59 | $resolver->addProcessor(new MyProcessorTwo());
60 | $resolver->addProcessor(new MyProcessorThree());
61 | // ... snip ...
62 | ```
63 |
64 | [Config]: http://symfony.com/doc/current/components/config/index.html
65 | [configuration definition]: http://symfony.com/doc/current/components/config/definition.html
--------------------------------------------------------------------------------
/doc/02-HowToCreateALoader.md:
--------------------------------------------------------------------------------
1 | How to Create a Loader
2 | ======================
3 |
4 | Creating a loader is nearly identical to that of the Symfony [Config][]
5 | component, with the difference being added support for Wise features.
6 |
7 | - [File Based Loader](#FileBasedLoader)
8 | - [Other Loader](#OtherLoader)
9 |
10 | ---
11 |
12 | # File Based Loader
13 |
14 | To create a file-based loader, you need to extend the `AbstractFileLoader`
15 | class. The `AbstractFileLoader` class enabled support for global parameters
16 | and importing from other configuration resources. The following is an example
17 | simple loader for CSV files:
18 |
19 | ```php
20 | class CsvFileLoader extends Herrera\Wise\Loader\AbstractFileLoader
21 | {
22 | public function supports($resource, $type = null)
23 | {
24 | return (is_string($resource)
25 | && ('csv' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
26 | && ((null === $type) || ('csv' === $type));
27 | }
28 |
29 | protected function doLoad($resource, $type = null)
30 | {
31 | $fp = fopen($resource, 'r');
32 | $data = array();
33 |
34 | while (false !== ($row = fgetcsv($fp))) {
35 | if ((1 === count($row)) && (null === $row[0])) {
36 | continue;
37 | }
38 |
39 | $data[$row[0]] = $row[1];
40 | }
41 |
42 | fcloses($fp);
43 |
44 | return $data;
45 | }
46 | }
47 | ```
48 |
49 | # Other Loader
50 |
51 | For resources that are not files, you will need to implement these interfaces:
52 |
53 | - `Herrera\Wise\Resource\ResourceAwareInterface` - For caching support
54 | - `Herrera\Wise\WiseAwareInterface` - For global parameters support
55 | - `Symfony\Component\Config\Loader\LoaderInterface` - For basic loading
56 |
57 | Implementing the first two interfaces flags your class as having support for
58 | caching and global parameters. Your class will actually need to make use of
59 | the resource collector and `Wise` instance, which will be set when your class
60 | is set as the `Wise` loader. In the `AbstractFileLoader` class provided by the
61 | library, this is already handled for you.
62 |
63 | [Config]: http://symfony.com/doc/current/components/config/resources.html#resource-loaders
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/LoaderResolver.php:
--------------------------------------------------------------------------------
1 |
16 | */
17 | class LoaderResolver extends Base implements
18 | ResourceAwareInterface,
19 | WiseAwareInterface
20 | {
21 | /**
22 | * The resource collector.
23 | *
24 | * @var ResourceCollectorInterface
25 | */
26 | private $collector;
27 |
28 | /**
29 | * The Wise instance.
30 | *
31 | * @var Wise
32 | */
33 | private $wise;
34 |
35 | /**
36 | * @override
37 | */
38 | public function addLoader(LoaderInterface $loader)
39 | {
40 | if ($this->collector && ($loader instanceof ResourceAwareInterface)) {
41 | $loader->setResourceCollector($this->collector);
42 | }
43 |
44 | if ($this->wise && ($loader instanceof WiseAwareInterface)) {
45 | $loader->setWise($this->wise);
46 | }
47 |
48 | parent::addLoader($loader);
49 | }
50 |
51 | /**
52 | * {@inheritDoc}
53 | */
54 | public function getResourceCollector()
55 | {
56 | return $this->collector;
57 | }
58 |
59 | /**
60 | * {@inheritDoc}
61 | */
62 | public function getWise()
63 | {
64 | return $this->wise;
65 | }
66 |
67 | /**
68 | * {@inheritDoc}
69 | */
70 | public function setResourceCollector(ResourceCollectorInterface $collector)
71 | {
72 | $this->collector = $collector;
73 |
74 | foreach ($this->getLoaders() as $loader) {
75 | if ($loader instanceof ResourceAwareInterface) {
76 | $loader->setResourceCollector($collector);
77 | }
78 | }
79 | }
80 |
81 | /**
82 | * {@inheritDoc}
83 | */
84 | public function setWise(Wise $wise)
85 | {
86 | $this->wise = $wise;
87 |
88 | foreach ($this->getLoaders() as $loader) {
89 | if ($loader instanceof WiseAwareInterface) {
90 | $loader->setWise($wise);
91 | }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/XmlFileLoader.php:
--------------------------------------------------------------------------------
1 |
12 | */
13 | class XmlFileLoader extends AbstractFileLoader
14 | {
15 | /**
16 | * {@inheritDoc}
17 | */
18 | public function supports($resource, $type = null)
19 | {
20 | return (is_string($resource)
21 | && ('xml' === strtolower(pathinfo($resource, PATHINFO_EXTENSION))))
22 | && ((null === $type) || ('xml' === $type));
23 | }
24 |
25 | /**
26 | * @override
27 | */
28 | protected function doLoad($file)
29 | {
30 | $doc = new DOMDocument();
31 | $doc->preserveWhiteSpace = false;
32 |
33 | $doc->load($file);
34 | $doc->schemaValidate(__DIR__ . '/../../../../../res/schema.xsd');
35 |
36 | return $this->toArray($doc->documentElement);
37 | }
38 |
39 | /**
40 | * Converts a DOM elements to native PHP values.
41 | *
42 | * @param DOMElement $node The node.
43 | *
44 | * @return mixed The result.
45 | */
46 | private function toArray(DOMElement $node)
47 | {
48 | $value = null;
49 |
50 | switch ($node->nodeName) {
51 | case 'array':
52 | $value = array();
53 |
54 | if ($node->hasChildNodes()) {
55 | for ($i = 0; $i < $node->childNodes->length; $i++) {
56 | /** @var $child DOMElement */
57 | $child = $node->childNodes->item($i);
58 |
59 | if ($child->hasAttribute('key')) {
60 | $value[$child->getAttribute('key')] = $this->toArray($child);
61 | } else {
62 | $value[] = $this->toArray($child);
63 | }
64 | }
65 | }
66 | break;
67 | case 'bool':
68 | $value = (bool) $node->textContent;
69 | break;
70 | case 'float':
71 | $value = (float) $node->textContent;
72 | break;
73 | case 'int':
74 | $value = (int) $node->textContent;
75 | break;
76 | case 'str':
77 | $value = $node->textContent;
78 | break;
79 | }
80 |
81 | return $value;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/LoaderResolverTest.php:
--------------------------------------------------------------------------------
1 | setPropertyValue($this->resolver, 'collector', $this->collector);
32 | $this->setPropertyValue($this->resolver, 'wise', $this->wise);
33 |
34 | $loader = new ExampleFileLoader(new FileLocator());
35 |
36 | $this->resolver->addLoader($loader);
37 |
38 | $this->assertSame($this->collector, $loader->getResourceCollector());
39 | $this->assertSame($this->wise, $loader->getWise());
40 | }
41 |
42 | public function testGetResourceCollector()
43 | {
44 | $this->setPropertyValue($this->resolver, 'collector', $this->collector);
45 |
46 | $this->assertSame(
47 | $this->collector,
48 | $this->resolver->getResourceCollector()
49 | );
50 | }
51 |
52 | public function testGetWise()
53 | {
54 | $this->setPropertyValue($this->resolver, 'wise', $this->wise);
55 |
56 | $this->assertSame($this->wise, $this->resolver->getWise());
57 | }
58 |
59 | public function testSetResourceCollector()
60 | {
61 | $loader = new ExampleFileLoader(new FileLocator());
62 |
63 | $this->resolver->addLoader($loader);
64 | $this->resolver->setResourceCollector($this->collector);
65 |
66 | $this->assertSame($this->collector, $loader->getResourceCollector());
67 | }
68 |
69 | public function testSetWise()
70 | {
71 | $loader = new ExampleFileLoader(new FileLocator());
72 |
73 | $this->resolver->addLoader($loader);
74 | $this->resolver->setWise($this->wise);
75 |
76 | $this->assertSame($this->wise, $loader->getWise());
77 | }
78 |
79 | protected function setUp()
80 | {
81 | $this->collector = new ResourceCollector();
82 | $this->resolver = new LoaderResolver();
83 | $this->wise = new Wise();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/doc/01-Usage.md:
--------------------------------------------------------------------------------
1 | Usage
2 | =====
3 |
4 | > **Notice:** The documentation was designed to be read from top to bottom.
5 | > Some > tasks are shared with other topics. For example, the `$locator`
6 | > instance > in the **Single Loader** topic is needed in the **Multiple Loader**
7 | > topic, but the process of creating it is not covered again.
8 |
9 | - [All-In-One](#all-in-one)
10 | - [Cherry Pick](#cherry-pick)
11 | - [Single Loader](#single-loader)
12 | - [Multiple Loaders](#multiple-loaders)
13 | - [Caching](#caching)
14 | - [Processing](#processing)
15 | - [Loading Data](#loading-data)
16 |
17 | There are two ways of using Wise.
18 |
19 | All-In-One
20 | ----------
21 |
22 | The easiest way to start using Wise is by calling the `create()` method:
23 |
24 | ```php
25 | use Herrera\Wise\Wise;
26 |
27 | $wise = Wise::create('/path/to/config');
28 | ```
29 |
30 | Using this approach requires that you install all of Wise's suggested Composer
31 | dependencies, but grants you the ability to load INI, JSON, PHP, XML, and YAML
32 | configuration files.
33 |
34 | The `create()` method will accept a single directory path, or an array of
35 | directory paths. You may also specify a cache directory path, and the debug
36 | mode, if necessary:
37 |
38 | ```php
39 | $wise = Wise::create(
40 | array( // multiple directory paths
41 | '/path/1',
42 | '/path/2',
43 | '/path/3',
44 | '/path/4',
45 | ),
46 | '/path/to/cache/dir', // cache directory path
47 | true // enables debugging
48 | );
49 | ```
50 |
51 | Cherry Pick
52 | -----------
53 |
54 | Your project may not make use of one or more configuration file types, so
55 | registering all of the available loaders may be wasteful. Instead of using
56 | the `create()` method, you will want to create a new instance of `Wise`:
57 |
58 | ```php
59 | $wise = new Wise();
60 | ```
61 |
62 | ### Single Loader
63 |
64 | If you are using only one file type for your project, setting up a loader
65 | is fairly straightforward. First, you will need to create a `FileLocator`
66 | instance, which is used by all loaders to find configuration files:
67 |
68 | ```php
69 | use Symfony\Component\Config\FileLocator;
70 |
71 | $locator = new FileLocator('/path/to/config');
72 | ```
73 |
74 | If your configuration files are located in multiple directories, you may
75 | provide an array of directory paths.
76 |
77 | > You might be scratching your head and wondering why you are creating an
78 | > instance of a class from a different library. The Wise library is built on
79 | > top of Symfony's Config library, which shares many of the same classes
80 | > with Wise.
81 |
82 | Once you have created your locator, you can now instantiate your desired
83 | loader with the new `FileLocator` object, which will then be registered
84 | with `$wise`:
85 |
86 | ```php
87 | use Herrera\Wise\Loader\PhpFileLoader;
88 |
89 | $loader = new PhpFileLoader($locator);
90 |
91 | $wise->setLoader($loader);
92 | ```
93 |
94 | This example demonstrates how to support only PHP scripts as configuration
95 | files. You may also use any of the loaders that have been bundled with the
96 | library:
97 |
98 | - `Herrera\Wise\Loader\IniFileLoader`
99 | - `Herrera\Wise\Loader\JsonFileLoader` — Requires `herrera-io/json`.
100 | - `Herrera\Wise\Loader\PhpFileLoader`
101 | - `Herrera\Wise\Loader\XmlFileLoader` — Requires the `dom` extension.
102 | - `Herrera\Wise\Loader\YamlFileLoader` — Requires `symfony/yaml`.
103 |
104 | You may also [create your own loader][] and use that instead.
105 |
106 | ### Multiple Loaders
107 |
108 | To use multiple loaders, you do not need to create multiple instances of Wise.
109 | Instead, what you will need is a delegating loader. This delegating loader is
110 | used in place of an actual loader. To use a delegating loader, you must first
111 | create its resolver:
112 |
113 | ```php
114 | use Herrera\Wise\Loader\LoaderResolver;
115 | use Herrera\Wise\Loader\IniFileLoader;
116 | use Herrera\Wise\Loader\PhpFileLoader;
117 |
118 | $resolver = new LoaderResolver(
119 | array(
120 | new IniFileLoader($locator),
121 | new PhpFileLoader($locator),
122 | )
123 | );
124 | ```
125 |
126 | In this example, the INI and PHP file loaders have been registered with the
127 | resolver. This will allow the delegating loader to use the INI and PHP loaders
128 | when an attempt is made to load either file type. Before that can be done, you
129 | must create the delegating loader using your resolver, and then registering
130 | the loader with Wise:
131 |
132 | ```php
133 | use Herrera\Wise\Loader\DelegatingLoader;
134 |
135 | $delegator = new DelegatingLoader($resolver);
136 |
137 | $wise->setLoader($delegator);
138 | ```
139 |
140 | #### Caching
141 |
142 | Now that you have registered your loader(s), you may want to cache the result
143 | to improve performance. To do so, you must register a resource collector, and
144 | then set the cache directory path:
145 |
146 | ```php
147 | use Herrera\Wise\Resource\ResourceCollector;
148 |
149 | $wise->setCacheDir('/path/to/cache/dir');
150 | $wise->setCollector(new ResourceCollector());
151 | ```
152 |
153 | > The purpose of the `ResourceCollector` instance is so that `imports` can be
154 | > properly tracked when they are loaded. Without the resource collector, any
155 | > changes made to imported files will not be considered when the cache needs
156 | > to be refreshed, resulting in stale cache data.
157 |
158 | Processing
159 | ----------
160 |
161 | Regardless of whether you chose the **Single Loader** or **Multiple Loaders**
162 | approach, you may want to normalize and/or validate the configuration data that
163 | you are loading. In Wise, this is called processing. For this part, **you must
164 | known** how to create your own definitions, which is covered by Symfony's
165 | own [documentation][]. You must have a solid understanding of that
166 | documentation before you will be able to proceed.
167 |
168 | *intermission, Jeopardy theme song*
169 |
170 | You should now continue on to [How to Create a Processor][].
171 |
172 | Loading Data
173 | ------------
174 |
175 | After you have set up Wise, you may now load your configuration files:
176 |
177 | ```php
178 | $config = $wise->load('config.ini');
179 | ```
180 |
181 | If you want a flattened version of your configuration data, delimited by ".",
182 | you may instead use the `loadFlat()` method:
183 |
184 | ```php
185 | $flatConfig = $wise->loadFlat('config.ini');
186 | ```
187 |
188 | This will turn this data:
189 |
190 | ```php
191 | array(
192 | 'one' => array(
193 | 'two' => array(
194 | 'three' => 123
195 | )
196 | ),
197 | 'two' => 2
198 | )
199 | ```
200 |
201 | into:
202 |
203 | ```php
204 | array(
205 | 'one.two.three' => 123,
206 | 'two' => 2
207 | )
208 | ```
209 |
210 | [create your own loader]: 02-HowToCreateALoader.md
211 | [documentation]: http://symfony.com/doc/current/components/config/definition.html
212 | [How to Create a Processor]: 03-HowToCreateAProcessor.md
213 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Loader/AbstractFileLoader.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | abstract class AbstractFileLoader extends FileLoader implements ResourceAwareInterface, WiseAwareInterface
22 | {
23 | /**
24 | * The resource collector.
25 | *
26 | * @var ResourceCollectorInterface
27 | */
28 | private $collector;
29 |
30 | /**
31 | * The Wise instance.
32 | *
33 | * @var Wise
34 | */
35 | private $wise;
36 |
37 | /**
38 | * Replace the placeholder value(s).
39 | *
40 | * @param mixed $input The input.
41 | * @param array $data The data the input is from.
42 | * @param array $global The global values.
43 | *
44 | * @return mixed The result.
45 | *
46 | * @throws InvalidReferenceException If an invalid reference is used.
47 | */
48 | public function doReplace($input, $data, $global)
49 | {
50 | preg_match_all(
51 | '/%(?P[^%]+)%/',
52 | $input,
53 | $matches
54 | );
55 |
56 | if (false === empty($matches['reference'])) {
57 | foreach ($matches['reference'] as $reference) {
58 | try {
59 | $ref = $this->resolveReference($reference, $data);
60 | } catch (InvalidReferenceException $exception) {
61 | if (empty($global)) {
62 | throw $exception;
63 | }
64 |
65 | $ref = $this->resolveReference($reference, $global);
66 | }
67 |
68 | if ((false === is_null($ref))
69 | && (false === is_scalar($ref))
70 | && (false == preg_match('/^%(?:[^%]+)%$/', $input))) {
71 | throw InvalidReferenceException::format(
72 | 'The non-scalar reference "%s" cannot be used inline.',
73 | "%$reference%"
74 | );
75 | }
76 |
77 | if ("%$reference%" === $input) {
78 | $input = $ref;
79 | } else {
80 | $input = str_replace("%$reference%", $ref, $input);
81 | }
82 | }
83 | }
84 |
85 | return $input;
86 | }
87 |
88 | /**
89 | * {@inheritDoc}
90 | */
91 | public function getResourceCollector()
92 | {
93 | return $this->collector;
94 | }
95 |
96 | /**
97 | * {@inheritDoc}
98 | */
99 | public function getWise()
100 | {
101 | return $this->wise;
102 | }
103 |
104 | /**
105 | * {@inheritDoc}
106 | */
107 | public function load($resource, $type = null)
108 | {
109 | $file = $this->locator->locate($resource, $type);
110 |
111 | if ($this->collector) {
112 | $this->collector->addResource(new FileResource($file));
113 | }
114 |
115 | $data = $this->doLoad($file);
116 |
117 | return $this->process($data, $resource);
118 | }
119 |
120 | /**
121 | * Imports other configuration files and resolves references.
122 | *
123 | * @param array $data The data.
124 | * @param string $file The file source.
125 | *
126 | * @return array The processed data.
127 | *
128 | * @throws ImportException If "imports" is invalid.
129 | * @throws InvalidReferenceException If an invalid reference is used.
130 | */
131 | public function process($data, $file)
132 | {
133 | if (empty($data)) {
134 | return array();
135 | }
136 |
137 | if (isset($data['imports'])) {
138 | if (false === is_array($data['imports'])) {
139 | throw ImportException::format(
140 | 'The "imports" value is not valid in "%s".',
141 | $file
142 | );
143 | }
144 |
145 | $dir = dirname($file);
146 |
147 | foreach ($data['imports'] as $i => $import) {
148 | if (false === is_array($import)) {
149 | throw ImportException::format(
150 | 'One of the "imports" values (#%d) is not valid in "%s".',
151 | $i,
152 | $file
153 | );
154 | }
155 |
156 | if (false === isset($import['resource'])) {
157 | throw ImportException::format(
158 | 'A resource was not defined for an import in "%s".',
159 | $file
160 | );
161 | }
162 |
163 | $this->setCurrentDir($dir);
164 |
165 | $data = array_replace_recursive(
166 | $this->import(
167 | $import['resource'],
168 | null,
169 | isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false
170 | ),
171 | $data
172 | );
173 | }
174 | }
175 |
176 | $global = $this->wise ? $this->wise->getGlobalParameters() : array();
177 | $_this = $this;
178 |
179 | ArrayUtil::walkRecursive(
180 | $data,
181 | function (&$value, $key, &$array) use (&$data, $global, $_this) {
182 | $value = $_this->doReplace($value, $data, $global);
183 |
184 | if (false !== strpos($key, '%')) {
185 | unset($array[$key]);
186 |
187 | $key = $_this->doReplace($key, $data, $global);
188 |
189 | $array[$key] = $value;
190 | }
191 | }
192 | );
193 |
194 | return $data;
195 | }
196 |
197 | /**
198 | * Resolves the reference and returns its value.
199 | *
200 | * @param string $reference A reference.
201 | * @param array|ArrayAccess $values A list of values.
202 | *
203 | * @return mixed The referenced value.
204 | *
205 | * @throws InvalidReferenceException If the reference is not valid.
206 | */
207 | public function resolveReference($reference, $values)
208 | {
209 | foreach (explode('.', $reference) as $leaf) {
210 | if ((!is_array($values) && !($values instanceof ArrayAccess))
211 | || (is_array($values) && !array_key_exists($leaf, $values))
212 | || (($values instanceof ArrayAccess) && !$values->offsetExists($leaf))) {
213 | throw InvalidReferenceException::format(
214 | 'The reference "%s" could not be resolved (failed at "%s").',
215 | "%$reference%",
216 | $leaf
217 | );
218 | }
219 |
220 | $values = $values[$leaf];
221 | }
222 |
223 | return $values;
224 | }
225 |
226 | /**
227 | * {@inheritDoc}
228 | */
229 | public function setResourceCollector(ResourceCollectorInterface $collector)
230 | {
231 | $this->collector = $collector;
232 | }
233 |
234 | /**
235 | * {@inheritDoc}
236 | */
237 | public function setWise(Wise $wise)
238 | {
239 | $this->wise = $wise;
240 | }
241 |
242 | /**
243 | * Returns the parsed data of the file.
244 | *
245 | * @param string $file The file path.
246 | *
247 | * @return array The parsed data.
248 | */
249 | abstract protected function doLoad($file);
250 | }
251 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/Loader/AbstractFileLoaderTest.php:
--------------------------------------------------------------------------------
1 | setPropertyValue($this->loader, 'collector', $this->collector);
30 |
31 | $this->assertSame(
32 | $this->collector,
33 | $this->loader->getResourceCollector()
34 | );
35 | }
36 |
37 | public function testGetWise()
38 | {
39 | $wise = new Wise();
40 |
41 | $this->setPropertyValue($this->loader, 'wise', $wise);
42 |
43 | $this->assertSame($wise, $this->loader->getWise());
44 | }
45 |
46 | public function testLoad()
47 | {
48 | $data = array('rand' => rand());
49 |
50 | file_put_contents(
51 | "{$this->dir}/test.php",
52 | 'setPropertyValue($this->loader, 'collector', $this->collector);
56 | $this->assertSame($data, $this->loader->load('test.php'));
57 |
58 | $resources = $this->collector->getResources();
59 |
60 | $this->assertCount(1, $resources);
61 | $this->assertInstanceOf(
62 | 'Symfony\\Component\\Config\\Resource\\FileResource',
63 | $resources[0]
64 | );
65 | }
66 |
67 | public function testProcessEmpty()
68 | {
69 | $this->assertSame(array(), $this->loader->process(null, 'test.file'));
70 | }
71 |
72 | /**
73 | * @expectedException \Herrera\Wise\Exception\ImportException
74 | * @expectedExceptionMessage The "imports" value is not valid in "test.file".
75 | */
76 | public function testProcessInvalidImports()
77 | {
78 | $this->loader->process(array('imports' => 123), 'test.file');
79 | }
80 |
81 | /**
82 | * @expectedException \Herrera\Wise\Exception\ImportException
83 | * @expectedExceptionMessage One of the "imports" values (#0) is not valid in "test.file".
84 | */
85 | public function testProcessInvalidImport()
86 | {
87 | $this->loader->process(
88 | array('imports' => array(123)),
89 | 'test.file'
90 | );
91 | }
92 |
93 | /**
94 | * @expectedException \Herrera\Wise\Exception\ImportException
95 | * @expectedExceptionMessage A resource was not defined for an import in "test.file".
96 | */
97 | public function testProcessInvalidImportMissingResource()
98 | {
99 | $this->loader->process(
100 | array('imports' => array(array())),
101 | 'test.file'
102 | );
103 | }
104 |
105 | public function testProcess()
106 | {
107 | $wise = new Wise();
108 | $wise->setGlobalParameters(
109 | array(
110 | 'global' => array(
111 | 'value' => 999
112 | )
113 | )
114 | );
115 |
116 | $this->setPropertyValue($this->loader, 'wise', $wise);
117 |
118 | file_put_contents(
119 | "{$this->dir}/one.php",
120 | ' array(
123 | array('resource' => 'two.php')
124 | ),
125 | 'global' => '%global.value%',
126 | 'placeholder' => '%imported.list%',
127 | 'sub' => array(
128 | 'inline_placeholder' => 'rand: %imported.list.null%%imported.value%',
129 | ),
130 | '%imported.key%' => 'a value'
131 | ),
132 | true
133 | ) . ';'
134 | );
135 |
136 | file_put_contents(
137 | "{$this->dir}/two.php",
138 | ' array(
141 | 'key' => 'replaced_key',
142 | 'list' => array(
143 | 'null' => null,
144 | 'value' => 123
145 | ),
146 | 'value' => $rand = rand()
147 | )
148 | ),
149 | true
150 | ) . ';'
151 | );
152 |
153 | $this->assertEquals(
154 | array(
155 | 'imports' => array(
156 | array(
157 | 'resource' => 'two.php'
158 | )
159 | ),
160 | 'global' => 999,
161 | 'placeholder' => array(
162 | 'null' => null,
163 | 'value' => 123
164 | ),
165 | 'sub' => array(
166 | 'inline_placeholder' => 'rand: ' . $rand,
167 | ),
168 | 'replaced_key' => 'a value',
169 | 'imported' => array(
170 | 'key' => 'replaced_key',
171 | 'list' => array(
172 | 'null' => null,
173 | 'value' => 123
174 | ),
175 | 'value' => $rand
176 | )
177 | ),
178 | $this->loader->load('one.php')
179 | );
180 | }
181 |
182 | /**
183 | * @expectedException \Herrera\Wise\Exception\InvalidReferenceException
184 | * @expectedExceptionMessage The reference "%test.reference%" could not be resolved (failed at "test").
185 | */
186 | public function testProcessInvalidReference()
187 | {
188 | $this->loader->process(
189 | array(
190 | 'bad_reference' => '%test.reference%'
191 | ),
192 | 'test.php'
193 | );
194 | }
195 |
196 | /**
197 | * @expectedException \Herrera\Wise\Exception\InvalidReferenceException
198 | * @expectedExceptionMessage The non-scalar reference "%test.reference%" cannot be used inline.
199 | */
200 | public function testProcessNonScalarReference()
201 | {
202 | $this->loader->process(
203 | array(
204 | 'bad_reference' => 'bad: %test.reference%',
205 | 'test' => array(
206 | 'reference' => array(
207 | 'value' => 123
208 | )
209 | )
210 | ),
211 | 'test.php'
212 | );
213 | }
214 |
215 | /**
216 | * @expectedException \Herrera\Wise\Exception\InvalidReferenceException
217 | * @expectedExceptionMessage The reference "%a.b.c.d%" could not be resolved (failed at "a").
218 | */
219 | public function testResolveReferenceInvalid()
220 | {
221 | $this->loader->resolveReference('a.b.c.d', array());
222 | }
223 |
224 | public function testResolveReference()
225 | {
226 | $array = array(
227 | 'a' => array(
228 | 'b' => array(
229 | 'c' => array(
230 | 'd' => 123
231 | )
232 | )
233 | )
234 | );
235 |
236 | $object = new ArrayObject($array);
237 |
238 | $this->assertEquals(
239 | 123,
240 | $this->loader->resolveReference('a.b.c.d', $array)
241 | );
242 |
243 | $this->assertEquals(
244 | 123,
245 | $this->loader->resolveReference('a.b.c.d', $object)
246 | );
247 | }
248 |
249 | /**
250 | * @depends testGetResourceCollector
251 | */
252 | public function testSetResourceCollector()
253 | {
254 | $this->loader->setResourceCollector($this->collector);
255 |
256 | $this->assertSame(
257 | $this->collector,
258 | $this->loader->getResourceCollector()
259 | );
260 | }
261 |
262 | /**
263 | * @depends testGetWise
264 | */
265 | public function testSetWise()
266 | {
267 | $wise = new Wise();
268 |
269 | $this->loader->setWise($wise);
270 |
271 | $this->assertSame($wise, $this->loader->getWise());
272 | }
273 |
274 | protected function setUp()
275 | {
276 | $this->dir = $this->createDir();
277 | $this->collector = new ResourceCollector();
278 | $this->loader = new ExampleFileLoader(new FileLocator($this->dir));
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/src/lib/Herrera/Wise/Wise.php:
--------------------------------------------------------------------------------
1 |
26 | */
27 | class Wise
28 | {
29 | /**
30 | * The cache directory path.
31 | *
32 | * @var string
33 | */
34 | private $cacheDir;
35 |
36 | /**
37 | * The resource collector.
38 | *
39 | * @var ResourceCollectorInterface
40 | */
41 | private $collector;
42 |
43 | /**
44 | * The debug mode flag.
45 | *
46 | * @var boolean
47 | */
48 | private $debug;
49 |
50 | /**
51 | * The configuration loader.
52 | *
53 | * @var LoaderInterface
54 | */
55 | private $loader;
56 |
57 | /**
58 | * The list of global parameters.
59 | *
60 | * @var array
61 | */
62 | private $parameters = array();
63 |
64 | /**
65 | * The configuration processor.
66 | *
67 | * @var ProcessorInterface
68 | */
69 | private $processor;
70 |
71 | /**
72 | * Sets the debugging mode.
73 | *
74 | * @param boolean $debug Enable debugging?
75 | */
76 | public function __construct($debug = false)
77 | {
78 | $this->debug = $debug;
79 | }
80 |
81 | /**
82 | * Creates a pre-configured instance of Wise.
83 | *
84 | * @param array|string $paths The configuration directory path(s).
85 | * @param string $cache The cache directory path.
86 | * @param boolean $debug Enable debugging?
87 | *
88 | * @return Wise The instance.
89 | */
90 | public static function create($paths, $cache = null, $debug = false)
91 | {
92 | $wise = new self($debug);
93 |
94 | if ($cache) {
95 | $wise->setCacheDir($cache);
96 | }
97 |
98 | $locator = new FileLocator($paths);
99 | $resolver = new LoaderResolver(
100 | array(
101 | new Loader\IniFileLoader($locator),
102 | new Loader\JsonFileLoader($locator),
103 | new Loader\PhpFileLoader($locator),
104 | new Loader\XmlFileLoader($locator),
105 | new Loader\YamlFileLoader($locator),
106 | )
107 | );
108 |
109 | $wise->setCollector(new Resource\ResourceCollector());
110 | $wise->setLoader(new DelegatingLoader($resolver));
111 |
112 | $resolver->setResourceCollector($wise->getCollector());
113 | $resolver->setWise($wise);
114 |
115 | return $wise;
116 | }
117 |
118 | /**
119 | * Returns the cache directory path.
120 | *
121 | * @return string The path.
122 | */
123 | public function getCacheDir()
124 | {
125 | return $this->cacheDir;
126 | }
127 |
128 | /**
129 | * Returns the resource collector.
130 | *
131 | * @return ResourceCollectorInterface The collector.
132 | */
133 | public function getCollector()
134 | {
135 | return $this->collector;
136 | }
137 |
138 | /**
139 | * Returns the list of global parameters.
140 | *
141 | * @return array The parameters.
142 | */
143 | public function getGlobalParameters()
144 | {
145 | return $this->parameters;
146 | }
147 |
148 | /**
149 | * Returns the configuration loader.
150 | *
151 | * @return LoaderInterface The loader.
152 | */
153 | public function getLoader()
154 | {
155 | return $this->loader;
156 | }
157 |
158 | /**
159 | * Returns the configuration processor.
160 | *
161 | * @return ProcessorInterface The processor.
162 | */
163 | public function getProcessor()
164 | {
165 | return $this->processor;
166 | }
167 |
168 | /**
169 | * Checks if debugging is enabled.
170 | *
171 | * @return boolean TRUE if it is enabled, FALSE if not.
172 | */
173 | public function isDebugEnabled()
174 | {
175 | return $this->debug;
176 | }
177 |
178 | /**
179 | * Loads the configuration data from a resource.
180 | *
181 | * @param mixed $resource A resource.
182 | * @param string $type The resource type.
183 | * @param boolean $require Require processing?
184 | *
185 | * @return array The data.
186 | *
187 | * @throws LoaderException If the loader could not be used.
188 | * @throws LogicException If no loader has been configured.
189 | */
190 | public function load($resource, $type = null, $require = false)
191 | {
192 | if (null === $this->loader) {
193 | throw new LogicException('No loader has been configured.');
194 | }
195 |
196 | if (false === $this->loader->supports($resource, $type)) {
197 | throw LoaderException::format(
198 | 'The resource "%s"%s is not supported by the loader.',
199 | is_scalar($resource) ? $resource : gettype($resource),
200 | $type ? " ($type)" : ''
201 | );
202 | }
203 |
204 | if ($this->cacheDir
205 | && $this->collector
206 | && is_string($resource)
207 | && (false === strpos("\n", $resource))
208 | && (false === strpos("\r", $resource))) {
209 | $cache = new ConfigCache(
210 | $this->cacheDir . DIRECTORY_SEPARATOR . basename($resource) . '.cache',
211 | $this->debug
212 | );
213 |
214 | if ($cache->isFresh()) {
215 | /** @noinspection PhpIncludeInspection */
216 | return require $cache;
217 | }
218 | }
219 |
220 | if ($this->collector) {
221 | $this->collector->clearResources();
222 | }
223 |
224 | $data = $this->process(
225 | $this->loader->load($resource, $type),
226 | $resource,
227 | $type,
228 | $require
229 | );
230 |
231 | if (isset($cache)) {
232 | $cache->write(
233 | 'collector->getResources()
235 | );
236 | }
237 |
238 | return $data;
239 | }
240 |
241 | /**
242 | * Loads the configuration data from a resource and returns it flattened.
243 | *
244 | * @param mixed $resource A resource.
245 | * @param string $type The resource type.
246 | * @param boolean $require Require processing?
247 | *
248 | * @return array The data.
249 | */
250 | public function loadFlat($resource, $type = null, $require = false)
251 | {
252 | return ArrayUtil::flatten($this->load($resource, $type, $require));
253 | }
254 |
255 | /**
256 | * Sets the cache directory path.
257 | *
258 | * @param string $path The path.
259 | */
260 | public function setCacheDir($path)
261 | {
262 | $this->cacheDir = $path;
263 | }
264 |
265 | /**
266 | * Sets the resource collector.
267 | *
268 | * @param ResourceCollectorInterface $collector The collector.
269 | */
270 | public function setCollector(ResourceCollectorInterface $collector)
271 | {
272 | $this->collector = $collector;
273 |
274 | if ($this->loader) {
275 | if ($this->loader instanceof ResourceAwareInterface) {
276 | $this->loader->setResourceCollector($collector);
277 | }
278 |
279 | if ($this->loader instanceof DelegatingLoader) {
280 | $resolver = $this->loader->getResolver();
281 |
282 | if ($resolver instanceof ResourceAwareInterface) {
283 | $resolver->setResourceCollector($collector);
284 | }
285 | }
286 | }
287 | }
288 |
289 | /**
290 | * Sets a list of global parameters.
291 | *
292 | * @param array|ArrayAccess $parameters The parameters.
293 | *
294 | * @throws InvalidArgumentException If $parameters is invalid.
295 | */
296 | public function setGlobalParameters($parameters)
297 | {
298 | if (!is_array($parameters) && !($parameters instanceof ArrayAccess)) {
299 | throw new InvalidArgumentException(
300 | 'The $parameters argument must be an array or array accessible object.'
301 | );
302 | }
303 |
304 | $this->parameters = $parameters;
305 | }
306 |
307 | /**
308 | * Sets a configuration loader.
309 | *
310 | * @param LoaderInterface $loader A loader.
311 | */
312 | public function setLoader(LoaderInterface $loader)
313 | {
314 | $this->loader = $loader;
315 |
316 | if ($this->collector && ($loader instanceof ResourceAwareInterface)) {
317 | $loader->setResourceCollector($this->collector);
318 | }
319 |
320 | if ($loader instanceof WiseAwareInterface) {
321 | $loader->setWise($this);
322 | }
323 |
324 | if ($loader instanceof DelegatingLoader) {
325 | $resolver = $loader->getResolver();
326 |
327 | if ($this->collector && ($resolver instanceof ResourceAwareInterface)) {
328 | $resolver->setResourceCollector($this->collector);
329 | }
330 |
331 | if ($resolver instanceof WiseAwareInterface) {
332 | $resolver->setWise($this);
333 | }
334 |
335 | }
336 | }
337 |
338 | /**
339 | * Sets a configuration processor.
340 | *
341 | * @param ConfigurationInterface $processor A processor.
342 | */
343 | public function setProcessor(ConfigurationInterface $processor)
344 | {
345 | $this->processor = $processor;
346 | }
347 |
348 | /**
349 | * Processes the configuration definition.
350 | *
351 | * @param array $data The configuration data.
352 | * @param mixed $resource A resource.
353 | * @param string $type The resource type.
354 | * @param boolean $require Require processing?
355 | *
356 | * @return array The processed configuration data.
357 | *
358 | * @throws ProcessorException If the processor could not be used and it is
359 | * require that one be used.
360 | */
361 | private function process(array $data, $resource, $type, $require)
362 | {
363 | if ($this->processor) {
364 | if ($this->processor instanceof ProcessorInterface) {
365 | if ($this->processor->supports($resource, $type)) {
366 | $data = $this->processor->process($data);
367 | } elseif ($require) {
368 | throw ProcessorException::format(
369 | 'The resource "%s"%s is not supported by the processor.',
370 | is_string($resource) ? $resource : gettype($resource),
371 | $type ? " ($type)" : ''
372 | );
373 | }
374 | } else {
375 | $processor = new Processor();
376 | $data = $processor->processConfiguration(
377 | $this->processor,
378 | $data
379 | );
380 | }
381 | } elseif ($require) {
382 | throw ProcessorException::format(
383 | 'No processor registered to handle any resource.'
384 | );
385 | }
386 |
387 | return $data;
388 | }
389 | }
390 |
--------------------------------------------------------------------------------
/src/tests/Herrera/Wise/Tests/WiseTest.php:
--------------------------------------------------------------------------------
1 | assertTrue($this->getPropertyValue($this->wise, 'debug'));
49 |
50 | $wise = new Wise();
51 |
52 | $this->assertFalse($this->getPropertyValue($wise, 'debug'));
53 | }
54 |
55 | public function testCreate()
56 | {
57 | file_put_contents(
58 | $this->dir . '/test.php',
59 | << array(
62 | 'number' => 123
63 | )
64 | );
65 | PHP
66 | );
67 |
68 | $wise = Wise::create($this->dir, $this->cache, true);
69 | $expected = array(
70 | 'root' => array(
71 | 'number' => 123
72 | )
73 | );
74 |
75 | $this->assertEquals($expected, $wise->load('test.php', 'php'));
76 | $this->assertFileExists($this->cache . '/test.php.cache');
77 | $this->assertFileExists($this->cache . '/test.php.cache.meta');
78 |
79 | /** @var $delegator \Symfony\Component\Config\Loader\DelegatingLoader */
80 | $delegator = $this->getPropertyValue($wise, 'loader');
81 |
82 | /** @var $loaders \Herrera\Wise\Loader\LoaderResolver */
83 | $resolver = $delegator->getResolver();
84 |
85 | /** @var $loader \Herrera\Wise\Loader\AbstractFileLoader */
86 | foreach ($resolver->getLoaders() as $loader) {
87 | $this->assertSame(
88 | $wise->getCollector(),
89 | $loader->getResourceCollector()
90 | );
91 | $this->assertSame($wise, $loader->getWise());
92 | }
93 | }
94 |
95 | public function testGetCacheDir()
96 | {
97 | $this->setPropertyValue($this->wise, 'cacheDir', $this->cache);
98 |
99 | $this->assertEquals($this->cache, $this->wise->getCacheDir());
100 | }
101 |
102 | public function testGetCollector()
103 | {
104 | $this->setPropertyValue($this->wise, 'collector', $this->collector);
105 |
106 | $this->assertSame($this->collector, $this->wise->getCollector());
107 | }
108 |
109 | public function testGetGlobalParameters()
110 | {
111 | $this->setPropertyValue(
112 | $this->wise,
113 | 'parameters',
114 | array('value' => 123)
115 | );
116 |
117 | $this->assertEquals(
118 | array('value' => 123),
119 | $this->wise->getGlobalParameters()
120 | );
121 | }
122 |
123 | public function testGetLoader()
124 | {
125 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
126 |
127 | $this->assertSame($this->loader, $this->wise->getLoader());
128 | }
129 |
130 | public function testGetProcessor()
131 | {
132 | $this->setPropertyValue($this->wise, 'processor', $this->processor);
133 |
134 | $this->assertSame($this->processor, $this->wise->getProcessor());
135 | }
136 |
137 | /**
138 | * @depends testConstruct
139 | */
140 | public function testIsDebugEnabled()
141 | {
142 | $this->assertTrue($this->wise->isDebugEnabled());
143 | }
144 |
145 | /**
146 | * @expectedException \Herrera\Wise\Exception\LogicException
147 | * @expectedExceptionMessage No loader has been configured.
148 | */
149 | public function testLoadLoaderNotSet()
150 | {
151 | $this->wise->load('test');
152 | }
153 |
154 | /**
155 | * @expectedException \Herrera\Wise\Exception\LoaderException
156 | * @expectedExceptionMessage The resource "123" (test) is not supported by the loader.
157 | */
158 | public function testLoadLoaderNotSupported()
159 | {
160 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
161 |
162 | $this->wise->load(123, 'test');
163 | }
164 |
165 | public function testLoad()
166 | {
167 | file_put_contents(
168 | $this->dir . '/test.php',
169 | << array(
172 | 'number' => 123
173 | )
174 | );
175 | PHP
176 | );
177 |
178 | $expected = array(
179 | 'enabled' => false,
180 | 'number' => '123'
181 | );
182 |
183 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
184 |
185 | $this->assertEquals(
186 | array(
187 | 'root' => array(
188 | 'number' => 123
189 | )
190 | ),
191 | $this->wise->load('test.php', 'php')
192 | );
193 |
194 | $this->setPropertyValue($this->wise, 'cacheDir', $this->cache);
195 | $this->setPropertyValue($this->wise, 'collector', $this->collector);
196 | $this->setPropertyValue($this->wise, 'debug', true);
197 | $this->setPropertyValue($this->wise, 'processor', $this->processor);
198 |
199 | $this->assertEquals($expected, $this->wise->load('test.php', 'php'));
200 | $this->assertFileExists($this->cache . '/test.php.cache');
201 | $this->assertFileExists($this->cache . '/test.php.cache.meta');
202 |
203 | /** @noinspection PhpIncludeInspection */
204 | $this->assertEquals($expected, require $this->cache . '/test.php.cache');
205 |
206 | $meta = unserialize(
207 | file_get_contents(
208 | $this->cache . '/test.php.cache.meta'
209 | )
210 | );
211 |
212 | $this->assertCount(1, $meta);
213 | $this->assertInstanceOf(
214 | 'Symfony\\Component\\Config\\Resource\\FileResource',
215 | $meta[0]
216 | );
217 |
218 | file_put_contents($this->dir . '/test.php', '');
219 | touch(
220 | $this->dir . '/test.php',
221 | filemtime($this->cache . '/test.php.cache') - 1000
222 | );
223 |
224 | $this->assertEquals($expected, $this->wise->load('test.php', 'php'));
225 | }
226 |
227 | /**
228 | * @depends testLoad
229 | */
230 | public function testLoadFlat()
231 | {
232 | file_put_contents(
233 | $this->dir . '/test.php',
234 | << array(
237 | 'number' => 123
238 | )
239 | );
240 | PHP
241 | );
242 |
243 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
244 |
245 | $this->assertEquals(
246 | array(
247 | 'root.number' => 123
248 | ),
249 | $this->wise->loadFlat('test.php', 'php')
250 | );
251 | }
252 |
253 | public function testLoadWithBasicProcessor()
254 | {
255 | file_put_contents(
256 | $this->dir . '/test.php',
257 | << array(
260 | 'number' => 123
261 | )
262 | );
263 | PHP
264 | );
265 |
266 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
267 | $this->setPropertyValue($this->wise, 'processor', new BasicProcessor());
268 |
269 | $this->assertEquals(
270 | array(
271 | 'enabled' => false,
272 | 'number' => 123
273 | ),
274 | $this->wise->load('test.php', 'php')
275 | );
276 | }
277 |
278 | public function testLoadNoProcessorSupported()
279 | {
280 | file_put_contents(
281 | $this->dir . '/test.php',
282 | << array(
285 | 'number' => 123
286 | )
287 | );
288 | PHP
289 | );
290 |
291 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
292 | $this->setPropertyValue(
293 | $this->wise,
294 | 'processor',
295 | new NeverSupportedProcessor()
296 | );
297 |
298 | $this->setExpectedException(
299 | 'Herrera\\Wise\\Exception\\ProcessorException',
300 | 'The resource "test.php" (php) is not supported by the processor.'
301 | );
302 |
303 | $this->wise->load('test.php', 'php', true);
304 | }
305 |
306 | public function testLoadNoProcessorRegistered()
307 | {
308 | file_put_contents(
309 | $this->dir . '/test.php',
310 | << array(
313 | 'number' => 123
314 | )
315 | );
316 | PHP
317 | );
318 |
319 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
320 |
321 | $this->setExpectedException(
322 | 'Herrera\\Wise\\Exception\\ProcessorException',
323 | 'No processor registered to handle any resource.'
324 | );
325 |
326 | $this->wise->load('test.php', 'php', true);
327 | }
328 |
329 | /**
330 | * @depends testGetCacheDir
331 | */
332 | public function testSetCacheDir()
333 | {
334 | $this->wise->setCacheDir($this->cache);
335 |
336 | $this->assertEquals($this->cache, $this->wise->getCacheDir());
337 | }
338 |
339 | /**
340 | * @depends testGetCollector
341 | */
342 | public function testSetCollector()
343 | {
344 | $this->setPropertyValue($this->wise, 'loader', $this->loader);
345 |
346 | $this->wise->setCollector($this->collector);
347 |
348 | $this->assertSame($this->collector, $this->wise->getCollector());
349 | $this->assertSame(
350 | $this->collector,
351 | $this->loader->getResourceCollector()
352 | );
353 | }
354 |
355 | public function testSetCollectorDelegator()
356 | {
357 | $resolver = new LoaderResolver();
358 | $loader = new DelegatingLoader($resolver);
359 |
360 | $this->setPropertyValue($this->wise, 'loader', $loader);
361 |
362 | $this->wise->setCollector($this->collector);
363 |
364 | $this->assertSame($this->collector, $resolver->getResourceCollector());
365 | }
366 |
367 | /**
368 | * @depends testGetGlobalParameters
369 | */
370 | public function testSetGlobalParameters()
371 | {
372 | $this->wise->setGlobalParameters(array('value' => 123));
373 |
374 | $this->assertEquals(
375 | array('value' => 123),
376 | $this->wise->getGlobalParameters()
377 | );
378 | }
379 |
380 | public function testSetGlobalParametersInvalid()
381 | {
382 | $this->setExpectedException(
383 | 'Herrera\\Wise\\Exception\\InvalidArgumentException',
384 | 'The $parameters argument must be an array or array accessible object.'
385 | );
386 |
387 | $this->wise->setGlobalParameters(true);
388 | }
389 |
390 | /**
391 | * @depends testGetLoader
392 | */
393 | public function testSetLoader()
394 | {
395 | $this->setPropertyValue($this->wise, 'collector', $this->collector);
396 |
397 | $this->wise->setLoader($this->loader);
398 |
399 | $this->assertSame($this->loader, $this->wise->getLoader());
400 | $this->assertSame(
401 | $this->collector,
402 | $this->loader->getResourceCollector()
403 | );
404 | $this->assertSame(
405 | $this->wise,
406 | $this->loader->getWise()
407 | );
408 | }
409 |
410 | public function setSetLoaderDelegator()
411 | {
412 | $this->setPropertyValue($this->wise, 'collector', $this->collector);
413 |
414 | $resolver = new LoaderResolver();
415 | $loader = new DelegatingLoader($resolver);
416 |
417 | $this->wise->setLoader($loader);
418 |
419 | $this->assertSame($this->collector, $resolver->getResourceCollector());
420 | $this->assertSame($this->wise, $resolver->getWise());
421 | }
422 |
423 | /**
424 | * @depends testGetProcessor
425 | */
426 | public function testSetProcessor()
427 | {
428 | $this->wise->setProcessor($this->processor);
429 |
430 | $this->assertSame($this->processor, $this->wise->getProcessor());
431 |
432 | $processor = new BasicProcessor();
433 |
434 | $this->wise->setProcessor($processor);
435 |
436 | $this->assertSame($processor, $this->wise->getProcessor());
437 | }
438 |
439 | protected function setUp()
440 | {
441 | $this->cache = $this->createDir();
442 | $this->dir = $this->createDir();
443 |
444 | $this->collector = new ResourceCollector();
445 | $this->loader = new PhpFileLoader(new FileLocator($this->dir));
446 | $this->processor = new TestProcessor();
447 | $this->wise = new Wise(true);
448 |
449 | $this->loader->setResourceCollector($this->collector);
450 | }
451 | }
452 |
--------------------------------------------------------------------------------