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()); |
|
|
|
|
66
|
|
|
$extractor = $this->getExtractor($container, $config->getExtractor()); |
|
|
|
|
67
|
|
|
$transformer = $this->getTransformer($container, $config); |
68
|
|
|
$hydrator = $this->getHydrator($container, $config->getHydrator()); |
|
|
|
|
69
|
|
|
$outputValidator = $this->getValidator($container, $config->getOutputValidator(), $config->getOutputClass()); |
|
|
|
|
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]); |
|
|
|
|
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) { |
|
|
|
|
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) |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
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.