canCreateServiceWithName()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 3
1
<?php
2
3
namespace Abacaphiliac\Zend\Transformer\Factory;
4
5
use Abacaphiliac\Zend\Transformer\Config\TransformerConfig;
6
use Abacaphiliac\Zend\Transformer\Transformer;
7
use Assert\Assertion;
8
use Zend\Hydrator\ClassMethods;
9
use Zend\Hydrator\ExtractionInterface;
10
use Zend\Hydrator\HydrationInterface;
11
use Zend\Hydrator\HydratorPluginManager;
12
use Zend\ServiceManager\AbstractFactoryInterface;
13
use Zend\ServiceManager\AbstractPluginManager;
14
use Zend\ServiceManager\ServiceLocatorInterface;
15
use Zend\Validator\IsInstanceOf;
16
use Zend\Validator\ValidatorChain;
17
use Zend\Validator\ValidatorInterface;
18
use Zend\Validator\ValidatorPluginManager;
19
20
class AbstractTransformerFactory implements AbstractFactoryInterface
21
{
22
    private static $pluginManagers = [
23
        'HydratorManager' => HydratorPluginManager::class,
24
        'ValidatorManager' => ValidatorPluginManager::class,
25
    ];
26
    
27
    /**
28
     * Can the factory create an instance for the service?
29
     *
30
     * @param ServiceLocatorInterface $container
31
     * @param string $name
32
     * @param string $requestedName
33
     * @return bool
34
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
35
     */
36
    public function canCreateServiceWithName(ServiceLocatorInterface $container, $name, $requestedName)
37
    {
38
        if ($container instanceof AbstractPluginManager) {
39
            $container = $container->getServiceLocator();
40
        }
41
        
42
        return is_array($this->getTransformerConfig($container, $requestedName));
43
    }
44
    
45
    /**
46
     * Create an object
47
     *
48
     * @param ServiceLocatorInterface $container
49
     * @param string $name
50
     * @param string $requestedName
51
     * @return Transformer
52
     * @throws \Zend\Validator\Exception\InvalidArgumentException
53
     * @throws \Assert\AssertionFailedException
54
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
55
     * @internal param array|null $options
56
     */
57
    public function createServiceWithName(ServiceLocatorInterface $container, $name, $requestedName)
58
    {
59
        if ($container instanceof AbstractPluginManager) {
60
            $container = $container->getServiceLocator();
61
        }
62
        
63
        $config = new TransformerConfig($this->getTransformerConfig($container, $requestedName));
64
    
65
        $inputValidator = $this->getValidator($container, $config->getInputValidator(), $config->getInputClass());
0 ignored issues
show
Bug introduced by
It seems like $config->getInputValidator() targeting Abacaphiliac\Zend\Transf...ig::getInputValidator() can also be of type null or object<Zend\Validator\ValidatorInterface>; however, Abacaphiliac\Zend\Transf...Factory::getValidator() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
66
        $extractor = $this->getExtractor($container, $config->getExtractor());
0 ignored issues
show
Bug introduced by
It seems like $config->getExtractor() targeting Abacaphiliac\Zend\Transf...rConfig::getExtractor() can also be of type null or object<Zend\Hydrator\ExtractionInterface>; however, Abacaphiliac\Zend\Transf...Factory::getExtractor() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
67
        $transformer = $this->getTransformer($container, $config);
68
        $hydrator = $this->getHydrator($container, $config->getHydrator());
0 ignored issues
show
Bug introduced by
It seems like $config->getHydrator() targeting Abacaphiliac\Zend\Transf...erConfig::getHydrator() can also be of type null or object<Zend\Hydrator\HydrationInterface>; however, Abacaphiliac\Zend\Transf...rFactory::getHydrator() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
69
        $outputValidator = $this->getValidator($container, $config->getOutputValidator(), $config->getOutputClass());
0 ignored issues
show
Bug introduced by
It seems like $config->getOutputValidator() targeting Abacaphiliac\Zend\Transf...g::getOutputValidator() can also be of type null or object<Zend\Validator\ValidatorInterface>; however, Abacaphiliac\Zend\Transf...Factory::getValidator() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
70
        
71
        return new Transformer(
72
            $inputValidator,
73
            $extractor,
74
            $transformer,
75
            $hydrator,
76
            $outputValidator
77
        );
78
    }
79
    
80
    /**
81
     * @param ServiceLocatorInterface $container
82
     * @param string $requestedName
83
     * @return mixed[]
84
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
85
     */
86
    private function getTransformerConfig(ServiceLocatorInterface $container, $requestedName)
87
    {
88
        $applicationConfig = $container->get('config');
89
    
90
        return \igorw\get_in($applicationConfig, ['abacaphiliac/zend-transformer', 'transformers', $requestedName]);
0 ignored issues
show
Bug introduced by
It seems like $applicationConfig defined by $container->get('config') on line 88 can also be of type object; however, igorw\get_in() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
91
    }
92
    
93
    /**
94
     * @param ServiceLocatorInterface $container
95
     * @param string $service
96
     * @param string $validateIsInstanceOf
97
     * @return ValidatorInterface
98
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
99
     * @throws \Assert\AssertionFailedException
100
     * @throws \Zend\Validator\Exception\InvalidArgumentException
101
     * @internal param TransformerConfig $config
102
     */
103
    private function getValidator(ServiceLocatorInterface $container, $service, $validateIsInstanceOf = null)
104
    {
105
        if ($service instanceof ValidatorInterface) {
106
            return $service;
107
        }
108
        
109
        if ($service === null) {
110
            $validator = new ValidatorChain();
111
            
112
            if ($validateIsInstanceOf) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $validateIsInstanceOf of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
113
                $validator->attach(new IsInstanceOf(['className' => $validateIsInstanceOf]));
114
            }
115
            
116
            return $validator;
117
        }
118
        
119
        $validator = $this->getService($container, $service, 'ValidatorManager');
120
        Assertion::isInstanceOf($validator, ValidatorInterface::class);
121
        
122
        /** @var ValidatorInterface $validator */
123
        return $validator;
124
    }
