Completed
Push — master ( e0700f...6825fb )
by Markus
03:47
created

MathielenImportEngineExtension::load()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 11
ccs 8
cts 8
cp 1
rs 9.4286
cc 2
eloc 6
nc 2
nop 2
crap 2
1
<?php
2
namespace Mathielen\ImportEngineBundle\DependencyInjection;
3
4
use Mathielen\ImportEngine\Exception\InvalidConfigurationException;
5
use Symfony\Component\DependencyInjection\ContainerBuilder;
6
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
7
use Symfony\Component\DependencyInjection\Extension\Extension;
8
use Symfony\Component\Config\FileLocator;
9
use Symfony\Component\DependencyInjection\Reference;
10
use Symfony\Component\DependencyInjection\Definition;
11
use Symfony\Component\ExpressionLanguage\Expression;
12
13
class MathielenImportEngineExtension extends Extension
14
{
15
16 11
    public function load(array $configs, ContainerBuilder $container)
17
    {
18 11
        $config = $this->processConfiguration(new Configuration(), $configs);
19
20 11
        if (!empty($config['importers'])) {
21 9
            $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
22 9
            $loader->load('services.xml');
23
24 9
            $this->parseConfig($config, $container);
25 9
        }
26 11
    }
27
28 9
    private function parseConfig(array $config, ContainerBuilder $container)
29
    {
30 9
        $storageLocatorDef = $container->findDefinition('mathielen_importengine.import.storagelocator');
31 9
        foreach ($config['storageprovider'] as $name => $sourceConfig) {
32 5
            $this->addStorageProviderDef($storageLocatorDef, $sourceConfig, $name);
33 9
        }
34
35 9
        $importerRepositoryDef = $container->findDefinition('mathielen_importengine.importer.repository');
36 9
        foreach ($config['importers'] as $name => $importConfig) {
37 9
            $finderDef = null;
38 9
            if (isset($importConfig['preconditions'])) {
39 5
                $finderDef = $this->generateFinderDef($importConfig['preconditions']);
40 5
            }
41
42 9
            $objectFactoryDef = null;
43 9
            if (isset($importConfig['object_factory'])) {
44 5
                $objectFactoryDef = $this->generateObjectFactoryDef($importConfig['object_factory']);
45 5
            }
46
47 9
            $importerRepositoryDef->addMethodCall('register', array(
48 9
                $name,
49 9
                $this->generateImporterDef($importConfig, $objectFactoryDef),
50
                $finderDef
51 9
            ));
52 9
        }
53 9
    }
54
55 5
    private function generateObjectFactoryDef(array $config)
56
    {
57 5
        if ($config['type'] == 'jms_serializer') {
58 5
            return new Definition('Mathielen\DataImport\Writer\ObjectWriter\JmsSerializerObjectFactory', array(
59 5
                $config['class'],
60 5
                new Reference('jms_serializer')));
61
        }
62
63 5
        return new Definition('Mathielen\DataImport\Writer\ObjectWriter\DefaultObjectFactory', array($config['class']));
64
    }
65
66
    /**
67
     * @return \Symfony\Component\DependencyInjection\Definition
68
     */
69 5
    private function generateFinderDef(array $finderConfig)
70
    {
71 5
        $finderDef = new Definition('Mathielen\ImportEngine\Importer\ImporterPrecondition');
72
73 5
        if (isset($finderConfig['filename'])) {
74 5
            foreach ($finderConfig['filename'] as $conf) {
75 5
                $finderDef->addMethodCall('filename', array($conf));
76 5
            }
77 5
        }
78
79 5 View Code Duplication
        if (isset($finderConfig['format'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
80 5
            foreach ($finderConfig['format'] as $conf) {
81 5
                $finderDef->addMethodCall('format', array($conf));
82 5
            }
83 5
        }
84
85 5
        if (isset($finderConfig['fieldcount'])) {
86 5
            $finderDef->addMethodCall('fieldcount', array($finderConfig['fieldcount']));
87 5
        }
88
89 5 View Code Duplication
        if (isset($finderConfig['fields'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
90 5
            foreach ($finderConfig['fields'] as $conf) {
91 5
                $finderDef->addMethodCall('field', array($conf));
92 5
            }
93 5
        }
94
95 5
        if (isset($finderConfig['fieldset'])) {
96 5
            $finderDef->addMethodCall('fieldset', array($finderConfig['fieldset']));
97 5
        }
98
99 5
        return $finderDef;
100
    }
101
102
    /**
103
     * @return \Symfony\Component\DependencyInjection\Definition
104
     */
105 9
    private function generateImporterDef(array $importConfig, Definition $objectFactoryDef=null)
106
    {
107 9
        $importerDef = new Definition('Mathielen\ImportEngine\Importer\Importer', array(
108 9
            $this->getStorageDef($importConfig['target'], $objectFactoryDef)
109 9
        ));
110
111 9
        if (isset($importConfig['source'])) {
112 5
            $this->setSourceStorageDef($importConfig['source'], $importerDef);
113 5
        }
114
115
        //enable validation?
116 9
        if (isset($importConfig['validation']) && !empty($importConfig['validation'])) {
117 7
            $this->generateValidationDef($importConfig['validation'], $importerDef, $objectFactoryDef);
118 7
        }
119
120
        //add converters?
121 9
        if (isset($importConfig['mappings']) && !empty($importConfig['mappings'])) {
122 5
            $this->generateTransformerDef($importConfig['mappings'], $importerDef);
123 5
        }
124
125
        //add filters?
126 9
        if (isset($importConfig['filters']) && !empty($importConfig['filters'])) {
127
            $this->generateFiltersDef($importConfig['filters'], $importerDef);
128
        }
129
130
        //has static context?
131 9
        if (isset($importConfig['context'])) {
132 9
            $importerDef->addMethodCall('setContext', array(
133 9
                $importConfig['context']
134 9
            ));
135 9
        }
136
137 9
        return $importerDef;
138
    }
139
140
    private function generateFiltersDef(array $filtersOptions, Definition $importerDef)
141
    {
142
        $filtersDef = new Definition('Mathielen\ImportEngine\Filter\Filters');
143
144
        foreach ($filtersOptions as $filtersOption) {
145
            $filtersDef->addMethodCall('add', array(
146
                new Reference($filtersOption)
147
            ));
148
        }
149
150
        $importerDef->addMethodCall('filters', array(
151
            $filtersDef
152
        ));
153
    }
154
155 5
    private function generateTransformerDef(array $mappingOptions, Definition $importerDef)
156
    {
157 5
        $mappingsDef = new Definition('Mathielen\ImportEngine\Mapping\Mappings');
158
159
        //set converters
160 5
        foreach ($mappingOptions as $field=>$fieldMapping) {
161 5
            $converter = null;
162 5
            if (isset($fieldMapping['converter'])) {
163 5
                $converter = $fieldMapping['converter'];
164 5
            }
165
166 5
            if (isset($fieldMapping['to'])) {
167 5
                $mappingsDef->addMethodCall('add', array(
168 5
                    $field,
169 5
                    $fieldMapping['to'],
170
                    $converter
171 5
            ));
172 5
            } elseif ($converter) {
173 5
                $mappingsDef->addMethodCall('setConverter', array(
174 5
                    $converter,
175
                    $field
176 5
                ));
177 5
            }
178 5
        }
179
180 5
        $mappingFactoryDef = new Definition('Mathielen\ImportEngine\Mapping\DefaultMappingFactory', array(
181
            $mappingsDef
182 5
        ));
183 5
        $converterProviderDef = new Definition('Mathielen\ImportEngine\Mapping\Converter\Provider\ContainerAwareConverterProvider', array(
184 5
            new Reference('service_container')
185 5
        ));
186
187 5
        $transformerDef = new Definition('Mathielen\ImportEngine\Transformation\Transformation');
188 5
        $transformerDef->addMethodCall('setMappingFactory', array(
189
            $mappingFactoryDef
190 5
        ));
191 5
        $transformerDef->addMethodCall('setConverterProvider', array(
192
            $converterProviderDef
193 5
        ));
194
195 5
        $importerDef->addMethodCall('transformation', array(
196
            $transformerDef
197 5
        ));
198 5
    }
199
200 7
    private function generateValidatorDef(array $options)
201
    {
202
        //eventdispatcher aware source validatorfilter
203 7
        $validatorFilterDef = new Definition('Mathielen\DataImport\Filter\ValidatorFilter', array(
204 7
            new Reference('validator'),
205 7
            $options,
206 7
            new Reference('event_dispatcher')
207 7
        ));
208
209 7
        return $validatorFilterDef;
210
    }
211
212 7
    private function generateValidationDef(array $validationConfig, Definition $importerDef, Definition $objectFactoryDef=null)
213
    {
214 7
        $validationDef = new Definition('Mathielen\ImportEngine\Validation\ValidatorValidation', array(
215 7
            new Reference('validator')
216 7
        ));
217 7
        $importerDef->addMethodCall('validation', array(
218
            $validationDef
219 7
        ));
220
221 7
        $validatorFilterDef = $this->generateValidatorDef(
222 7
            isset($validationConfig['options'])?$validationConfig['options']:array()
223 7
        );
224
225 7
        if (isset($validationConfig['source'])) {
226 3
            $validationDef->addMethodCall('setSourceValidatorFilter', array(
227
                $validatorFilterDef
228 3
            ));
229
230 3
            foreach ($validationConfig['source']['constraints'] as $field=>$constraint) {
231 3
                $validationDef->addMethodCall('addSourceConstraint', array(
232 3
                    $field,
233 3
                    new Definition($constraint)
234 3
                ));
235 3
            }
236 3
        }
237
238
        //automatically apply class validation
239 7
        if (isset($validationConfig['target'])) {
240
241
            //using objects as result
242 7
            if ($objectFactoryDef) {
243
244
                //set eventdispatcher aware target CLASS-validatorfilter
245 5
                $validatorFilterDef = new Definition('Mathielen\DataImport\Filter\ClassValidatorFilter', array(
246 5
                    new Reference('validator'),
247 5
                    $objectFactoryDef,
248 5
                    new Reference('event_dispatcher')
249 5
                ));
250
251 5
            } else {
252 3
                foreach ($validationConfig['target']['constraints'] as $field=>$constraint) {
253 3
                    $validationDef->addMethodCall('addTargetConstraint', array(
254 3
                        $field,
255 3
                        new Definition($constraint)
256 3
                    ));
257 3
                }
258
            }
259
260 7
            $validationDef->addMethodCall('setTargetValidatorFilter', array(
261
                $validatorFilterDef
262 7
            ));
263 7
        }
264
265 7
        return $validationDef;
266
    }
267
268 5
    private function setSourceStorageDef(array $sourceConfig, Definition $importerDef)
269
    {
270 5
        $sDef = $this->getStorageDef($sourceConfig, $importerDef);
271 5
        $importerDef->addMethodCall('setSourceStorage', array(
272
            $sDef
273 5
        ));
274 5
    }
275
276 5
    private function addStorageProviderDef(Definition $storageLocatorDef, $config, $id = 'default')
277
    {
278 5
        $formatDiscoverLocalFileStorageFactoryDef = new Definition('Mathielen\ImportEngine\Storage\Factory\FormatDiscoverLocalFileStorageFactory', array(
279 5
            new Definition('Mathielen\ImportEngine\Storage\Format\Discovery\MimeTypeDiscoverStrategy', array(
280
                array(
281 5
                    'text/plain'=>new Definition('Mathielen\ImportEngine\Storage\Format\Factory\CsvAutoDelimiterFormatFactory'),
282 5
                    'text/csv'=>new Definition('Mathielen\ImportEngine\Storage\Format\Factory\CsvAutoDelimiterFormatFactory'),
283
                )
284 5
            )),
285 5
            new Reference('logger')
286 5
        ));
287
288 5
        switch ($config['type']) {
289 5
            case 'directory':
290 5
                $spFinderDef = new Definition('Symfony\Component\Finder\Finder');
291 5
                $spFinderDef->addMethodCall('in', array(
292 5
                    $config['uri']
293 5
                ));
294 5
                $spDef = new Definition('Mathielen\ImportEngine\Storage\Provider\FinderFileStorageProvider', array(
295 5
                    $spFinderDef,
296
                    $formatDiscoverLocalFileStorageFactoryDef
297 5
                ));
298 5
                break;
299 5
            case 'upload':
300 5
                $spDef = new Definition('Mathielen\ImportEngine\Storage\Provider\UploadFileStorageProvider', array(
301 5
                    $config['uri'],
302
                    $formatDiscoverLocalFileStorageFactoryDef
303 5
                ));
304 5
                break;
305 5
            case 'doctrine':
306 5
                $spDef = new Definition('Mathielen\ImportEngine\Storage\Provider\DoctrineQueryStorageProvider', array(
307 5
                    new Reference('doctrine.orm.entity_manager'),
308 5
                    $config['queries']
309 5
                ));
310 5
                break;
311 5
            case 'service':
312 5
                $spDef = new Definition('Mathielen\ImportEngine\Storage\Provider\ServiceStorageProvider', array(
313 5
                    new Reference('service_container'),
314 5
                    $config['services']
315 5
                ));
316 5
                break;
317 5
            case 'file':
318 5
                $spDef = new Definition('Mathielen\ImportEngine\Storage\Provider\FileStorageProvider', array(
319
                    $formatDiscoverLocalFileStorageFactoryDef
320 5
                ));
321 5
                break;
322
            default:
323
                throw new InvalidConfigurationException('Unknown type for storage provider: '.$config['type']);
324 5
        }
325
326 5
        $storageLocatorDef->addMethodCall('register', array(
327 5
            $id,
328
            $spDef
329 5
        ));
330 5
    }
331
332 9
    private function getStorageFileDefinitionFromUri($uri)
333
    {
334 9
        if (substr($uri, 0, 2) === '@=') {
335
            $uri = new Expression(substr($uri, 2));
336
        }
337
338 9
        return new Definition('SplFileInfo', array(
339
            $uri
340 9
        ));
341
    }
342
343
    /**
344
     * @return Definition
345
     */
346 9
    private function getStorageDef(array $config, Definition $objectFactoryDef=null)
347
    {
348 9
        switch ($config['type']) {
349 9
            case 'file':
350 9
                $fileDef = $this->getStorageFileDefinitionFromUri($config['uri']);
351
352 9
                $format = $config['format'];
353 9
                $storageDef = new Definition('Mathielen\ImportEngine\Storage\LocalFileStorage', array(
354 9
                    $fileDef,
355 9
                    new Definition('Mathielen\ImportEngine\Storage\Format\\'.ucfirst($format['type'])."Format", $format['arguments'])
356 9
                ));
357
358 9
                break;
359 5
            case 'doctrine':
360 5
                $storageDef = new Definition('Mathielen\ImportEngine\Storage\DoctrineStorage', array(
361 5
                    new Reference('doctrine.orm.entity_manager'),
362 5
                    $config['entity']
363 5
                ));
364
365 5
                break;
366 5
            case 'service':
367 5
                $storageDef = new Definition('Mathielen\ImportEngine\Storage\ServiceStorage', array(
368 5
                    array(new Reference($config['service']), $config['method']), //callable
369 5
                    array(),
370
                    $objectFactoryDef //from parameter array
371 5
                ));
372
373 5
                break;
374
            default:
375
                throw new InvalidConfigurationException('Unknown type for storage: '.$config['type']);
376 9
        }
377
378 9
        return $storageDef;
379
    }
380
381 11
    public function getAlias()
382
    {
383 11
        return 'mathielen_import_engine';
384
    }
385
}
386