Completed
Push — develop ( 7bdff2...e8d178 )
by
unknown
08:10
created

OptionsAbstractFactory::createServiceWithName()   C

Complexity

Conditions 8
Paths 25

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 5.3846
c 0
b 0
f 0
cc 8
eloc 14
nc 25
nop 3
1
<?php
2
/**
3
 * YAWIK
4
 *
5
 * @filesource
6
 * @license    MIT
7
 * @copyright  2013 - 2016 Cross Solution <http://cross-solution.de>
8
 */
9
10
/** */
11
namespace Core\Factory;
12
13
use Interop\Container\ContainerInterface;
14
use Zend\ServiceManager\AbstractFactoryInterface;
15
use Zend\ServiceManager\ServiceLocatorInterface;
16
use Zend\Stdlib\AbstractOptions;
17
18
/**
19
 * Creates options instances from configuration specifications.
20
 *
21
 * @author Mathias Gelhausen <[email protected]>
22
 * @since  0.23
23
 */
24
class OptionsAbstractFactory implements AbstractFactoryInterface
25
{
26
27
    /**
28
     * Simple mode handles only skalar values, arrays and POPOs.
29
     */
30
    const MODE_SIMPLE = 'simple';
31
32
    /**
33
     * Nested mode is able to handle other options instances as an option value.
34
     */
35
    const MODE_NESTED = 'nested';
36
37
    /**
38
     * The configuration specification of all creatable options instances.
39
     *
40
     * The format is
41
     * <pre>
42
     * [
43
     *      'ServiceNameOfTheOptionsInstance' => [
44
     *          'class' => 'FQCN of the options class.',
45
     *          'mode' => SIMPLE or NESTED (optional, default SIMPLE)
46
     *          'options' => [
47
     *              'simpleSkalar' => 'value',
48
     *              'simpleArray' => [ 'someArray' ],
49
     *              'nestedOptions' => [
50
     *                  '__class__' => 'FQCN of the nested options class.',
51
     *                  'someValue' => 'skalar'
52
     *              ],
53
     *          ],
54
     *      ],
55
     * ];
56
     *
57
     * @var array
58
     */
59
    protected $optionsConfig;
60
61
    /**
62
     * Create an object
63
     *
64
     * @param  ContainerInterface $container
65
     * @param  string             $requestedName
66
     * @param  null|array         $options
67
     *
68
     * @return object
69
     */
70
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
71
    {
72
        return new $requestedName();
73
    }
74
75
    /**
76
     * Can the factory create an instance for the service?
77
     *
78
     * @param  ContainerInterface $container
79
     * @param  string             $requestedName
80
     *
81
     * @return bool
82
     */
83
    public function canCreate(ContainerInterface $container, $requestedName)
0 ignored issues
show
Coding Style introduced by
function canCreate() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
Unused Code introduced by
The parameter $container is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
84
    {
85
        return class_exists($requestedName);
86
    }
87
88
89
    /**
90
     * Determines if we can create an options instance with name.
91
     *
92
     * @param ServiceLocatorInterface $serviceLocator
93
     * @param string                  $name
94
     * @param string                  $requestedName
95
     *
96
     * @return bool
97
     */
98
    public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
99
    {
100
        // Load options config specifications the first time this method is called.
101
        if (null === $this->optionsConfig) {
102
            $mainConfig          = $serviceLocator->get('config');
103
            $this->optionsConfig = isset($mainConfig['options']) ? $mainConfig['options'] : [];
104
        }
105
        return false !== $this->getOptionsConfig($requestedName, $name);
106
    }
107
108
    /**
109
     * Creates an options instance  with name.
110
     *
111
     * @param ServiceLocatorInterface $serviceLocator
112
     * @param string                  $name
113
     * @param string                  $requestedName
114
     *
115
     * @return AbstractOptions
116
     * @throws \InvalidArgumentException
117
     */
118
    public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName)
119
    {
120
        $config = $this->getOptionsConfig($requestedName, $name);
121
122
        if (!isset($config['class']) && !class_exists($requestedName)) {
123
            throw new \InvalidArgumentException(sprintf(
124
                                                    'Missing index "class" from the config array for options "%s"',
125
                                                    $requestedName
126
                                                ));
127
        }
128
129
        $className = isset($config['class']) ? $config['class'] : $requestedName;
130
        $mode      = isset($config['mode']) ? $config['mode'] : self::MODE_SIMPLE;
131
        $options   = isset($config['options']) ? $config['options'] : [];
132
133
        if (self::MODE_SIMPLE == $mode) {
134
            return new $className($options);
135
        }
136
137
        if (self::MODE_NESTED == $mode) {
138
            return $this->createNestedOptions($className, $options);
139
140
        }
141
142
        throw new \InvalidArgumentException(sprintf('Unknown mode "%s".', $mode));
143
    }
144
145
146
    /**
147
     * Creates a nested options instance.
148
     *
149
     * @param string $className
150
     * @param array  $options
151
     *
152
     * @return AbstractOptions
153
     */
154
    protected function createNestedOptions($className, $options)
155
    {
156
        $class = new $className();
157
158
        foreach ($options as $key => $spec) {
159
            if (is_array($spec) && array_key_exists('__class__', $spec)) {
160
                $nestedClassName = $spec['__class__'];
161
                unset($spec['__class__']);
162
                $spec = $this->createNestedOptions($nestedClassName, $spec);
163
            }
164
165
            $class->{$key} = $spec;
166
        }
167
168
        return $class;
169
    }
170
171
    /**
172
     * Gets the configuration for a specific options instance.
173
     *
174
     * Returns FALSE if configuration cannot be found.
175
     *
176
     * @param string $fullName
177
     * @param string $normalizedName
178
     *
179
     * @return array|bool
180
     */
181
    protected function getOptionsConfig($fullName, $normalizedName)
182
    {
183
        if (array_key_exists($fullName, $this->optionsConfig)) {
184
            return $this->optionsConfig[$fullName];
185
        }
186
187
        if (array_key_exists($normalizedName, $this->optionsConfig)) {
188
            return $this->optionsConfig[$normalizedName];
189
        }
190
191
        return false;
192
    }
193
}