125
    
126
    /**
127
     * @param ServiceLocatorInterface $container
128
     * @param string $service
129
     * @return ExtractionInterface
130
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
131
     * @throws \Assert\AssertionFailedException
132
     */
133 View Code Duplication
    private function getExtractor(ServiceLocatorInterface $container, $service)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
134
    {
135
        if ($service instanceof ExtractionInterface) {
136
            return $service;
137
        }
138
        
139
        if ($service === null) {
140
            return new ClassMethods();
141
        }
142
        
143
        $extractor = $this->getService($container, $service, 'HydratorManager');
144
        Assertion::isInstanceOf($extractor, ExtractionInterface::class);
145
        
146
        /** @var ExtractionInterface $extractor */
147
        return $extractor;
148
    }
149
    
150
    /**
151
     * @param ServiceLocatorInterface $container
152
     * @param string $service
153
     * @return HydrationInterface
154
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
155
     * @throws \Assert\AssertionFailedException
156
     */
157 View Code Duplication
    private function getHydrator(ServiceLocatorInterface $container, $service)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
158
    {
159
        if ($service instanceof HydrationInterface) {
160
            return $service;
161
        }
162
        
163
        if ($service === null) {
164
            return new ClassMethods();
165
        }
166
        
167
        $validator = $this->getService($container, $service, 'HydratorManager');
168
        Assertion::isInstanceOf($validator, HydrationInterface::class);
169
        
170
        /** @var HydrationInterface $validator */
171
        return $validator;
172
    }
173
    
174
    /**
175
     * @param ServiceLocatorInterface $container
176
     * @param string $pluginManagerName
177
     * @param string $service
178
     * @return Object
179
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
180
     * @throws \Assert\AssertionFailedException
181
     */
182
    private function getService(ServiceLocatorInterface $container, $service, $pluginManagerName)
183
    {
184
        $plugins = null;
185
        
186
        if ($container->has($pluginManagerName)) {
187
            // Get the named plugin-manager from parent container.
188
            $plugins = $container->get($pluginManagerName);
189
            Assertion::isInstanceOf($plugins, AbstractPluginManager::class);
190
        } elseif (isset(self::$pluginManagers[$pluginManagerName])) {
191
            // Create a new plugin-manager.
192
            $plugins = new self::$pluginManagers[$pluginManagerName];
193
            Assertion::isInstanceOf($plugins, AbstractPluginManager::class);
194
            
195
            /** @var AbstractPluginManager $plugins */
196
            $plugins->setServiceLocator($container);
197
        }
198
        
199
        if ($plugins instanceof ServiceLocatorInterface && $plugins->has($service)) {
200
            // Get the service/plugin from the plugin-manager.
201
            return $plugins->get($service);
202
        }
203
    
204
        // Fall-back to parent container for service since it could not be provided by a plugin-manager.
205
        return $container->get($service);
206
    }
207
    
208
    /**
209
     * @param ServiceLocatorInterface $container
210
     * @param TransformerConfig $config
211
     * @return callable
212
     * @throws \Zend\ServiceManager\Exception\ServiceNotFoundException
213
     */
214
    private function getTransformer(ServiceLocatorInterface $container, TransformerConfig $config)
215
    {
216
        $transformer = $config->getTransformer();
217
        if (is_callable($transformer)) {
218
            return $transformer;
219
        }
220
    
221
        $keyMap = $config->getKeyMap();
222
        if (is_array($keyMap)) {
223
            return function (array $data) use ($keyMap) {
224
                $result = [];
225
                foreach ($data as $key => $value) {
226
                    $result[\igorw\get_in($keyMap, [$key], $key)] = $value;
227
                }
228
                
229
                return $result;
230
            };
231
        }
232
        
233
        $transformer = $container->get($transformer);
234
        Assertion::isCallable($transformer);
235
        
236
        return $transformer;
237
    }
238
}
239