1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the FOSElasticaBundle package. |
5
|
|
|
* |
6
|
|
|
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace FOS\ElasticaBundle\DependencyInjection; |
13
|
|
|
|
14
|
|
|
use Elastica\Client as ElasticaClient; |
15
|
|
|
use FOS\ElasticaBundle\Elastica\Client; |
16
|
|
|
use FOS\ElasticaBundle\Manager\RepositoryManagerInterface; |
17
|
|
|
use Symfony\Component\Config\FileLocator; |
18
|
|
|
use Symfony\Component\DependencyInjection\Alias; |
19
|
|
|
use Symfony\Component\DependencyInjection\ChildDefinition; |
20
|
|
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface; |
21
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder; |
22
|
|
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; |
23
|
|
|
use Symfony\Component\DependencyInjection\Reference; |
24
|
|
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension; |
25
|
|
|
|
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
|
21 |
|
public function load(array $configs, ContainerBuilder $container) |
58
|
|
|
{ |
59
|
21 |
|
$configuration = $this->getConfiguration($configs, $container); |
60
|
21 |
|
$config = $this->processConfiguration($configuration, $configs); |
61
|
|
|
|
62
|
21 |
|
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
63
|
|
|
|
64
|
21 |
|
if (empty($config['clients']) || empty($config['indexes'])) { |
65
|
|
|
// No Clients or indexes are defined |
66
|
|
|
return; |
67
|
|
|
} |
68
|
|
|
|
69
|
21 |
|
foreach (['config', 'index', 'persister', 'provider', 'source', 'transformer', 'event_listener', 'commands'] as $basename) { |
70
|
21 |
|
$loader->load(sprintf('%s.xml', $basename)); |
71
|
|
|
} |
72
|
|
|
|
73
|
21 |
|
if (empty($config['default_client'])) { |
74
|
21 |
|
$keys = array_keys($config['clients']); |
75
|
21 |
|
$config['default_client'] = reset($keys); |
76
|
|
|
} |
77
|
|
|
|
78
|
21 |
|
if (empty($config['default_index'])) { |
79
|
21 |
|
$keys = array_keys($config['indexes']); |
80
|
21 |
|
$config['default_index'] = reset($keys); |
81
|
|
|
} |
82
|
|
|
|
83
|
21 |
|
if (isset($config['serializer'])) { |
84
|
1 |
|
$loader->load('serializer.xml'); |
85
|
|
|
|
86
|
1 |
|
$this->loadSerializer($config['serializer'], $container); |
87
|
|
|
} |
88
|
|
|
|
89
|
21 |
|
$this->loadClients($config['clients'], $container); |
90
|
21 |
|
$container->setAlias('fos_elastica.client', sprintf('fos_elastica.client.%s', $config['default_client'])); |
91
|
21 |
|
$container->getAlias('fos_elastica.client')->setPublic(true); |
92
|
21 |
|
$container->setAlias(ElasticaClient::class, new Alias('fos_elastica.client', false)); |
93
|
21 |
|
$container->setAlias(Client::class, 'fos_elastica.client'); |
94
|
21 |
|
$container->getAlias(Client::class)->setPublic(false); |
95
|
|
|
|
96
|
21 |
|
$this->loadIndexes($config['indexes'], $container); |
97
|
21 |
|
$container->setAlias('fos_elastica.index', sprintf('fos_elastica.index.%s', $config['default_index'])); |
98
|
21 |
|
$container->getAlias('fos_elastica.index')->setPublic(true); |
99
|
21 |
|
$container->setParameter('fos_elastica.default_index', $config['default_index']); |
100
|
|
|
|
101
|
21 |
|
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
|
21 |
|
$this->loadIndexTemplates($config['index_templates'], $container); |
110
|
|
|
|
111
|
21 |
|
$container->getDefinition('fos_elastica.config_source.container')->replaceArgument(0, $this->indexConfigs); |
112
|
|
|
$container |
113
|
21 |
|
->getDefinition('fos_elastica.config_source.template_container') |
114
|
21 |
|
->replaceArgument(0, $this->indexTemplateConfigs); |
115
|
|
|
|
116
|
21 |
|
$this->loadIndexManager($container); |
117
|
21 |
|
$this->loadIndexTemplateManager($container); |
118
|
|
|
|
119
|
21 |
|
$this->createDefaultManagerAlias($config['default_manager'], $container); |
120
|
21 |
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @param array $config |
124
|
|
|
* @param ContainerBuilder $container |
125
|
|
|
* |
126
|
|
|
* @return Configuration |
127
|
|
|
*/ |
128
|
21 |
|
public function getConfiguration(array $config, ContainerBuilder $container) |
129
|
|
|
{ |
130
|
21 |
|
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
|
21 |
|
private function loadClients(array $clients, ContainerBuilder $container) |
142
|
|
|
{ |
143
|
21 |
|
foreach ($clients as $name => $clientConfig) { |
144
|
21 |
|
$clientId = sprintf('fos_elastica.client.%s', $name); |
145
|
|
|
|
146
|
21 |
|
$clientDef = new ChildDefinition('fos_elastica.client_prototype'); |
147
|
21 |
|
$clientDef->replaceArgument(0, $clientConfig); |
148
|
|
|
|
149
|
21 |
|
$logger = $clientConfig['connections'][0]['logger']; |
150
|
21 |
|
if (false !== $logger) { |
151
|
21 |
|
$clientDef->addMethodCall('setLogger', [new Reference($logger)]); |
152
|
|
|
} |
153
|
|
|
|
154
|
21 |
|
$clientDef->addTag('fos_elastica.client'); |
155
|
|
|
|
156
|
21 |
|
$container->setDefinition($clientId, $clientDef); |
157
|
|
|
|
158
|
21 |
|
$this->clients[$name] = [ |
159
|
21 |
|
'id' => $clientId, |
160
|
21 |
|
'reference' => new Reference($clientId), |
161
|
|
|
]; |
162
|
|
|
} |
163
|
21 |
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Loads the configured indexes. |
167
|
|
|
* |
168
|
|
|
* @param array $indexes An array of indexes configurations |
169
|
|
|
* @param ContainerBuilder $container A ContainerBuilder instance |
170
|
|
|
* |
171
|
|
|
* @throws \InvalidArgumentException |
172
|
|
|
* |
173
|
|
|
* @return array |
174
|
|
|
*/ |
175
|
21 |
|
private function loadIndexes(array $indexes, ContainerBuilder $container) |
176
|
|
|
{ |
177
|
21 |
|
$indexableCallbacks = []; |
178
|
|
|
|
179
|
21 |
|
foreach ($indexes as $name => $index) { |
180
|
21 |
|
$indexId = sprintf('fos_elastica.index.%s', $name); |
181
|
21 |
|
$indexName = isset($index['index_name']) ? $index['index_name'] : $name; |
182
|
|
|
|
183
|
21 |
|
$indexDef = new ChildDefinition('fos_elastica.index_prototype'); |
184
|
21 |
|
$indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndex']); |
185
|
21 |
|
$indexDef->replaceArgument(0, $indexName); |
186
|
21 |
|
$indexDef->addTag('fos_elastica.index', [ |
187
|
21 |
|
'name' => $name, |
188
|
|
|
]); |
189
|
|
|
|
190
|
21 |
View Code Duplication |
if (isset($index['client'])) { |
191
|
2 |
|
$client = $this->getClient($index['client']); |
192
|
|
|
|
193
|
2 |
|
$indexDef->setFactory([$client, 'getIndex']); |
194
|
|
|
} |
195
|
|
|
|
196
|
21 |
|
$container->setDefinition($indexId, $indexDef); |
197
|
21 |
|
$reference = new Reference($indexId); |
198
|
|
|
|
199
|
21 |
|
$this->indexConfigs[$name] = [ |
200
|
21 |
|
'elasticsearch_name' => $indexName, |
201
|
21 |
|
'reference' => $reference, |
202
|
21 |
|
'name' => $name, |
203
|
21 |
|
'settings' => $index['settings'], |
204
|
21 |
|
'type_prototype' => isset($index['type_prototype']) ? $index['type_prototype'] : [], |
205
|
21 |
|
'use_alias' => $index['use_alias'], |
206
|
|
|
]; |
207
|
|
|
|
208
|
21 |
|
if ($index['finder']) { |
209
|
|
|
$this->loadIndexFinder($container, $name, $reference); |
210
|
|
|
} |
211
|
|
|
|
212
|
21 |
|
$this->loadTypes((array) $index['types'], $container, $this->indexConfigs[$name], $indexableCallbacks); |
213
|
|
|
} |
214
|
|
|
|
215
|
21 |
|
$indexable = $container->getDefinition('fos_elastica.indexable'); |
216
|
21 |
|
$indexable->replaceArgument(0, $indexableCallbacks); |
217
|
21 |
|
} |
218
|
|
|
|
219
|
|
|
/** |
220
|
|
|
* Loads the configured indexes. |
221
|
|
|
* |
222
|
|
|
* @param array $indexTemplates An array of indexes configurations |
223
|
|
|
* @param ContainerBuilder $container A ContainerBuilder instance |
224
|
|
|
* |
225
|
|
|
* @throws \InvalidArgumentException |
226
|
|
|
* |
227
|
|
|
* @return void |
228
|
|
|
*/ |
229
|
21 |
|
private function loadIndexTemplates(array $indexTemplates, ContainerBuilder $container) |
230
|
|
|
{ |
231
|
21 |
|
$indexableCallbacks = array(); |
232
|
21 |
|
foreach ($indexTemplates as $name => $indexTemplate) { |
233
|
6 |
|
$indexId = sprintf('fos_elastica.index_template.%s', $name); |
234
|
6 |
|
$indexTemplateName = isset($indexTemplate['template_name']) ? $indexTemplate['template_name'] : $name; |
235
|
|
|
|
236
|
6 |
|
$indexDef = new ChildDefinition('fos_elastica.index_template_prototype'); |
237
|
6 |
|
$indexDef->setFactory([new Reference('fos_elastica.client'), 'getIndexTemplate']); |
238
|
6 |
|
$indexDef->replaceArgument(0, $indexTemplateName); |
239
|
6 |
|
$indexDef->addTag('fos_elastica.index_template', array( |
240
|
6 |
|
'name' => $name, |
241
|
|
|
)); |
242
|
|
|
|
243
|
6 |
View Code Duplication |
if (isset($indexTemplate['client'])) { |
244
|
6 |
|
$client = $this->getClient($indexTemplate['client']); |
245
|
6 |
|
$indexDef->setFactory([$client, 'getIndexTemplate']); |
246
|
|
|
} |
247
|
|
|
|
248
|
6 |
|
$container->setDefinition($indexId, $indexDef); |
249
|
6 |
|
$reference = new Reference($indexId); |
250
|
|
|
|
251
|
6 |
|
$this->indexTemplateConfigs[$name] = array( |
252
|
6 |
|
'elasticsearch_name' => $indexTemplateName, |
253
|
6 |
|
'reference' => $reference, |
254
|
6 |
|
'name' => $name, |
255
|
6 |
|
'settings' => $indexTemplate['settings'], |
256
|
6 |
|
'template' => $indexTemplate['template'], |
257
|
|
|
); |
258
|
|
|
|
259
|
6 |
|
$this->loadTypes( |
260
|
6 |
|
(array) $indexTemplate['types'], |
261
|
|
|
$container, |
262
|
6 |
|
$this->indexTemplateConfigs[$name], |
263
|
|
|
$indexableCallbacks |
264
|
|
|
); |
265
|
|
|
} |
266
|
|
|
|
267
|
21 |
|
if ($indexableCallbacks) { |
|
|
|
|
268
|
|
|
throw new \RuntimeException('`indexable_callback` option is not supported by index templates'); |
269
|
|
|
} |
270
|
21 |
|
} |
271
|
|
|
|
272
|
|
|
/** |
273
|
|
|
* Loads the configured index finders. |
274
|
|
|
* |
275
|
|
|
* @param \Symfony\Component\DependencyInjection\ContainerBuilder $container |
276
|
|
|
* @param string $name The index name |
277
|
|
|
* @param Reference $index Reference to the related index |
278
|
|
|
* |
279
|
|
|
* @return string |
280
|
|
|
*/ |
281
|
|
|
private function loadIndexFinder(ContainerBuilder $container, $name, Reference $index) |
282
|
|
|
{ |
283
|
|
|
/* Note: transformer services may conflict with "collection.index", if |
284
|
|
|
* an index and type names were "collection" and an index, respectively. |
285
|
|
|
*/ |
286
|
|
|
$transformerId = sprintf('fos_elastica.elastica_to_model_transformer.collection.%s', $name); |
287
|
|
|
$transformerDef = new ChildDefinition('fos_elastica.elastica_to_model_transformer.collection'); |
288
|
|
|
$container->setDefinition($transformerId, $transformerDef); |
289
|
|
|
|
290
|
|
|
$finderId = sprintf('fos_elastica.finder.%s', $name); |
291
|
|
|
$finderDef = new ChildDefinition('fos_elastica.finder'); |
292
|
|
|
$finderDef->replaceArgument(0, $index); |
293
|
|
|
$finderDef->replaceArgument(1, new Reference($transformerId)); |
294
|
|
|
|
295
|
|
|
$container->setDefinition($finderId, $finderDef); |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* Loads the configured types. |
300
|
|
|
* |
301
|
|
|
* @param array $types |
302
|
|
|
* @param ContainerBuilder $container |
303
|
|
|
* @param array $indexConfig |
304
|
|
|
* @param array $indexableCallbacks |
305
|
|
|
*/ |
306
|
21 |
|
private function loadTypes(array $types, ContainerBuilder $container, array &$indexConfig, array &$indexableCallbacks) |
307
|
|
|
{ |
308
|
21 |
|
foreach ($types as $name => $type) { |
309
|
21 |
|
$indexName = $indexConfig['name']; |
310
|
|
|
|
311
|
21 |
|
$typeId = sprintf('%s.%s', $indexConfig['reference'], $name); |
312
|
21 |
|
$typeDef = new ChildDefinition('fos_elastica.type_prototype'); |
313
|
21 |
|
$typeDef->setFactory([$indexConfig['reference'], 'getType']); |
314
|
21 |
|
$typeDef->replaceArgument(0, $name); |
315
|
|
|
|
316
|
21 |
|
$container->setDefinition($typeId, $typeDef); |
317
|
|
|
|
318
|
|
|
$typeConfig = [ |
319
|
21 |
|
'name' => $name, |
320
|
|
|
'mapping' => [], // An array containing anything that gets sent directly to ElasticSearch |
321
|
|
|
'config' => [], |
322
|
|
|
]; |
323
|
|
|
|
324
|
|
|
foreach ([ |
325
|
21 |
|
'dynamic_templates', |
326
|
|
|
'properties', |
327
|
|
|
'_all', |
328
|
|
|
'_id', |
329
|
|
|
'_parent', |
330
|
|
|
'_routing', |
331
|
|
|
'_source', |
332
|
|
|
] as $field) { |
333
|
21 |
|
if (isset($type[$field])) { |
334
|
21 |
|
$typeConfig['mapping'][$field] = $type[$field]; |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
foreach ([ |
339
|
21 |
|
'persistence', |
340
|
|
|
'serializer', |
341
|
|
|
'analyzer', |
342
|
|
|
'search_analyzer', |
343
|
|
|
'dynamic', |
344
|
|
|
'date_detection', |
345
|
|
|
'dynamic_date_formats', |
346
|
|
|
'numeric_detection', |
347
|
|
|
] as $field) { |
348
|
21 |
|
$typeConfig['config'][$field] = array_key_exists($field, $type) ? |
349
|
21 |
|
$type[$field] : |
350
|
21 |
|
null; |
351
|
|
|
} |
352
|
|
|
|
353
|
21 |
|
$indexConfig['types'][$name] = $typeConfig; |
354
|
|
|
|
355
|
21 |
|
if (isset($type['persistence'])) { |
356
|
15 |
|
$this->loadTypePersistenceIntegration($type['persistence'], $container, new Reference($typeId), $indexName, $name); |
357
|
|
|
|
358
|
15 |
|
$typeConfig['persistence'] = $type['persistence']; |
359
|
|
|
} |
360
|
|
|
|
361
|
21 |
|
if (isset($type['_parent'])) { |
362
|
|
|
// _parent mapping cannot contain `property` and `identifier`, so removing them after building `persistence` |
363
|
6 |
|
unset($indexConfig['types'][$name]['mapping']['_parent']['property'], $indexConfig['types'][$name]['mapping']['_parent']['identifier']); |
364
|
|
|
} |
365
|
|
|
|
366
|
21 |
|
if (isset($type['indexable_callback'])) { |
367
|
4 |
|
$indexableCallbacks[sprintf('%s/%s', $indexName, $name)] = $this->buildCallback($type['indexable_callback'], $name); |
368
|
|
|
} |
369
|
|
|
|
370
|
21 |
|
if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { |
371
|
1 |
|
$typeSerializerId = sprintf('%s.serializer.callback', $typeId); |
372
|
1 |
|
$typeSerializerDef = new ChildDefinition('fos_elastica.serializer_callback_prototype'); |
373
|
|
|
|
374
|
1 |
|
if (isset($type['serializer']['groups'])) { |
375
|
1 |
|
$typeSerializerDef->addMethodCall('setGroups', [$type['serializer']['groups']]); |
376
|
|
|
} |
377
|
|
|
|
378
|
1 |
|
if (isset($type['serializer']['serialize_null'])) { |
379
|
1 |
|
$typeSerializerDef->addMethodCall('setSerializeNull', [$type['serializer']['serialize_null']]); |
380
|
|
|
} |
381
|
|
|
|
382
|
1 |
|
if (isset($type['serializer']['version'])) { |
383
|
1 |
|
$typeSerializerDef->addMethodCall('setVersion', [$type['serializer']['version']]); |
384
|
|
|
} |
385
|
|
|
|
386
|
1 |
|
$typeDef->addMethodCall('setSerializer', [[new Reference($typeSerializerId), 'serialize']]); |
387
|
21 |
|
$container->setDefinition($typeSerializerId, $typeSerializerDef); |
388
|
|
|
} |
389
|
|
|
} |
390
|
21 |
|
} |
391
|
|
|
|
392
|
4 |
|
private function buildCallback($indexCallback, $typeName) |
393
|
|
|
{ |
394
|
4 |
|
if (is_array($indexCallback)) { |
395
|
4 |
|
if (!isset($indexCallback[0])) { |
396
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName)); |
397
|
|
|
} |
398
|
|
|
|
399
|
4 |
|
$classOrServiceRef = $this->transformServiceReference($indexCallback[0]); |
400
|
4 |
|
if ($classOrServiceRef instanceof Reference && !isset($indexCallback[1])) { |
401
|
|
|
return $classOrServiceRef; // __invoke |
402
|
|
|
} |
403
|
|
|
|
404
|
4 |
|
if (!isset($indexCallback[1])) { |
405
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName)); |
406
|
|
|
} |
407
|
|
|
|
408
|
4 |
|
return [$classOrServiceRef, $indexCallback[1]]; |
409
|
|
|
} |
410
|
|
|
|
411
|
4 |
|
if (is_string($indexCallback)) { |
412
|
4 |
|
return $this->transformServiceReference($indexCallback); |
413
|
|
|
} |
414
|
|
|
|
415
|
|
|
throw new \InvalidArgumentException(sprintf('Invalid indexable_callback for type %s', $typeName)); |
416
|
|
|
} |
417
|
|
|
|
418
|
4 |
|
private function transformServiceReference($classOrService) |
419
|
|
|
{ |
420
|
4 |
|
return 0 === strpos($classOrService, '@') ? new Reference(substr($classOrService, 1)) : $classOrService; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
/** |
424
|
|
|
* Loads the optional provider and finder for a type. |
425
|
|
|
* |
426
|
|
|
* @param array $typeConfig |
427
|
|
|
* @param ContainerBuilder $container |
428
|
|
|
* @param Reference $typeRef |
429
|
|
|
* @param string $indexName |
430
|
|
|
* @param string $typeName |
431
|
|
|
*/ |
432
|
15 |
|
private function loadTypePersistenceIntegration(array $typeConfig, ContainerBuilder $container, Reference $typeRef, $indexName, $typeName) |
433
|
|
|
{ |
434
|
15 |
|
if (isset($typeConfig['driver'])) { |
435
|
15 |
|
$this->loadDriver($container, $typeConfig['driver']); |
436
|
|
|
} |
437
|
|
|
|
438
|
15 |
|
$elasticaToModelTransformerId = $this->loadElasticaToModelTransformer($typeConfig, $container, $indexName, $typeName); |
439
|
15 |
|
$modelToElasticaTransformerId = $this->loadModelToElasticaTransformer($typeConfig, $container, $indexName, $typeName); |
440
|
15 |
|
$objectPersisterId = $this->loadObjectPersister($typeConfig, $typeRef, $container, $indexName, $typeName, $modelToElasticaTransformerId); |
441
|
|
|
|
442
|
15 |
|
if (isset($typeConfig['provider'])) { |
443
|
15 |
|
$this->loadTypePagerProvider($typeConfig, $container, $indexName, $typeName); |
444
|
|
|
} |
445
|
15 |
|
if (isset($typeConfig['finder'])) { |
446
|
15 |
|
$this->loadTypeFinder($typeConfig, $container, $elasticaToModelTransformerId, $typeRef, $indexName, $typeName); |
447
|
|
|
} |
448
|
15 |
|
if (isset($typeConfig['listener']) && $typeConfig['listener']['enabled']) { |
449
|
14 |
|
$this->loadTypeListener($typeConfig, $container, $objectPersisterId, $indexName, $typeName); |
450
|
|
|
} |
451
|
15 |
|
} |
452
|
|
|
|
453
|
|
|
/** |
454
|
|
|
* Creates and loads an ElasticaToModelTransformer. |
455
|
|
|
* |
456
|
|
|
* @param array $typeConfig |
457
|
|
|
* @param ContainerBuilder $container |
458
|
|
|
* @param string $indexName |
459
|
|
|
* @param string $typeName |
460
|
|
|
* |
461
|
|
|
* @return string |
462
|
|
|
*/ |
463
|
15 |
|
private function loadElasticaToModelTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) |
464
|
|
|
{ |
465
|
15 |
|
if (isset($typeConfig['elastica_to_model_transformer']['service'])) { |
466
|
1 |
|
return $typeConfig['elastica_to_model_transformer']['service']; |
467
|
|
|
} |
468
|
|
|
|
469
|
|
|
/* Note: transformer services may conflict with "prototype.driver", if |
470
|
|
|
* the index and type names were "prototype" and a driver, respectively. |
471
|
|
|
*/ |
472
|
14 |
|
$abstractId = sprintf('fos_elastica.elastica_to_model_transformer.prototype.%s', $typeConfig['driver']); |
473
|
14 |
|
$serviceId = sprintf('fos_elastica.elastica_to_model_transformer.%s.%s', $indexName, $typeName); |
474
|
14 |
|
$serviceDef = new ChildDefinition($abstractId); |
475
|
14 |
|
$serviceDef->addTag('fos_elastica.elastica_to_model_transformer', ['type' => $typeName, 'index' => $indexName]); |
476
|
|
|
|
477
|
14 |
|
$serviceDef->replaceArgument(1, $typeConfig['model']); |
478
|
14 |
|
$serviceDef->replaceArgument(2, array_merge($typeConfig['elastica_to_model_transformer'], [ |
479
|
14 |
|
'identifier' => $typeConfig['identifier'], |
480
|
|
|
])); |
481
|
14 |
|
$container->setDefinition($serviceId, $serviceDef); |
482
|
|
|
|
483
|
14 |
|
return $serviceId; |
484
|
|
|
} |
485
|
|
|
|
486
|
|
|
/** |
487
|
|
|
* Creates and loads a ModelToElasticaTransformer for an index/type. |
488
|
|
|
* |
489
|
|
|
* @param array $typeConfig |
490
|
|
|
* @param ContainerBuilder $container |
491
|
|
|
* @param string $indexName |
492
|
|
|
* @param string $typeName |
493
|
|
|
* |
494
|
|
|
* @return string |
495
|
|
|
*/ |
496
|
15 |
|
private function loadModelToElasticaTransformer(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) |
497
|
|
|
{ |
498
|
15 |
|
if (isset($typeConfig['model_to_elastica_transformer']['service'])) { |
499
|
|
|
return $typeConfig['model_to_elastica_transformer']['service']; |
500
|
|
|
} |
501
|
|
|
|
502
|
15 |
|
$abstractId = $container->hasDefinition('fos_elastica.serializer_callback_prototype') ? |
503
|
1 |
|
'fos_elastica.model_to_elastica_identifier_transformer' : |
504
|
15 |
|
'fos_elastica.model_to_elastica_transformer'; |
505
|
|
|
|
506
|
15 |
|
$serviceId = sprintf('fos_elastica.model_to_elastica_transformer.%s.%s', $indexName, $typeName); |
507
|
15 |
|
$serviceDef = new ChildDefinition($abstractId); |
508
|
15 |
|
$serviceDef->replaceArgument(0, [ |
509
|
15 |
|
'identifier' => $typeConfig['identifier'], |
510
|
15 |
|
'index' => $indexName, |
511
|
|
|
]); |
512
|
15 |
|
$container->setDefinition($serviceId, $serviceDef); |
513
|
|
|
|
514
|
15 |
|
return $serviceId; |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Creates and loads an object persister for a type. |
519
|
|
|
* |
520
|
|
|
* @param array $typeConfig |
521
|
|
|
* @param Reference $typeRef |
522
|
|
|
* @param ContainerBuilder $container |
523
|
|
|
* @param string $indexName |
524
|
|
|
* @param string $typeName |
525
|
|
|
* @param string $transformerId |
526
|
|
|
* |
527
|
|
|
* @return string |
528
|
|
|
*/ |
529
|
15 |
|
private function loadObjectPersister(array $typeConfig, Reference $typeRef, ContainerBuilder $container, $indexName, $typeName, $transformerId) |
530
|
|
|
{ |
531
|
15 |
|
if (isset($typeConfig['persister']['service'])) { |
532
|
1 |
|
return $typeConfig['persister']['service']; |
533
|
|
|
} |
534
|
|
|
|
535
|
|
|
$arguments = [ |
536
|
14 |
|
$typeRef, |
537
|
14 |
|
new Reference($transformerId), |
538
|
14 |
|
$typeConfig['model'], |
539
|
|
|
]; |
540
|
|
|
|
541
|
14 |
|
if ($container->hasDefinition('fos_elastica.serializer_callback_prototype')) { |
542
|
1 |
|
$abstractId = 'fos_elastica.object_serializer_persister'; |
543
|
1 |
|
$callbackId = sprintf('%s.%s.serializer.callback', $this->indexConfigs[$indexName]['reference'], $typeName); |
544
|
1 |
|
$arguments[] = [new Reference($callbackId), 'serialize']; |
545
|
|
|
} else { |
546
|
13 |
|
$abstractId = 'fos_elastica.object_persister'; |
547
|
13 |
|
$mapping = $this->indexConfigs[$indexName]['types'][$typeName]['mapping']; |
548
|
13 |
|
$argument = $mapping['properties']; |
549
|
13 |
|
if (isset($mapping['_parent'])) { |
550
|
1 |
|
$argument['_parent'] = $mapping['_parent']; |
551
|
|
|
} |
552
|
13 |
|
$arguments[] = $argument; |
553
|
|
|
} |
554
|
|
|
|
555
|
14 |
|
$arguments[] = array_intersect_key($typeConfig['persister'], array_flip(['refresh'])); |
556
|
|
|
|
557
|
14 |
|
$serviceId = sprintf('fos_elastica.object_persister.%s.%s', $indexName, $typeName); |
558
|
14 |
|
$serviceDef = new ChildDefinition($abstractId); |
559
|
14 |
|
foreach ($arguments as $i => $argument) { |
560
|
14 |
|
$serviceDef->replaceArgument($i, $argument); |
561
|
|
|
} |
562
|
|
|
|
563
|
14 |
|
$serviceDef->addTag('fos_elastica.persister', ['index' => $indexName, 'type' => $typeName]); |
564
|
|
|
|
565
|
14 |
|
$container->setDefinition($serviceId, $serviceDef); |
566
|
|
|
|
567
|
14 |
|
return $serviceId; |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* Loads a pager provider for a type. |
572
|
|
|
* |
573
|
|
|
* @param array $typeConfig |
574
|
|
|
* @param ContainerBuilder $container |
575
|
|
|
* @param string $indexName |
576
|
|
|
* @param string $typeName |
577
|
|
|
* |
578
|
|
|
* @return string |
579
|
|
|
*/ |
580
|
15 |
|
private function loadTypePagerProvider(array $typeConfig, ContainerBuilder $container, $indexName, $typeName) |
581
|
|
|
{ |
582
|
15 |
|
if (isset($typeConfig['provider']['service'])) { |
583
|
|
|
return $typeConfig['provider']['service']; |
584
|
|
|
} |
585
|
|
|
|
586
|
15 |
|
$baseConfig = $typeConfig['provider']; |
587
|
15 |
|
unset($baseConfig['service']); |
588
|
|
|
|
589
|
15 |
|
$driver = $typeConfig['driver']; |
590
|
|
|
|
591
|
15 |
|
switch ($driver) { |
592
|
15 |
|
case 'orm': |
593
|
14 |
|
$providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
594
|
14 |
|
$providerDef->replaceArgument(2, $typeConfig['model']); |
595
|
14 |
|
$providerDef->replaceArgument(3, $baseConfig); |
596
|
|
|
|
597
|
14 |
|
break; |
598
|
1 |
View Code Duplication |
case 'mongodb': |
599
|
|
|
$providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
600
|
|
|
$providerDef->replaceArgument(2, $typeConfig['model']); |
601
|
|
|
$providerDef->replaceArgument(3, $baseConfig); |
602
|
|
|
|
603
|
|
|
break; |
604
|
1 |
View Code Duplication |
case 'phpcr': |
605
|
1 |
|
$providerDef = new ChildDefinition('fos_elastica.pager_provider.prototype.'.$driver); |
606
|
1 |
|
$providerDef->replaceArgument(2, $typeConfig['model']); |
607
|
1 |
|
$providerDef->replaceArgument(3, $baseConfig); |
608
|
|
|
|
609
|
1 |
|
break; |
610
|
|
|
default: |
611
|
|
|
throw new \LogicException(sprintf('The pager provider for driver "%s" does not exist.', $driver)); |
612
|
|
|
} |
613
|
|
|
|
614
|
|
|
/* Note: provider services may conflict with "prototype.driver", if the |
615
|
|
|
* index and type names were "prototype" and a driver, respectively. |
616
|
|
|
*/ |
617
|
15 |
|
$providerId = sprintf('fos_elastica.pager_provider.%s.%s', $indexName, $typeName); |
618
|
15 |
|
$providerDef->addTag('fos_elastica.pager_provider', ['index' => $indexName, 'type' => $typeName]); |
619
|
|
|
|
620
|
15 |
|
$container->setDefinition($providerId, $providerDef); |
621
|
|
|
|
622
|
15 |
|
return $providerId; |
623
|
|
|
} |
624
|
|
|
|
625
|
|
|
/** |
626
|
|
|
* Loads doctrine listeners to handle indexing of new or updated objects. |
627
|
|
|
* |
628
|
|
|
* @param array $typeConfig |
629
|
|
|
* @param ContainerBuilder $container |
630
|
|
|
* @param string $objectPersisterId |
631
|
|
|
* @param string $indexName |
632
|
|
|
* @param string $typeName |
633
|
|
|
* |
634
|
|
|
* @return string |
635
|
|
|
*/ |
636
|
14 |
|
private function loadTypeListener(array $typeConfig, ContainerBuilder $container, $objectPersisterId, $indexName, $typeName) |
637
|
|
|
{ |
638
|
14 |
|
if (isset($typeConfig['listener']['service'])) { |
639
|
|
|
return $typeConfig['listener']['service']; |
640
|
|
|
} |
641
|
|
|
|
642
|
|
|
/* Note: listener services may conflict with "prototype.driver", if the |
643
|
|
|
* index and type names were "prototype" and a driver, respectively. |
644
|
|
|
*/ |
645
|
14 |
|
$abstractListenerId = sprintf('fos_elastica.listener.prototype.%s', $typeConfig['driver']); |
646
|
14 |
|
$listenerId = sprintf('fos_elastica.listener.%s.%s', $indexName, $typeName); |
647
|
14 |
|
$listenerDef = new ChildDefinition($abstractListenerId); |
648
|
14 |
|
$listenerDef->replaceArgument(0, new Reference($objectPersisterId)); |
649
|
14 |
|
$listenerDef->replaceArgument(3, $typeConfig['listener']['logger'] ? |
650
|
|
|
new Reference($typeConfig['listener']['logger']) : |
651
|
14 |
|
null |
652
|
|
|
); |
653
|
|
|
$listenerConfig = [ |
654
|
14 |
|
'identifier' => $typeConfig['identifier'], |
655
|
14 |
|
'indexName' => $indexName, |
656
|
14 |
|
'typeName' => $typeName, |
657
|
|
|
]; |
658
|
|
|
|
659
|
14 |
|
$tagName = null; |
660
|
14 |
|
switch ($typeConfig['driver']) { |
661
|
14 |
|
case 'orm': |
662
|
13 |
|
$tagName = 'doctrine.event_listener'; |
663
|
13 |
|
break; |
664
|
1 |
|
case 'phpcr': |
665
|
1 |
|
$tagName = 'doctrine_phpcr.event_listener'; |
666
|
1 |
|
break; |
667
|
|
|
case 'mongodb': |
668
|
|
|
$tagName = 'doctrine_mongodb.odm.event_listener'; |
669
|
|
|
break; |
670
|
|
|
} |
671
|
|
|
|
672
|
14 |
|
if ($typeConfig['listener']['defer']) { |
673
|
|
|
$listenerDef->setPublic(true); |
674
|
|
|
$listenerDef->addTag( |
675
|
|
|
'kernel.event_listener', |
676
|
|
|
['event' => 'kernel.terminate', 'method' => 'onTerminate'] |
677
|
|
|
); |
678
|
|
|
$listenerDef->addTag( |
679
|
|
|
'kernel.event_listener', |
680
|
|
|
['event' => 'console.terminate', 'method' => 'onTerminate'] |
681
|
|
|
); |
682
|
|
|
$listenerConfig['defer'] = true; |
683
|
|
|
} |
684
|
|
|
|
685
|
14 |
|
$listenerDef->replaceArgument(2, $listenerConfig); |
686
|
|
|
|
687
|
14 |
|
if (null !== $tagName) { |
688
|
14 |
|
foreach ($this->getDoctrineEvents($typeConfig) as $event) { |
689
|
14 |
|
$listenerDef->addTag($tagName, ['event' => $event]); |
690
|
|
|
} |
691
|
|
|
} |
692
|
|
|
|
693
|
14 |
|
$container->setDefinition($listenerId, $listenerDef); |
694
|
|
|
|
695
|
14 |
|
return $listenerId; |
696
|
|
|
} |
697
|
|
|
|
698
|
|
|
/** |
699
|
|
|
* Map Elastica to Doctrine events for the current driver. |
700
|
|
|
*/ |
701
|
14 |
|
private function getDoctrineEvents(array $typeConfig) |
702
|
|
|
{ |
703
|
14 |
|
switch ($typeConfig['driver']) { |
704
|
14 |
|
case 'orm': |
705
|
13 |
|
$eventsClass = '\Doctrine\ORM\Events'; |
706
|
13 |
|
break; |
707
|
1 |
|
case 'phpcr': |
708
|
1 |
|
$eventsClass = '\Doctrine\ODM\PHPCR\Event'; |
709
|
1 |
|
break; |
710
|
|
|
case 'mongodb': |
711
|
|
|
$eventsClass = '\Doctrine\ODM\MongoDB\Events'; |
712
|
|
|
break; |
713
|
|
|
default: |
714
|
|
|
throw new \InvalidArgumentException(sprintf('Cannot determine events for driver "%s"', $typeConfig['driver'])); |
715
|
|
|
} |
716
|
|
|
|
717
|
14 |
|
$events = []; |
718
|
|
|
$eventMapping = [ |
719
|
14 |
|
'insert' => [constant($eventsClass.'::postPersist')], |
720
|
14 |
|
'update' => [constant($eventsClass.'::postUpdate')], |
721
|
14 |
|
'delete' => [constant($eventsClass.'::preRemove')], |
722
|
14 |
|
'flush' => [constant($eventsClass.'::postFlush')], |
723
|
|
|
]; |
724
|
|
|
|
725
|
14 |
|
foreach ($eventMapping as $event => $doctrineEvents) { |
726
|
14 |
|
if (isset($typeConfig['listener'][$event]) && $typeConfig['listener'][$event]) { |
727
|
14 |
|
$events = array_merge($events, $doctrineEvents); |
728
|
|
|
} |
729
|
|
|
} |
730
|
|
|
|
731
|
14 |
|
return $events; |
732
|
|
|
} |
733
|
|
|
|
734
|
|
|
/** |
735
|
|
|
* Loads a Type specific Finder. |
736
|
|
|
* |
737
|
|
|
* @param array $typeConfig |
738
|
|
|
* @param ContainerBuilder $container |
739
|
|
|
* @param string $elasticaToModelId |
740
|
|
|
* @param Reference $typeRef |
741
|
|
|
* @param string $indexName |
742
|
|
|
* @param string $typeName |
743
|
|
|
* |
744
|
|
|
* @return string |
745
|
|
|
*/ |
746
|
15 |
|
private function loadTypeFinder(array $typeConfig, ContainerBuilder $container, $elasticaToModelId, Reference $typeRef, $indexName, $typeName) |
747
|
|
|
{ |
748
|
15 |
|
if (isset($typeConfig['finder']['service'])) { |
749
|
|
|
$finderId = $typeConfig['finder']['service']; |
750
|
|
|
} else { |
751
|
15 |
|
$finderId = sprintf('fos_elastica.finder.%s.%s', $indexName, $typeName); |
752
|
15 |
|
$finderDef = new ChildDefinition('fos_elastica.finder'); |
753
|
15 |
|
$finderDef->replaceArgument(0, $typeRef); |
754
|
15 |
|
$finderDef->replaceArgument(1, new Reference($elasticaToModelId)); |
755
|
15 |
|
$container->setDefinition($finderId, $finderDef); |
756
|
|
|
} |
757
|
|
|
|
758
|
15 |
|
$indexTypeName = "$indexName/$typeName"; |
759
|
15 |
|
$arguments = [$indexTypeName, new Reference($finderId)]; |
760
|
15 |
|
if (isset($typeConfig['repository'])) { |
761
|
4 |
|
$arguments[] = $typeConfig['repository']; |
762
|
|
|
} |
763
|
|
|
|
764
|
15 |
|
$container->getDefinition('fos_elastica.repository_manager') |
765
|
15 |
|
->addMethodCall('addType', $arguments); |
766
|
|
|
|
767
|
15 |
|
$managerId = sprintf('fos_elastica.manager.%s', $typeConfig['driver']); |
768
|
15 |
|
$container->getDefinition($managerId) |
769
|
15 |
|
->addMethodCall('addEntity', [$typeConfig['model'], $indexTypeName]); |
770
|
|
|
|
771
|
15 |
|
return $finderId; |
772
|
|
|
} |
773
|
|
|
|
774
|
|
|
/** |
775
|
|
|
* Loads the index manager. |
776
|
|
|
* |
777
|
|
|
* @param ContainerBuilder $container |
778
|
|
|
**/ |
779
|
|
View Code Duplication |
private function loadIndexManager(ContainerBuilder $container) |
780
|
|
|
{ |
781
|
21 |
|
$indexRefs = array_map(function ($index) { |
782
|
21 |
|
return $index['reference']; |
783
|
21 |
|
}, $this->indexConfigs); |
784
|
|
|
|
785
|
21 |
|
$managerDef = $container->getDefinition('fos_elastica.index_manager'); |
786
|
21 |
|
$managerDef->replaceArgument(0, $indexRefs); |
787
|
21 |
|
} |
788
|
|
|
|
789
|
|
|
/** |
790
|
|
|
* Load index template manager |
791
|
|
|
* |
792
|
|
|
* @param ContainerBuilder $container |
793
|
|
|
* |
794
|
|
|
* @return void |
795
|
|
|
*/ |
796
|
|
View Code Duplication |
private function loadIndexTemplateManager(ContainerBuilder $container) |
797
|
|
|
{ |
798
|
21 |
|
$indexTemplateRefs = array_map(function ($index) { |
799
|
6 |
|
return $index['reference']; |
800
|
21 |
|
}, $this->indexTemplateConfigs); |
801
|
|
|
|
802
|
21 |
|
$managerDef = $container->getDefinition('fos_elastica.index_template_manager'); |
803
|
21 |
|
$managerDef->replaceArgument(0, $indexTemplateRefs); |
804
|
21 |
|
} |
805
|
|
|
|
806
|
|
|
/** |
807
|
|
|
* Makes sure a specific driver has been loaded. |
808
|
|
|
* |
809
|
|
|
* @param ContainerBuilder $container |
810
|
|
|
* @param string $driver |
811
|
|
|
*/ |
812
|
15 |
|
private function loadDriver(ContainerBuilder $container, $driver) |
813
|
|
|
{ |
814
|
15 |
|
if (in_array($driver, $this->loadedDrivers)) { |
815
|
6 |
|
return; |
816
|
|
|
} |
817
|
|
|
|
818
|
15 |
|
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); |
819
|
15 |
|
$loader->load($driver.'.xml'); |
820
|
15 |
|
$this->loadedDrivers[] = $driver; |
821
|
15 |
|
} |
822
|
|
|
|
823
|
|
|
/** |
824
|
|
|
* Loads and configures the serializer prototype. |
825
|
|
|
* |
826
|
|
|
* @param array $config |
827
|
|
|
* @param ContainerBuilder $container |
828
|
|
|
*/ |
829
|
1 |
|
private function loadSerializer($config, ContainerBuilder $container) |
830
|
|
|
{ |
831
|
1 |
|
$container->setAlias('fos_elastica.serializer', $config['serializer']); |
832
|
|
|
|
833
|
1 |
|
$serializer = $container->getDefinition('fos_elastica.serializer_callback_prototype'); |
834
|
1 |
|
$serializer->setClass($config['callback_class']); |
835
|
|
|
|
836
|
1 |
|
if (is_subclass_of($config['callback_class'], ContainerAwareInterface::class)) { |
|
|
|
|
837
|
|
|
$serializer->addMethodCall('setContainer', [new Reference('service_container')]); |
838
|
|
|
} |
839
|
1 |
|
} |
840
|
|
|
|
841
|
|
|
/** |
842
|
|
|
* Creates a default manager alias for defined default manager or the first loaded driver. |
843
|
|
|
* |
844
|
|
|
* @param string $defaultManager |
845
|
|
|
* @param ContainerBuilder $container |
846
|
|
|
*/ |
847
|
21 |
|
private function createDefaultManagerAlias($defaultManager, ContainerBuilder $container) |
848
|
|
|
{ |
849
|
21 |
|
if (0 == count($this->loadedDrivers)) { |
850
|
6 |
|
return; |
851
|
|
|
} |
852
|
|
|
|
853
|
15 |
|
if (count($this->loadedDrivers) > 1 |
854
|
15 |
|
&& in_array($defaultManager, $this->loadedDrivers) |
855
|
|
|
) { |
856
|
|
|
$defaultManagerService = $defaultManager; |
857
|
|
|
} else { |
858
|
15 |
|
$defaultManagerService = $this->loadedDrivers[0]; |
859
|
|
|
} |
860
|
|
|
|
861
|
15 |
|
$container->setAlias('fos_elastica.manager', sprintf('fos_elastica.manager.%s', $defaultManagerService)); |
862
|
15 |
|
$container->getAlias('fos_elastica.manager')->setPublic(true); |
863
|
15 |
|
$container->setAlias(RepositoryManagerInterface::class, 'fos_elastica.manager'); |
864
|
15 |
|
$container->getAlias(RepositoryManagerInterface::class)->setPublic(false); |
865
|
15 |
|
} |
866
|
|
|
|
867
|
|
|
/** |
868
|
|
|
* Returns a reference to a client given its configured name. |
869
|
|
|
* |
870
|
|
|
* @param string $clientName |
871
|
|
|
* |
872
|
|
|
* @return Reference |
873
|
|
|
* |
874
|
|
|
* @throws \InvalidArgumentException |
875
|
|
|
*/ |
876
|
8 |
|
private function getClient($clientName) |
877
|
|
|
{ |
878
|
8 |
|
if (!array_key_exists($clientName, $this->clients)) { |
879
|
|
|
throw new \InvalidArgumentException(sprintf('The elastica client with name "%s" is not defined', $clientName)); |
880
|
|
|
} |
881
|
|
|
|
882
|
8 |
|
return $this->clients[$clientName]['reference']; |
883
|
|
|
} |
884
|
|
|
} |
885
|
|
|
|
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.