Skip to content

Commit

Permalink
Merge pull request #14 from sandrokeil/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Sandro Keil committed Sep 24, 2014
2 parents 4fb3b2c + 9e3da9c commit 4e75786
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 12 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,10 @@
# EasyConfig CHANGELOG

## 1.3.0 (2014-09-24)

- Added MandatoryOptionsInterface to check for mandatory options automatically
- Added empty Module.php e.g. for modules.zendframework.com

## 1.2.0 (2014-04-29)

- Updated source to PSR-4
Expand Down
56 changes: 45 additions & 11 deletions README.md
@@ -1,4 +1,4 @@
# Easy Config module for Zend Framework 2
# EasyConfig module for Zend Framework 2

> You want to configure your factories via your module config?
Expand All @@ -18,7 +18,7 @@
[![Total Downloads](https://poser.pugx.org/sandrokeil/easy-config/downloads.png)](https://packagist.org/packages/sandrokeil/easy-config)
[![License](https://poser.pugx.org/sandrokeil/easy-config/license.png)](https://packagist.org/packages/sandrokeil/easy-config)

EasyConfig provides some abstract factories to easily create instances depending on configuration or retrieve specified module options.
EasyConfig provides some abstract factories and some interfaces to easily create instances depending on configuration or retrieve specified module options.

* **Well tested.** Besides unit test and continuous integration/inspection this solution is also ready for production use.
* **Great foundations.** Based on [Zend Framework 2](https://github.com/zendframework/zf2)
Expand All @@ -43,15 +43,16 @@ return array(
```

So `doctrine` is the module, `connection` is the scope and `orm_default` is the name. After that the specified instance options follow.
With [AbstractConfigurableFactory](https://github.com/sandrokeil/EasyConfig/tree/master/docs/Configurable.md) we can easily access to these options also with an option class.
With [AbstractConfigurableFactory](docs/Configurable.md) we can easily access to these options also with an option class and mandatory options check. See [docs](docs/Configurable.md) for a detailed explanation.

```php
use Sake\EasyConfig\Service\AbstractConfigurableFactory;
use Sake\EasyConfig\Service\OptionsClassInterface;
use Sake\EasyConfig\Service\MandatoryOptionsInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class MyDBALConnectionFactory extends AbstractConfigurableFactory implements FactoryInterface, OptionsClassInterface
class MyDBALConnectionFactory extends AbstractConfigurableFactory implements FactoryInterface, OptionsClassInterface, MandatoryOptionsInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
Expand All @@ -69,21 +70,54 @@ class MyDBALConnectionFactory extends AbstractConfigurableFactory implements Fac
return $instance;
}

/**
* Returns a list of mandatory options which must be available
*
* @return array
*/
public function getMandatoryOptions()
{
return array(
'driverClass',
'params',
);
}

/**
* Return the option class name (fcqn) where options are injected via constructor
*
* @return string
*/
public function getOptionsClass()
{
return '\DoctrineORMModule\Options\DBALConnection';
}

/**
* Module name
*
* @return string
*/
public function getModule()
{
return 'doctrine';
}

/**
* Config scope
*
* @return string
*/
public function getScope()
{
return 'connection';
}

/**
* Config name
*
* @return string
*/
public function getName()
{
return 'orm_default';
Expand All @@ -104,16 +138,16 @@ Put the following into your composer.json
}
}

It is not necessary to add this module to your `config/application.config.php`.
It is *not necessary* to add this module to your `config/application.config.php`.

## Documentation

You can find documentation about the usages of factories at the following links:

* [Configurable - Get an options class or an array of options](https://github.com/sandrokeil/EasyConfig/tree/master/docs/Configurable.md)
* [ConstructorOptionConfig - Inject options via constructor](https://github.com/sandrokeil/EasyConfig/tree/master/docs/ConstructorOptionConfig.md)
* [OptionHydratorConfig - Inject options with a hydrator](https://github.com/sandrokeil/EasyConfig/tree/master/docs/OptionHydratorConfig.md)
* [ServiceConfig - Inject an other service to instance](https://github.com/sandrokeil/EasyConfig/tree/master/docs/ServiceConfig.md)
* [ServiceManagerConfig - Inject Options to a service plugin manager](https://github.com/sandrokeil/EasyConfig/tree/master/docs/ServiceManagerConfig.md)
* [ServiceOptionConfig - Inject one or more services](https://github.com/sandrokeil/EasyConfig/tree/master/docs/ServiceOptionConfig.md)
* [Configurable - Get an options class or an array of options with mandytoy](docs/Configurable.md)
* [ConstructorOptionConfig - Inject options via constructor](docs/ConstructorOptionConfig.md)
* [OptionHydratorConfig - Inject options with a hydrator](docs/OptionHydratorConfig.md)
* [ServiceConfig - Inject an other service to instance](docs/ServiceConfig.md)
* [ServiceManagerConfig - Inject Options to a service plugin manager](docs/ServiceManagerConfig.md)
* [ServiceOptionConfig - Inject one or more services](docs/ServiceOptionConfig.md)

83 changes: 83 additions & 0 deletions docs/Configurable.md
Expand Up @@ -32,6 +32,29 @@ class MyDBALConnectionFactory extends AbstractConfigurableFactory implements Fac
{
// get options for doctrine.connection.orm_default
$options = $this->getOptions($serviceLocator);

// check if mandatory options are available
if (empty($options['driverClass'])) {
throw new Exception\RuntimeException(
sprintf(
'Driver class was not set for configuration %s.%s.%s',
$this->getModule(),
$this->getScope(),
$this->getName()
)
);
}

if (empty($options['params'])) {
throw new Exception\RuntimeException(
sprintf(
'Params was not set for configuration %s.%s.%s',
$this->getModule(),
$this->getScope(),
$this->getName()
)
);
}

$driverClass = $options['driverClass'];
$params = $options['params'];
Expand All @@ -57,6 +80,66 @@ class MyDBALConnectionFactory extends AbstractConfigurableFactory implements Fac
}
}
```

## Mandatory Options check
You can also check for mandatory options automatically with `MandatoryOptionsInterface`. Now we want also check that
option `driverClass` and `params` are available. So we also implement in the example above the interface
`MandatoryOptionsInterface`. If one of these options is missing, an exception is raised.

```php
use Sake\EasyConfig\Service\AbstractConfigurableFactory;
use Sake\EasyConfig\Service\MandatoryOptionsInterface;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class MyDBALConnectionFactory extends AbstractConfigurableFactory implements FactoryInterface, MandatoryOptionsInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
// get options for doctrine.connection.orm_default
$options = $this->getOptions($serviceLocator);

// mandatory options check is automatically done by MandatoryOptionsInterface

$driverClass = $options['driverClass'];
$params = $options['params'];

// create your instance and set options

return $instance;
}

/**
* Returns a list of mandatory options which must be available
*
* @return array
*/
public function getMandatoryOptions()
{
return array(
'driverClass',
'params',
);
}

public function getModule()
{
return 'doctrine';
}

public function getScope()
{
return 'connection';
}

public function getName()
{
return 'orm_default';
}
}
```
This can also be combined with `OptionsClassInterface`

## Option Class
If you implement `OptionClassInterface` then you get a option class. Your options class should extend from `\Zend\Stdlib\AbstractOptions`.
```
Expand Down
15 changes: 14 additions & 1 deletion src/Service/AbstractConfigurableFactory.php
Expand Up @@ -42,7 +42,20 @@ public function getOptions(ServiceLocatorInterface $sl)
));
}
$options = $options[$this->getModule()][$this->getScope()][$this->getName()];

// check for mandatory options
if ($this instanceof MandatoryOptionsInterface) {
foreach ($this->getMandatoryOptions() as $option) {
if (!isset($options[$option])) {
throw new Exception\RuntimeException(sprintf(
'Mandatory option "%s" was not set for configuration "%s.%s.%s".',
$option,
$this->getModule(),
$this->getScope(),
$this->getName()
));
}
}
}
// create option class
if ($this instanceof OptionsClassInterface) {
$optionClass = $this->getOptionsClass();
Expand Down
26 changes: 26 additions & 0 deletions src/Service/MandatoryOptionsInterface.php
@@ -0,0 +1,26 @@
<?php
/**
* Sake
*
* @link http://github.com/sandrokeil/EasyConfig for the canonical source repository
* @copyright Copyright (c) 2014 Sandro Keil
* @license http://github.com/sandrokeil/EasyConfig/blob/master/LICENSE.txt New BSD License
*/

namespace Sake\EasyConfig\Service;

/**
* Class MandatoryOptionsInterface
*
* Use this interface in a factory which extends from AbstractConfigurableFactory to check for required options
* automatically.
*/
interface MandatoryOptionsInterface
{
/**
* Returns a list of mandatory options which must be available
*
* @return array
*/
public function getMandatoryOptions();
}
39 changes: 39 additions & 0 deletions test/Service/AbstractConfigurableFactoryTest.php
Expand Up @@ -90,4 +90,43 @@ public function testGetOptionsShouldReturnOptionClass()
$this->assertSame('foo', $optionsClass->getFoo());
$this->assertSame('bar', $optionsClass->getBar());
}

/**
* Tests if getOptions() works with mandatory options interface
*
* @covers \Sake\EasyConfig\Service\AbstractConfigurableFactory::getOptions
*/
public function testGetOptionsShouldCheckMandatoryOptions()
{
$stub = parent::getStub('\SakeTest\EasyConfig\Service\TestAsset\AbstractMandatoryOptionsFactory');

$stub->expects($this->any())
->method('getMandatoryOptions')
->will($this->returnValue(array('invokables')));

$options = $stub->getOptions($this->serviceManager);

$this->assertArrayHasKey('invokables', $options);
}

/**
* Tests if getOptions() throws a runtime exception if mandatory option is missing
*
* @covers \Sake\EasyConfig\Service\AbstractConfigurableFactory::getOptions
*/
public function testGetOptionsShouldThrowRuntimeExceptionIfMandatoryOptionIsMissing()
{
$stub = parent::getStub('\SakeTest\EasyConfig\Service\TestAsset\AbstractMandatoryOptionsFactory');

$stub->expects($this->any())
->method('getMandatoryOptions')
->will($this->returnValue(array('invalid')));

$this->setExpectedException(
'\Sake\EasyConfig\Service\Exception\RuntimeException',
'Mandatory option "invalid"'
);

$stub->getOptions($this->serviceManager);
}
}
17 changes: 17 additions & 0 deletions test/Service/TestAsset/AbstractMandatoryOptionsFactory.php
@@ -0,0 +1,17 @@
<?php
/**
* Sake
*
* @link http://github.com/sandrokeil/EasyConfig for the canonical source repository
* @copyright Copyright (c) 2014 Sandro Keil
* @license http://github.com/sandrokeil/EasyConfig/blob/master/LICENSE.txt New BSD License
*/

namespace SakeTest\EasyConfig\Service\TestAsset;

use Sake\EasyConfig\Service;

abstract class AbstractMandatoryOptionsFactory extends Service\AbstractConfigurableFactory implements
Service\MandatoryOptionsInterface
{
}

0 comments on commit 4e75786

Please sign in to comment.