Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like FOSElasticaExtension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use FOSElasticaExtension, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class FOSElasticaExtension extends Extension |
||
27 | { |
||
28 | /** |
||
29 | * Definition of elastica clients as configured by this extension. |
||
30 | * |
||
31 | * @var array |
||
32 | */ |
||
33 | private $clients = []; |
||
34 | |||
35 | /** |
||
36 | * An array of indexes as configured by the extension. |
||
37 | * |
||
38 | * @var array |
||
39 | */ |
||
40 | private $indexConfigs = []; |
||
41 | |||
42 | /** |
||
43 | * An array of index templates as configured by the extension. |
||
44 | * |
||
45 | * @var array |
||
46 | */ |
||
47 | private $indexTemplateConfigs = array(); |
||
48 | |||
49 | /** |
||
50 | * If we've encountered a type mapped to a specific persistence driver, it will be loaded |
||
51 | * here. |
||
52 | * |
||
53 | * @var array |
||
54 | */ |
||
55 | private $loadedDrivers = []; |
||
56 | |||
57 | 20 | public function load(array $configs, ContainerBuilder $container) |
|
58 | { |
||
59 | 20 | $configuration = $this->getConfiguration($configs, $container); |
|
60 | 20 | $config = $this->processConfiguration($configuration, $configs); |
|
61 | |||
62 | 20 | $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
|
63 | |||
64 | 20 | if (empty($config['clients']) || empty($config['indexes'])) { |
|
65 | // No Clients or indexes are defined |
||
66 | return; |
||
67 | } |
||
68 | |||
69 | 20 | foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) { |
|
70 | 20 | $loader->load(sprintf('%s.xml', $basename)); |
|
71 | } |
||
72 | |||
73 | 20 | if (empty($config['default_client'])) { |
|
74 | 20 | $keys = array_keys($config['clients']); |
|
75 | 20 | $config['default_client'] = reset($keys); |
|
76 | } |
||
77 | |||
78 | 20 | if (empty($config['default_index'])) { |
|
79 | 20 | $keys = array_keys($config['indexes']); |
|
80 | 20 | $config['default_index'] = reset($keys); |
|
81 | } |
||
82 | |||
83 | 20 | if (isset($config['serializer'])) { |
|
84 | 1 | $loader->load('serializer.xml'); |
|
85 | |||
86 | 1 | $this->loadSerializer($config['serializer'], $container); |
|
87 | } |
||
88 | |||
89 | 20 | $this->loadClients($config['clients'], $container); |
|
90 | 20 | $container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client'])); |
|
91 | 20 | $container->getAlias('fos_elastica.client')->setPublic(true); |
|
92 | 20 | $container->setAlias(ElasticaClient::class, new Alias('fos_elastica.client', false)); |
|
93 | 20 | $container->setAlias(Client::class, 'fos_elastica.client'); |
|
94 | 20 | $container->getAlias(Client::class)->setPublic(false); |
|
95 | |||
96 | 20 | $this->loadIndexes($config['indexes'], $container); |
|
97 | 20 | $container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); |
|
98 | 20 | $container->getAlias('fos_elastica.index')->setPublic(true); |
|
99 | 20 | $container->setParameter('fos_elastica.default_index', $config['default_index']); |
|
100 | |||
101 | 20 | if ($usedIndexNames = \array_intersect_key($config['indexes'], $config['index_templates'])) { |
|
102 | throw new \DomainException( |
||
103 | \sprintf( |
||
104 | 'Index names "%s" are already in use and can not be used for index templates names', |
||
105 | \implode('","', \array_keys($usedIndexNames)) |
||
106 | ) |
||
107 | ); |
||
108 | } |
||
109 | 20 | $this->loadIndexTemplates($config['index_templates'], $container); |
|
110 | |||
111 | 20 | $container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs); |
|
112 | $container |
||
113 | 20 | ->getDefinition('fos_elastica.config_source.template_container') |
|
114 | 20 | ->replaceArgument(0, $this->indexTemplateConfigs); |
|
115 | |||
116 | 20 | $this->loadIndexManager($container); |
|
117 | 20 | $this->loadIndexTemplateManager($container); |
|
118 | |||
119 | 20 | $this->createDefaultManagerAlias($config['default_manager'], $container); |
|
120 | 20 | } |
|
121 | |||
122 | /** |
||
123 | * @param array $config |
||
124 | * @param ContainerBuilder $container |
||
125 | * |
||
126 | * @return Configuration |
||
127 | */ |
||
128 | 20 | public function getConfiguration(array $config, ContainerBuilder $container) |
|
129 | { |
||
130 | 20 | return new Configuration($container->getParameter('kernel.debug')); |
|
131 | } |
||
132 | |||
133 | /** |
||
134 | * Loads the configured clients. |
||
135 | * |
||
136 | * @param array $clients An array of clients configurations |
||
137 | * @param ContainerBuilder $container A ContainerBuilder instance |
||
138 | * |
||
139 | * @return array |
||
140 | */ |
||
141 | 20 | private function loadClients(array $clients, ContainerBuilder $container) |
|
142 | { |
||
143 | 20 | foreach ($clients as $name => $clientConfig) { |
|
144 | 20 | $clientId = sprintf('fos_elastica.client.%s', $name); |
|
145 | |||
146 | 20 | $clientDef = new ChildDefinition('fos_elastica.client_prototype'); |
|
147 | 20 | $clientDef->replaceArgument(0, $clientConfig); |
|
148 | 20 | $clientDef->replaceArgument(1, null); |
|
149 | |||
150 | 20 | $logger = $clientConfig['connections'][0]['logger']; |
|
151 | 20 | if (false !== $logger) { |
|
152 | 20 | $clientDef->addMethodCall('setLogger', [new Reference($logger)]); |
|
153 | } |
||
154 | |||
155 | 20 | $clientDef->addTag('fos_elastica.client'); |
|
156 | |||
157 | 20 | $container->setDefinition($clientId, $clientDef); |
|
158 | |||
159 | 20 | $this->clients[$name] = [ |
|
160 | 20 | 'id' => $clientId, |
|
161 | 20 | 'reference' => new Reference($clientId), |
|
162 | ]; |
||
163 | } |
||
164 | 20 | } |
|
165 | |||
166 | /** |
||
167 | * Loads the configured indexes. |
||
168 | * |
||
169 | * @param array $indexes An array of indexes configurations |
||
170 | * @param ContainerBuilder $container A ContainerBuilder instance |
||
171 | * |
||
172 | * @throws \InvalidArgumentException |
||
173 | * |
||
174 | * @return array |
||
175 | */ |
||
176 | 20 | private function loadIndexes(array $indexes, ContainerBuilder $container) |
|
177 | { |
||
178 | 20 | $indexableCallbacks = []; |
|
179 | |||
180 | 20 | foreach ($indexes as $name => $index) { |
|
181 | 20 | $indexId = sprintf('fos_elastica.index.%s', $name); |
|
182 | 20 | $indexName = isset($index['index_name']) ? $index['index_name'] : $name; |
|
183 | |||
184 | 20 | $indexDef = new ChildDefinition('fos_elastica.index_prototype'); |
|
185 | 20 | $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']); |
|
186 | 20 | $indexDef->replaceArgument(0, $indexName); |
|
187 | 20 | $indexDef->addTag('fos_elastica.index', [ |
|
188 | 20 | 'name' => $name, |
|
189 | ]); |
||
190 | |||
191 | 20 | View Code Duplication | if (isset($index['client'])) { |
192 | 1 | $client = $this->getClient($index['client']); |
|
193 | |||
194 | 1 | $indexDef->setFactory([$client, 'getIndex']); |
|
195 | } |
||
196 | |||
197 | 20 | $container->setDefinition($indexId, $indexDef); |
|
198 | 20 | $reference = new Reference($indexId); |
|
199 | |||
200 | 20 | $this->indexConfigs[$name] = [ |
|
201 | 20 | 'elasticsearch_name' => $indexName, |
|
202 | 20 | 'reference' => $reference, |
|
203 | 20 | 'name' => $name, |
|
204 | 20 | 'settings' => $index['settings'], |
|
205 | 20 | 'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [], |
|
206 | 20 | 'use_alias' => $index['use_alias'], |
|
207 | ]; |
||
208 | |||
209 | 20 | if ($index['finder']) { |
|
210 | $this->loadIndexFinder($container, $name, $reference); |
||
211 | } |
||
212 | |||
213 | 20 | $this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks); |
|
214 | } |
||
215 | |||
216 | 20 | $indexable = $container->getDefinition('fos_elastica.indexable'); |
|
217 | 20 | $indexable->replaceArgument(0, $indexableCallbacks); |
|
218 | 20 | } |
|
219 | |||
220 | /** |
||
221 | * Loads the configured indexes. |
||
222 | * |
||
223 | * @param array $indexTemplates An array of indexes configurations |
||
224 | * @param ContainerBuilder $container A ContainerBuilder instance |
||
225 | * |
||
226 | * @throws \InvalidArgumentException |
||
227 | * |
||
228 | * @return void |
||
229 | */ |
||
230 | 20 | private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container) |
|
231 | { |
||
232 | 20 | $indexableCallbacks = array(); |
|
233 | 20 | foreach ($indexTemplates as $name => $indexTemplate) { |
|
234 | 6 | $indexId = sprintf('fos_elastica.index_template.%s', $name); |
|
235 | 6 | $indexTemplateName = isset($indexTemplate['template_name']) ? $indexTemplate['template_name'] : $name; |
|
236 | |||
237 | 6 | $indexDef = new ChildDefinition('fos_elastica.index_template_prototype'); |
|
238 | 6 | $indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndexTemplate']); |
|
239 | 6 | $indexDef->replaceArgument(0, $indexTemplateName); |
|
240 | 6 | $indexDef->addTag('fos_elastica.index_template', array( |
|
241 | 6 | 'name' => $name, |
|
242 | )); |
||
243 | |||
244 | 6 | View Code Duplication | if (isset($indexTemplate['client'])) { |
245 | 6 | $client = $this->getClient($indexTemplate['client']); |
|
246 | 6 | $indexDef->setFactory([$client, 'getIndexTemplate']); |
|
247 | } |
||
248 | |||
249 | 6 | $container->setDefinition($indexId, $indexDef); |
|
250 | 6 | $reference = new Reference($indexId); |
|
251 | |||
252 | 6 | $this->indexTemplateConfigs[$name] = array( |
|
253 | 6 | 'elasticsearch_name' => $indexTemplateName, |
|
254 | 6 | 'reference' => $reference, |
|
255 | 6 | 'name' => $name, |
|
256 | 6 | 'settings' => $indexTemplate['settings'], |
|
257 | 6 | 'template' => $indexTemplate['template'], |
|
258 | ); |
||
259 | |||
260 | 6 | $this->loadTypes( |
|
261 | 6 | (array) $indexTemplate['types'], |
|
262 | $container, |
||
263 | 6 | $this->indexTemplateConfigs[$name], |
|
264 | $indexableCallbacks |
||
265 | ); |
||
266 | } |
||
267 | |||
268 | 20 | if ($indexableCallbacks) { |
|
|
|||
269 | throw new \RuntimeException('`indexable_callback` option is not supported by index templates'); |
||
270 | } |
||
271 | 20 | } |
|
272 | |||
273 | /** |
||
274 | * Loads the configured index finders. |
||
275 | * |
||
276 | * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
||
277 | * @param string $name The index name |
||
278 | * @param Reference $index Reference to the related index |
||
279 | * |
||
280 | * @return string |
||
281 | */ |
||
282 | private function loadIndexFinder(ContainerBuilder $container, string $name, Reference $index): void |
||
283 | { |
||
284 | $finderId = sprintf('fos_elastica.finder.%s', $name); |
||
285 | $finderDef = new ChildDefinition('fos_elastica.finder'); |
||
286 | $finderDef->replaceArgument(0, $index); |
||
287 | $finderDef->replaceArgument(1, new Reference(sprintf('fos_elastica.elastica_to_model_transformer.%s', $name))); |
||
288 | |||
289 | $container->setDefinition($finderId, $finderDef); |
||
290 | } |
||
291 | |||
292 | /** |
||
293 | * Loads the configured types. |
||
294 | */ |
||
295 | 20 | private function loadTypes(array $types, ContainerBuilder $container, array &$indexConfig, array &$indexableCallbacks): void |
|
296 | { |
||
297 | 20 | foreach ($types as $name => $type) { |
|
298 | 20 | $indexName = $indexConfig['name']; |
|
299 | |||
300 | $typeConfig = [ |
||
301 | 20 | 'name' => $name, |
|
302 | 'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch |
||
303 | 'config' => [], |
||
304 | ]; |
||
305 | |||
306 | foreach ([ |
||
307 | 20 | 'dynamic_templates', |
|
308 | 'properties', |
||
309 | '_all', |
||
310 | '_id', |
||
311 | '_routing', |
||
312 | '_source', |
||
313 | ] as $field) { |
||
314 | 20 | if (isset($type[$field])) { |
|
315 | 20 | $typeConfig['mapping'][$field] = $type[$field]; |
|
316 | } |
||
317 | } |
||
318 | |||
319 | foreach ([ |
||
320 | 20 | 'persistence', |
|
321 | 'serializer', |
||
322 | 'analyzer', |
||
323 | 'search_analyzer', |
||
324 | 'dynamic', |
||
325 | 'date_detection', |
||
326 | 'dynamic_date_formats', |
||
327 | 'numeric_detection', |
||
328 | ] as $field) { |
||
329 | 20 | $typeConfig['config'][$field] = array_key_exists($field, $type) ? |
|
330 | 20 | $type[$field] : |
|
331 | 20 | null; |
|
332 | } |
||
333 | |||
334 | 20 | $indexConfig['types'][$name] = $typeConfig; |
|
335 | |||
336 | 20 | if (isset($type['persistence'])) { |
|
337 | 14 | $this->loadTypePersistenceIntegration($type['persistence'], $container, $indexConfig['reference'], $indexName); |
|
338 | |||
339 | 14 | $typeConfig['persistence'] = $type['persistence']; |
|
340 | } |
||
341 | |||
342 | 20 | if (isset($type['indexable_callback'])) { |
|
343 | 4 | $indexableCallbacks[$indexName] = $this->buildCallback($type['indexable_callback'], $indexName); |
|
344 | } |
||
345 | |||
346 | 20 | if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { |
|
347 | 1 | $indexSerializerId = sprintf('%s.serializer.callback', $indexConfig['reference']); |
|
348 | 1 | $indexSerializerDef = new ChildDefinition('fos_elastica.serializer_callback_prototype'); |
|
349 | |||
350 | 1 | if (isset($type['serializer']['groups'])) { |
|
351 | 1 | $indexSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]); |
|
352 | } |
||
353 | |||
354 | 1 | if (isset($type['serializer']['serialize_null'])) { |
|
355 | 1 | $indexSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]); |
|
356 | } |
||
357 | |||
358 | 1 | if (isset($type['serializer']['version'])) { |
|
359 | 1 | $indexSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]); |
|
360 | } |
||
361 | |||
362 | 1 | $container->setDefinition($indexSerializerId, $indexSerializerDef); |
|
363 | } |
||
364 | } |
||
365 | 20 | } |
|
366 | |||
367 | 4 | private function buildCallback($indexCallback, $indexName) |
|
368 | { |
||
369 | 4 | if (is_array($indexCallback)) { |
|
370 | 4 | if (!isset($indexCallback[0])) { |
|
371 | throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for index %s', $indexName)); |
||
372 | } |
||
373 | |||
374 | 4 | $classOrServiceRef = $this->transformServiceReference($indexCallback[0]); |
|
375 | 4 | if ($classOrServiceRef instanceof Reference && !isset($indexCallback[1])) { |
|
376 | return $classOrServiceRef; // __invoke |
||
377 | } |
||
378 | |||
379 | 4 | if (!isset($indexCallback[1])) { |
|
380 | throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for index %s', $indexName)); |
||
381 | } |
||
382 | |||
383 | 4 | return [$classOrServiceRef, $indexCallback[1]]; |
|
384 | } |
||
385 | |||
386 | 4 | if (is_string($indexCallback)) { |
|
387 | 4 | return $this->transformServiceReference($indexCallback); |
|
388 | } |
||
389 | |||
390 | throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for index %s', $indexName)); |
||
391 | } |
||
392 | |||
393 | 4 | private function transformServiceReference($classOrService) |
|
394 | { |
||
395 | 4 | return 0 === strpos($classOrService, '@') ? new Reference(substr($classOrService, 1)) : $classOrService; |
|
396 | } |
||
397 | |||
398 | /** |
||
399 | * Loads the optional provider and finder for a type. |
||
400 | */ |
||
401 | 14 | private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $indexRef, string $indexName): void |
|
402 | { |
||
403 | 14 | if (isset($typeConfig['driver'])) { |
|
404 | 14 | $this->loadDriver($container, $typeConfig['driver']); |
|
405 | } |
||
406 | |||
407 | 14 | $elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName); |
|
408 | 14 | $modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName); |
|
409 | 14 | $objectPersisterId = $this->loadObjectPersister($typeConfig, $indexRef, $container, $indexName, $modelToElasticaTransformerId); |
|
410 | |||
411 | 14 | if (isset($typeConfig['provider'])) { |
|
412 | 14 | $this->loadTypePagerProvider($typeConfig, $container, $indexName); |
|
413 | } |
||
414 | 14 | if (isset($typeConfig['finder'])) { |
|
415 | 14 | $this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $indexRef, $indexName); |
|
416 | } |
||
417 | 14 | if (isset($typeConfig['listener']) && $typeConfig['listener']['enabled']) { |
|
418 | 13 | $this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName); |
|
419 | } |
||
420 | 14 | } |
|
421 | |||
422 | /** |
||
423 | * Creates and loads an ElasticaToModelTransformer. |
||
424 | */ |
||
425 | 14 | private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, string $indexName): string |
|
426 | { |
||
427 | 14 | if (isset($typeConfig['elastica_to_model_transformer']['service'])) { |
|
428 | 1 | return $typeConfig['elastica_to_model_transformer']['service']; |
|
429 | } |
||
430 | |||
431 | /* Note: transformer services may conflict with "prototype.driver", if |
||
432 | * the index and type names were "prototype" and a driver, respectively. |
||
433 | */ |
||
434 | 13 | $abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']); |
|
435 | 13 | $serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s', $indexName); |
|
436 | 13 | $serviceDef = new ChildDefinition($abstractId); |
|
437 | 13 | $serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['index' => $indexName]); |
|
438 | |||
439 | 13 | $serviceDef->replaceArgument(1, $typeConfig['model']); |
|
440 | 13 | $serviceDef->replaceArgument(2, array_merge($typeConfig['elastica_to_model_transformer'], [ |
|
441 | 13 | 'identifier' => $typeConfig['identifier'], |
|
442 | ])); |
||
443 | 13 | $container->setDefinition($serviceId, $serviceDef); |
|
444 | |||
445 | 13 | return $serviceId; |
|
446 | } |
||
447 | |||
448 | /** |
||
449 | * Creates and loads a ModelToElasticaTransformer for an index/type. |
||
450 | */ |
||
451 | 14 | private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, string $indexName): string |
|
452 | { |
||
453 | 14 | if (isset($typeConfig['model_to_elastica_transformer']['service'])) { |
|
454 | return $typeConfig['model_to_elastica_transformer']['service']; |
||
455 | } |
||
456 | |||
457 | 14 | $abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ? |
|
458 | 1 | 'fos_elastica.model_to_elastica_identifier_transformer' : |
|
459 | 14 | 'fos_elastica.model_to_elastica_transformer'; |
|
460 | |||
461 | 14 | $serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s', $indexName); |
|
462 | 14 | $serviceDef = new ChildDefinition($abstractId); |
|
463 | 14 | $serviceDef->replaceArgument(0, [ |
|
464 | 14 | 'identifier' => $typeConfig['identifier'], |
|
465 | 14 | 'index' => $indexName, |
|
466 | ]); |
||
467 | 14 | $container->setDefinition($serviceId, $serviceDef); |
|
468 | |||
469 | 14 | return $serviceId; |
|
470 | } |
||
471 | |||
472 | /** |
||
473 | * Creates and loads an object persister for a type. |
||
474 | */ |
||
475 | 14 | private function loadObjectPersister(array $typeConfig, Reference $indexRef, ContainerBuilder $container, string $indexName, string $transformerId): string |
|
476 | { |
||
477 | 14 | if (isset($typeConfig['persister']['service'])) { |
|
478 | 1 | return $typeConfig['persister']['service']; |
|
479 | } |
||
480 | |||
481 | $arguments = [ |
||
482 | 13 | $indexRef, |
|
483 | 13 | new Reference($transformerId), |
|
484 | 13 | $typeConfig['model'], |
|
485 | ]; |
||
486 | |||
487 | 13 | if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { |
|
488 | 1 | $abstractId = 'fos_elastica.object_serializer_persister'; |
|
489 | 1 | $callbackId = sprintf('%s.serializer.callback', $this->indexConfigs[$indexName]['reference']); |
|
490 | 1 | $arguments[] = [new Reference($callbackId), 'serialize']; |
|
491 | } else { |
||
492 | 12 | $abstractId = 'fos_elastica.object_persister'; |
|
493 | 12 | $mapping = $this->indexConfigs[$indexName]['types']['_doc']['mapping']; |
|
494 | 12 | $argument = $mapping['properties']; |
|
495 | 12 | $arguments[] = $argument; |
|
496 | } |
||
497 | |||
498 | 13 | $arguments[] = array_intersect_key($typeConfig['persister'], array_flip(['refresh'])); |
|
499 | |||
500 | 13 | $serviceId = sprintf('fos_elastica.object_persister.%s', $indexName); |
|
501 | 13 | $serviceDef = new ChildDefinition($abstractId); |
|
502 | 13 | foreach ($arguments as $i => $argument) { |
|
503 | 13 | $serviceDef->replaceArgument($i, $argument); |
|
504 | } |
||
505 | |||
506 | 13 | $serviceDef->addTag('fos_elastica.persister', ['index' => $indexName]); |
|
507 | |||
508 | 13 | $container->setDefinition($serviceId, $serviceDef); |
|
509 | |||
510 | 13 | return $serviceId; |
|
511 | } |
||
512 | |||
513 | /** |
||
514 | * Loads a pager provider for a type. |
||
515 | */ |
||
516 | 14 | private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, string $indexName): string |
|
517 | { |
||
518 | 14 | if (isset($typeConfig['provider']['service'])) { |
|
519 | return $typeConfig['provider']['service']; |
||
520 | } |
||
521 | |||
522 | 14 | $baseConfig = $typeConfig['provider']; |
|
523 | 14 | unset($baseConfig['service']); |
|
524 | |||
525 | 14 | $driver = $typeConfig['driver']; |
|
526 | |||
527 | 14 | switch ($driver) { |
|
528 | 14 | case 'orm': |
|
529 | 13 | $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
|
530 | 13 | $providerDef->replaceArgument(2, $typeConfig['model']); |
|
531 | 13 | $providerDef->replaceArgument(3, $baseConfig); |
|
532 | |||
533 | 13 | break; |
|
534 | 1 | View Code Duplication | case 'mongodb': |
535 | $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
||
536 | $providerDef->replaceArgument(2, $typeConfig['model']); |
||
537 | $providerDef->replaceArgument(3, $baseConfig); |
||
538 | |||
539 | break; |
||
540 | 1 | View Code Duplication | case 'phpcr': |
541 | 1 | $providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
|
542 | 1 | $providerDef->replaceArgument(2, $typeConfig['model']); |
|
543 | 1 | $providerDef->replaceArgument(3, $baseConfig); |
|
544 | |||
545 | 1 | break; |
|
546 | default: |
||
547 | throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver)); |
||
548 | } |
||
549 | |||
550 | /* Note: provider services may conflict with "prototype.driver", if the |
||
551 | * index and type names were "prototype" and a driver, respectively. |
||
552 | */ |
||
553 | 14 | $providerId = sprintf('fos_elastica.pager_provider.%s', $indexName); |
|
554 | 14 | $providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName]); |
|
555 | |||
556 | 14 | $container->setDefinition($providerId, $providerDef); |
|
557 | |||
558 | 14 | return $providerId; |
|
559 | } |
||
560 | |||
561 | /** |
||
562 | * Loads doctrine listeners to handle indexing of new or updated objects. |
||
563 | */ |
||
564 | 13 | private function loadTypeListener(array $typeConfig, ContainerBuilder $container, string $objectPersisterId, string $indexName): string |
|
565 | { |
||
566 | 13 | if (isset($typeConfig['listener']['service'])) { |
|
567 | return $typeConfig['listener']['service']; |
||
568 | } |
||
569 | |||
570 | /* Note: listener services may conflict with "prototype.driver", if the |
||
571 | * index and type names were "prototype" and a driver, respectively. |
||
572 | */ |
||
573 | 13 | $abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']); |
|
574 | 13 | $listenerId = sprintf('fos_elastica.listener.%s', $indexName); |
|
575 | 13 | $listenerDef = new ChildDefinition($abstractListenerId); |
|
576 | 13 | $listenerDef->replaceArgument(0, new Reference($objectPersisterId)); |
|
577 | 13 | $listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ? |
|
578 | new Reference($typeConfig['listener']['logger']) : |
||
579 | 13 | null |
|
580 | ); |
||
581 | $listenerConfig = [ |
||
582 | 13 | 'identifier' => $typeConfig['identifier'], |
|
583 | 13 | 'indexName' => $indexName, |
|
584 | ]; |
||
585 | |||
586 | 13 | $tagName = null; |
|
587 | 13 | switch ($typeConfig['driver']) { |
|
588 | 13 | case 'orm': |
|
589 | 12 | $tagName = 'doctrine.event_listener'; |
|
590 | 12 | break; |
|
591 | 1 | case 'phpcr': |
|
592 | 1 | $tagName = 'doctrine_phpcr.event_listener'; |
|
593 | 1 | break; |
|
594 | case 'mongodb': |
||
595 | $tagName = 'doctrine_mongodb.odm.event_listener'; |
||
596 | break; |
||
597 | } |
||
598 | |||
599 | 13 | if ($typeConfig['listener']['defer']) { |
|
600 | $listenerDef->setPublic(true); |
||
601 | $listenerDef->addTag( |
||
602 | 'kernel.event_listener', |
||
603 | ['event' => 'kernel.terminate', 'method' => 'onTerminate'] |
||
604 | ); |
||
605 | $listenerDef->addTag( |
||
606 | 'kernel.event_listener', |
||
607 | ['event' => 'console.terminate', 'method' => 'onTerminate'] |
||
608 | ); |
||
609 | $listenerConfig['defer'] = true; |
||
610 | } |
||
611 | |||
612 | 13 | $listenerDef->replaceArgument(2, $listenerConfig); |
|
613 | |||
614 | 13 | if (null !== $tagName) { |
|
615 | 13 | foreach ($this->getDoctrineEvents($typeConfig) as $event) { |
|
616 | 13 | $listenerDef->addTag($tagName, ['event' => $event]); |
|
617 | } |
||
618 | } |
||
619 | |||
620 | 13 | $container->setDefinition($listenerId, $listenerDef); |
|
621 | |||
622 | 13 | return $listenerId; |
|
623 | } |
||
624 | |||
625 | /** |
||
626 | * Map Elastica to Doctrine events for the current driver. |
||
627 | */ |
||
628 | 13 | private function getDoctrineEvents(array $typeConfig) |
|
629 | { |
||
630 | 13 | switch ($typeConfig['driver']) { |
|
631 | 13 | case 'orm': |
|
632 | 12 | $eventsClass = '\Doctrine\ORM\Events'; |
|
633 | 12 | break; |
|
634 | 1 | case 'phpcr': |
|
635 | 1 | $eventsClass = '\Doctrine\ODM\PHPCR\Event'; |
|
636 | 1 | break; |
|
637 | case 'mongodb': |
||
638 | $eventsClass = '\Doctrine\ODM\MongoDB\Events'; |
||
639 | break; |
||
640 | default: |
||
641 | throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver'])); |
||
642 | } |
||
643 | |||
644 | 13 | $events = []; |
|
645 | $eventMapping = [ |
||
646 | 13 | 'insert' => [constant($eventsClass.'::postPersist')], |
|
647 | 13 | 'update' => [constant($eventsClass.'::postUpdate')], |
|
648 | 13 | 'delete' => [constant($eventsClass.'::preRemove')], |
|
649 | 13 | 'flush' => [constant($eventsClass.'::postFlush')], |
|
650 | ]; |
||
651 | |||
652 | 13 | foreach ($eventMapping as $event => $doctrineEvents) { |
|
653 | 13 | if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) { |
|
654 | 13 | $events = array_merge($events, $doctrineEvents); |
|
655 | } |
||
656 | } |
||
657 | |||
658 | 13 | return $events; |
|
659 | } |
||
660 | |||
661 | /** |
||
662 | * Loads a Type specific Finder. |
||
663 | */ |
||
664 | 14 | private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, string $elasticaToModelId, Reference $indexRef, string $indexName): string |
|
665 | { |
||
666 | 14 | if (isset($typeConfig['finder']['service'])) { |
|
667 | $finderId = $typeConfig['finder']['service']; |
||
668 | } else { |
||
669 | 14 | $finderId = sprintf('fos_elastica.finder.%s', $indexName); |
|
670 | 14 | $finderDef = new ChildDefinition('fos_elastica.finder'); |
|
671 | 14 | $finderDef->replaceArgument(0, $indexRef); |
|
672 | 14 | $finderDef->replaceArgument(1, new Reference($elasticaToModelId)); |
|
673 | 14 | $container->setDefinition($finderId, $finderDef); |
|
674 | } |
||
675 | |||
676 | 14 | $arguments = [$indexName, new Reference($finderId)]; |
|
677 | 14 | if (isset($typeConfig['repository'])) { |
|
678 | 4 | $arguments[] = $typeConfig['repository']; |
|
679 | } |
||
680 | |||
681 | 14 | $container->getDefinition('fos_elastica.repository_manager') |
|
682 | 14 | ->addMethodCall('addType', $arguments); |
|
683 | |||
684 | 14 | $managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']); |
|
685 | 14 | $container->getDefinition($managerId) |
|
686 | 14 | ->addMethodCall('addEntity', [$typeConfig['model'], $indexName]); |
|
687 | |||
688 | 14 | return $finderId; |
|
689 | } |
||
690 | |||
691 | /** |
||
692 | * Loads the index manager. |
||
693 | **/ |
||
694 | 20 | View Code Duplication | private function loadIndexManager(ContainerBuilder $container): void |
695 | { |
||
696 | $indexRefs = array_map(function ($index) { |
||
697 | 20 | return $index['reference']; |
|
698 | 20 | }, $this->indexConfigs); |
|
699 | |||
700 | 20 | $managerDef = $container->getDefinition('fos_elastica.index_manager'); |
|
701 | 20 | $managerDef->replaceArgument(0, $indexRefs); |
|
702 | 20 | } |
|
703 | |||
704 | /** |
||
705 | * Load index template manager |
||
706 | */ |
||
707 | 20 | View Code Duplication | private function loadIndexTemplateManager(ContainerBuilder $container): void |
708 | { |
||
709 | $indexTemplateRefs = array_map(function ($index) { |
||
710 | 6 | return $index['reference']; |
|
711 | 20 | }, $this->indexTemplateConfigs); |
|
712 | |||
713 | 20 | $managerDef = $container->getDefinition('fos_elastica.index_template_manager'); |
|
714 | 20 | $managerDef->replaceArgument(0, $indexTemplateRefs); |
|
715 | 20 | } |
|
716 | |||
717 | /** |
||
718 | * Makes sure a specific driver has been loaded. |
||
719 | */ |
||
720 | 14 | private function loadDriver(ContainerBuilder $container, string $driver): void |
|
730 | |||
731 | /** |
||
732 | * Loads and configures the serializer prototype. |
||
733 | */ |
||
734 | 1 | private function loadSerializer(array $config, ContainerBuilder $container): void |
|
735 | { |
||
736 | 1 | $container->setAlias('fos_elastica.serializer', $config['serializer']); |
|
737 | |||
738 | 1 | $serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype'); |
|
739 | 1 | $serializer->setClass($config['callback_class']); |
|
740 | |||
741 | 1 | if (is_subclass_of($config['callback_class'], ContainerAwareInterface::class)) { |
|
742 | $serializer->addMethodCall('setContainer', [new Reference('service_container')]); |
||
743 | } |
||
744 | 1 | } |
|
745 | |||
746 | /** |
||
747 | * Creates a default manager alias for defined default manager or the first loaded driver. |
||
748 | */ |
||
749 | 20 | private function createDefaultManagerAlias(string $defaultManager, ContainerBuilder $container): void |
|
768 | |||
769 | /** |
||
770 | * Returns a reference to a client given its configured name. |
||
771 | * |
||
772 | * @throws \InvalidArgumentException |
||
773 | */ |
||
774 | 7 | private function getClient(string $clientName): Reference |
|
782 | } |
||
783 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.