Completed
Push — master ( d950da...d2fb93 )
by Narcotic
09:23 queued 10s
created

ResourceGenerator   C

Complexity

Total Complexity 60

Size/Duplication

Total Lines 925
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 44.64%

Importance

Changes 0
Metric Value
wmc 60
lcom 1
cbo 7
dl 0
loc 925
ccs 208
cts 466
cp 0.4464
rs 5
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
B generateParameters() 0 19 5
A addXmlParameter() 0 16 3
A loadServices() 0 11 2
A addParam() 0 14 2
A __construct() 0 14 1
A setJson() 0 4 1
A setGenerateController() 0 4 1
B generate() 0 59 5
A persistServicesXML() 0 6 1
B generateDocument() 0 40 1
B generateServices() 0 108 1
A addCollectionParam() 0 19 4
A parameterNodeExists() 0 7 1
B addNodeIfMissing() 0 26 4
A addAttributeToNode() 0 8 2
C addService() 0 62 8
A addCallsToService() 0 6 2
A addCallToService() 0 22 1
A addArgumentsToService() 0 6 2
A addArgumentToService() 0 20 2
C generateSerializer() 0 51 8
A generateModel() 0 70 1
B generateController() 0 38 1
A generateFixtures() 0 11 1

How to fix   Complexity   

Complex Class

Complex classes like ResourceGenerator 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 ResourceGenerator, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * generator code for resources
4
 */
5
6
namespace Graviton\GeneratorBundle\Generator;
7
8
use Sensio\Bundle\GeneratorBundle\Model\EntityGeneratorResult;
9
use Doctrine\Common\Collections\ArrayCollection;
10
use Graviton\GeneratorBundle\Definition\JsonDefinition;
11
use Graviton\GeneratorBundle\Generator\ResourceGenerator\FieldMapper;
12
use Graviton\GeneratorBundle\Generator\ResourceGenerator\ParameterBuilder;
13
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
14
use Symfony\Component\Filesystem\Filesystem;
15
use Symfony\Component\HttpKernel\HttpKernelInterface;
16
use Doctrine\Bundle\DoctrineBundle\Registry as DoctrineRegistry;
17
18
/**
19
 * bundle containing various code generators
20
 *
21
 * This code is more or less loosley based on SensioBundleGenerator. It could
22
 * use some refactoring to duplicate less for that, but this is how i finally
23
 * got a working version.
24
 *
25
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
26
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
27
 * @link     http://swisscom.ch
28
 */
29
class ResourceGenerator extends AbstractGenerator
30
{
31
    /**
32
     * @private Filesystem
33
     */
34
    private $filesystem;
35
36
    /**
37
     * @private DoctrineRegistry
38
     */
39
    private $doctrine;
40
41
    /**
42
     * @private HttpKernelInterface
43
     */
44
    private $kernel;
45
46
    /**
47
     * our json file definition
48
     *
49
     * @var JsonDefinition|null
50
     */
51
    private $json = null;
52
53
    /**
54
     * @var ArrayCollection
55
     */
56
    protected $xmlParameters;
57
58
    /**
59
     * @var \DomDocument
60
     */
61
    private $serviceDOM;
62
63
    /**
64
     * @var FieldMapper
65
     */
66
    private $mapper;
67
68
    /**
69
     * @var boolean
70
     */
71
    private $generateController = false;
72
73
    /**
74
     * @var ParameterBuilder
75
     */
76
    private $parameterBuilder;
77
78
    /**
79
     * Instantiates generator object
80
     *
81
     * @param Filesystem          $filesystem       fs abstraction layer
82
     * @param DoctrineRegistry    $doctrine         odm registry
83
     * @param HttpKernelInterface $kernel           app kernel
84
     * @param FieldMapper         $mapper           field type mapper
85
     * @param ParameterBuilder    $parameterBuilder param builder
86
     */
87 4
    public function __construct(
88
        Filesystem $filesystem,
89
        DoctrineRegistry $doctrine,
90
        HttpKernelInterface $kernel,
91
        FieldMapper $mapper,
92
        ParameterBuilder $parameterBuilder
93
    ) {
94 4
        $this->filesystem = $filesystem;
95 4
        $this->doctrine = $doctrine;
96 4
        $this->kernel = $kernel;
97 4
        $this->mapper = $mapper;
98 4
        $this->parameterBuilder = $parameterBuilder;
99 4
        $this->xmlParameters = new ArrayCollection();
100 4
    }
101
102
    /**
103
     * @param JsonDefinition $json optional JsonDefinition object
104
     *
105
     * @return void
106
     */
107
    public function setJson(JsonDefinition $json)
108
    {
109
        $this->json = $json;
110
    }
111
112
    /**
113
     * @param boolean $generateController should the controller be generated or not
114
     *
115
     * @return void
116
     */
117
    public function setGenerateController($generateController)
118
    {
119
        $this->generateController = $generateController;
120
    }
121
122
    /**
123
     * generate the resource with all its bits and parts
124
     *
125
     * @param BundleInterface $bundle   bundle
126
     * @param string          $document document name
127
     * @param string          $format   format of config files (please use xml)
128
     * @param array           $fields   fields to add
129
     *
130
     * @return EntityGeneratorResult
131
     */
132
    public function generate(
133
        BundleInterface $bundle,
134
        $document,
135
        $format,
136
        array $fields
137
    ) {
138
        $dir = $bundle->getPath();
139
        $basename = $this->getBundleBaseName($document);
140
        $bundleNamespace = substr(get_class($bundle), 0, 0 - strlen($bundle->getName()));
141
142
        if (!is_null($this->json)) {
143
            $this->json->setNamespace($bundleNamespace);
144
        }
145
146
        // add more info to the fields array
147
        $mapper = $this->mapper;
148
        $fields = array_map(
149
            function ($field) use ($mapper) {
150
                return $mapper->map($field, $this->json);
151
            },
152
            $fields
153
        );
154
155
        $parameters = $this->parameterBuilder
156
            ->setParameter('document', $document)
157
            ->setParameter('base', $bundleNamespace)
158
            ->setParameter('bundle', $bundle->getName())
159
            ->setParameter('format', $format)
160
            ->setParameter('json', $this->json)
161
            ->setParameter('fields', $fields)
162
            ->setParameter('basename', $basename)
163
            ->setParameter('isrecordOriginFlagSet', $this->json->isRecordOriginFlagSet())
164
            ->setParameter('recordOriginModifiable', $this->json->isRecordOriginModifiable())
165
            ->setParameter('isVersioning', $this->json->isVersionedService())
166
            ->setParameter('collection', $this->json->getServiceCollection())
167
            ->setParameter('indexes', $this->json->getIndexes())
168
            ->setParameter('textIndexes', $this->json->getAllTextIndexes())
169
            ->getParameters();
170
171
        $this->generateDocument($parameters, $dir, $document);
172
        $this->generateSerializer($parameters, $dir, $document);
173
        $this->generateModel($parameters, $dir, $document);
174
175
        if ($this->json instanceof JsonDefinition && $this->json->hasFixtures() === true) {
176
            $this->generateFixtures($parameters, $dir, $document);
177
        }
178
179
        if ($this->generateController) {
180
            $this->generateController($parameters, $dir, $document);
181
        }
182
183
        $this->generateParameters($dir);
184
185
        return new EntityGeneratorResult(
186
            $dir . '/Document/' . $document . '.php',
187
            $dir . '/Repository/' . $document . 'Repository.php',
188
            $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml'
189
        );
190
    }
191
192
    /**
193
     * Writes the current services definition to a file.
194
     *
195
     * @param string $dir base bundle dir
196
     *
197
     * @return void
198
     */
199 8
    protected function persistServicesXML($dir)
200
    {
201 8
        $services = $this->loadServices($dir);
202
203 8
        file_put_contents($dir . '/Resources/config/services.xml', $services->saveXML());
204 8
    }
205
206
    /**
207
     * generate document part of a resource
208
     *
209
     * @param array  $parameters twig parameters
210
     * @param string $dir        base bundle dir
211
     * @param string $document   document name
212
     *
213
     * @return void
214
     */
215 6
    protected function generateDocument($parameters, $dir, $document)
216
    {
217
        // doctrine mapping normal class
218 6
        $this->renderFile(
219 6
            'document/Document.mongodb.xml.twig',
220 6
            $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml',
221
            $parameters
222 3
        );
223
224
        // doctrine mapping embedded
225 6
        $this->renderFile(
226 6
            'document/Document.mongodb.xml.twig',
227 6
            $dir . '/Resources/config/doctrine/' . $document . 'Embedded.mongodb.xml',
228 3
            array_merge(
229 3
                $parameters,
230
                [
231 6
                    'document' => $document.'Embedded',
232 3
                    'docType' => 'embedded-document'
233 3
                ]
234 3
            )
235 3
        );
236
237 6
        $this->renderFile(
238 6
            'document/Document.php.twig',
239 6
            $dir . '/Document/' . $document . '.php',
240
            $parameters
241 3
        );
242 6
        $this->renderFile(
243 6
            'document/DocumentEmbedded.php.twig',
244 6
            $dir . '/Document/' . $document . 'Embedded.php',
245
            $parameters
246 3
        );
247 6
        $this->renderFile(
248 6
            'document/DocumentBase.php.twig',
249 6
            $dir . '/Document/' . $document . 'Base.php',
250
            $parameters
251 3
        );
252
253 6
        $this->generateServices($parameters, $dir, $document);
254 6
    }
255
256
    /**
257
     * update xml services
258
     *
259
     * @param array  $parameters twig parameters
260
     * @param string $dir        base bundle dir
261
     * @param string $document   document name
262
     *
263
     * @return void
264
     */
265 6
    protected function generateServices($parameters, $dir, $document)
266
    {
267 6
        $services = $this->loadServices($dir);
268
269 6
        $bundleParts = explode('\\', $parameters['base']);
270 6
        $shortName = $bundleParts[0];
271 6
        $shortBundle = $this->getBundleBaseName($bundleParts[1]);
272
273 6
        $docName = implode(
274 6
            '.',
275
            array(
276 6
                strtolower($shortName),
277 6
                strtolower($shortBundle),
278 6
                'document',
279 6
                strtolower($parameters['document'])
280 3
            )
281 3
        );
282
283 6
        $this->addXMLParameter(
284 6
            $parameters['base'] . 'Document\\' . $parameters['document'],
285 3
            $docName . '.class'
286 3
        );
287
288 6
        $this->addXMLParameter(
289 6
            $parameters['json']->getRoles(),
290 6
            $docName . '.roles',
291 3
            'collection'
292 3
        );
293
294 6
        $services = $this->addService(
295 3
            $services,
296
            $docName
297 3
        );
298
299 6
        $repoName = implode(
300 6
            '.',
301
            array(
302 6
                strtolower($shortName),
303 6
                strtolower($shortBundle),
304 6
                'repository',
305 6
                strtolower($parameters['document'])
306 3
            )
307 3
        );
308
309
        // normal repo service
310 6
        $services = $this->addParam(
311 3
            $services,
312 6
            $repoName . '.class',
313 6
            $parameters['base'] . 'Repository\\' . $parameters['document']
314 3
        );
315
316 6
        $this->addService(
317 3
            $services,
318 3
            $repoName,
319 6
            null,
320 6
            array(),
321 6
            null,
322
            array(
323
                array(
324 6
                    'type' => 'string',
325 6
                    'value' => $parameters['bundle'] . ':' . $document
326 3
                )
327 3
            ),
328 6
            'doctrine_mongodb.odm.default_document_manager',
329 3
            'getRepository'
330 3
        );
331
332
        // embedded repo service
333 6
        $services = $this->addParam(
334 3
            $services,
335 6
            $repoName . 'embedded.class',
336 6
            $parameters['base'] . 'Repository\\' . $parameters['document'] . 'Embedded'
337 3
        );
338
339 6
        $this->addService(
340 3
            $services,
341 6
            $repoName . 'embedded',
342 6
            null,
343 6
            array(),
344 6
            null,
345
            array(
346
                array(
347 6
                    'type' => 'string',
348 6
                    'value' => $parameters['bundle'] . ':' . $document . 'Embedded'
349 3
                )
350 3
            ),
351 6
            'doctrine_mongodb.odm.default_document_manager',
352 3
            'getRepository'
353 3
        );
354
355 6
        $this->renderFile(
356 6
            'document/DocumentRepository.php.twig',
357 6
            $dir . '/Repository/' . $document . 'Repository.php',
358
            $parameters
359 3
        );
360 6
        $this->renderFile(
361 6
            'document/DocumentRepository.php.twig',
362 6
            $dir . '/Repository/' . $document . 'EmbeddedRepository.php',
363 3
            array_merge(
364 3
                $parameters,
365
                [
366 6
                    'document' => $document.'Embedded',
367
                ]
368 3
            )
369 3
        );
370
371 6
        $this->persistServicesXML($dir);
372 6
    }
373
374
    /**
375
     * Generates the parameters section of the services.xml file.
376
     *
377
     * @param string $dir base bundle dir
378
     *
379
     * @return void
380
     */
381 2
    protected function generateParameters($dir)
382
    {
383 2
        if ($this->xmlParameters->count() > 0) {
384 2
            $services = $this->loadServices($dir);
385
386 2
            foreach ($this->xmlParameters as $parameter) {
387 2
                switch ($parameter['type']) {
388 2
                    case 'collection':
389 2
                        $this->addCollectionParam($services, $parameter['key'], $parameter['content']);
390 2
                        break;
391 2
                    case 'string':
392 1
                    default:
393 2
                        $this->addParam($services, $parameter['key'], $parameter['content']);
394 1
                }
395 1
            }
396 1
        }
397
398 2
        $this->persistServicesXML($dir);
399 2
    }
400
401
    /**
402
     * Registers information to be generated to a parameter tag.
403
     *
404
     * @param mixed  $value Content of the tag
405
     * @param string $key   Content of the key attribute
406
     * @param string $type  Type of the tag
407
     *
408
     * @return void
409
     */
410 2
    protected function addXmlParameter($value, $key, $type = 'string')
411
    {
412
        $element = array(
413 2
            'content' => $value,
414 2
            'key' => $key,
415 2
            'type' => strtolower($type),
416 1
        );
417
418 2
        if (!isset($this->xmlParameters)) {
419
            $this->xmlParameters = new ArrayCollection();
420
        }
421
422 2
        if (!$this->xmlParameters->contains($element)) {
423 2
            $this->xmlParameters->add($element);
424 1
        }
425 2
    }
426
427
    /**
428
     * load services.xml
429
     *
430
     * @param string $dir base dir
431
     *
432
     * @return \DOMDocument
433
     */
434 4
    protected function loadServices($dir)
435
    {
436 4
        if (empty($this->serviceDOM)) {
437 4
            $this->serviceDOM = new \DOMDocument;
438 4
            $this->serviceDOM->formatOutput = true;
439 4
            $this->serviceDOM->preserveWhiteSpace = false;
440 4
            $this->serviceDOM->load($dir . '/Resources/config/services.xml');
441 2
        }
442
443 4
        return $this->serviceDOM;
444
    }
445
446
    /**
447
     * add param to services.xml
448
     *
449
     * @param \DOMDocument $dom   services.xml document
450
     * @param string       $key   parameter key
451
     * @param string       $value parameter value
452
     *
453
     * @return \DOMDocument
454
     */
455 12
    protected function addParam(\DOMDocument $dom, $key, $value)
456
    {
457 12
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
458
459 12
        if (!$this->parameterNodeExists($dom, $key)) {
460 12
            $attrNode = $dom->createElement('parameter', $value);
461
462 12
            $this->addAttributeToNode('key', $key, $dom, $attrNode);
463
464 12
            $paramNode->appendChild($attrNode);
465 6
        }
466
467 12
        return $dom;
468
    }
469
470
    /**
471
     * Adds a new parameter tag to parameters section reflecting the defined roles.
472
     *
473
     * @param \DOMDocument $dom    services.xml document
474
     * @param string       $key    parameter key
475
     * @param array        $values parameter value
476
     *
477
     * @return void
478
     *
479
     * @link http://symfony.com/doc/current/book/service_container.html#array-parameters
480
     */
481 4
    protected function addCollectionParam(\DomDocument $dom, $key, array $values)
482
    {
483 4
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
484
485 4
        if (!$this->parameterNodeExists($dom, $key)) {
486 4
            if (!empty($values)) {
487 4
                $rolesNode = $dom->createElement('parameter');
488 4
                $this->addAttributeToNode('key', $key, $dom, $rolesNode);
489 4
                $this->addAttributeToNode('type', 'collection', $dom, $rolesNode);
490
491 4
                foreach ($values as $item) {
492 4
                    $roleNode = $dom->createElement('parameter', $item);
493 4
                    $rolesNode->appendChild($roleNode);
494 2
                }
495
496 4
                $paramNode->appendChild($rolesNode);
497 2
            }
498 2
        }
499 4
    }
500
501
    /**
502
     * Determines, if the provided key attribute was already claimed by a parameter node.
503
     *
504
     * @param \DomDocument $dom Current document
505
     * @param string       $key Key to be found in document
506
     *
507
     * @return bool
508
     */
509 14
    private function parameterNodeExists(\DomDocument $dom, $key)
0 ignored issues
show
Coding Style introduced by
function parameterNodeExists() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
510
    {
511 14
        $xpath = new \DomXpath($dom);
512 14
        $nodes = $xpath->query('//parameters/parameter[@key="' . $key . '"]');
513
514 14
        return $nodes->length > 0;
515
    }
516
517
    /**
518
     * add node if missing
519
     *
520
     * @param \DOMDocument $dom          document
521
     * @param string       $element      name for new node element
522
     * @param string       $insertBefore xPath query of the new node shall be added before
523
     * @param string       $container    name of container tag
524
     *
525
     * @return \DOMNode new element node
526
     */
527 14
    private function addNodeIfMissing(&$dom, $element, $insertBefore = '', $container = 'container')
528
    {
529 14
        $container = $dom->getElementsByTagName($container)
530 14
            ->item(0);
531 14
        $nodes = $dom->getElementsByTagName($element);
532 14
        if ($nodes->length < 1) {
533 14
            $newNode = $dom->createElement($element);
534
535 14
            if (!empty($insertBefore)) {
536 14
                $xpath = new \DomXpath($dom);
537 14
                $found = $xpath->query($insertBefore);
538
539 14
                if ($found->length > 0) {
540
                    $container->insertBefore($newNode, $found->item(0));
541
                } else {
542 14
                    $container->appendChild($newNode);
543
                }
544 7
            } else {
545 7
                $container->appendChild($newNode);
546
            }
547 7
        } else {
548 4
            $newNode = $nodes->item(0);
549
        }
550
551 14
        return $newNode;
552
    }
553
554
    /**
555
     * add attribute to node if needed
556
     *
557
     * @param string       $name  attribute name
558
     * @param string       $value attribute value
559
     * @param \DOMDocument $dom   document
560
     * @param \DOMElement  $node  parent node
561
     *
562
     * @return void
563
     */
564 14
    private function addAttributeToNode($name, $value, $dom, $node)
565
    {
566 14
        if ($value) {
567 14
            $attr = $dom->createAttribute($name);
568 14
            $attr->value = $value;
569 14
            $node->appendChild($attr);
570 7
        }
571 14
    }
572
573
    /**
574
     * add service to services.xml
575
     *
576
     * @param \DOMDocument $dom            services.xml dom
577
     * @param string       $id             id of new service
578
     * @param string       $parent         parent for service
0 ignored issues
show
Documentation introduced by
Should the type for parameter $parent not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
579
     * @param array        $calls          methodCalls to add
580
     * @param string       $tag            tag name or empty if no tag needed
0 ignored issues
show
Documentation introduced by
Should the type for parameter $tag not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
581
     * @param array        $arguments      service arguments
582
     * @param string       $factoryService factory service id
0 ignored issues
show
Documentation introduced by
Should the type for parameter $factoryService not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
583
     * @param string       $factoryMethod  factory method name
0 ignored issues
show
Documentation introduced by
Should the type for parameter $factoryMethod not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
584
     *
585
     * @return \DOMDocument
586
     */
587
    protected function addService(
588
        $dom,
589
        $id,
590
        $parent = null,
591
        array $calls = array(),
592
        $tag = null,
593
        array $arguments = array(),
594
        $factoryService = null,
595
        $factoryMethod = null
596
    ) {
597
        $servicesNode = $this->addNodeIfMissing($dom, 'services');
598
599
        $xpath = new \DomXpath($dom);
600
601
        // add controller to services
602
        $nodes = $xpath->query('//services/service[@id="' . $id . '"]');
603
        if ($nodes->length < 1) {
604
            $attrNode = $dom->createElement('service');
605
606
            $this->addAttributeToNode('id', $id, $dom, $attrNode);
607
            $this->addAttributeToNode('class', '%' . $id . '.class%', $dom, $attrNode);
608
            $this->addAttributeToNode('parent', $parent, $dom, $attrNode);
609
            if ($factoryService && $factoryMethod) {
610
                $factoryNode = $dom->createElement('factory');
611
                $this->addAttributeToNode('service', $factoryService, $dom, $factoryNode);
612
                $this->addAttributeToNode('method', $factoryMethod, $dom, $factoryNode);
613
                $attrNode->appendChild($factoryNode);
614
            }
615
            $this->addCallsToService($calls, $dom, $attrNode);
616
617
            if ($tag) {
618
                $tagNode = $dom->createElement('tag');
619
620
                $this->addAttributeToNode('name', $tag, $dom, $tagNode);
621
622
                // get stuff from json definition
623
                if ($this->json instanceof JsonDefinition) {
624
                    // id is also name of collection in mongodb
625
                    $this->addAttributeToNode('collection', $this->json->getId(), $dom, $tagNode);
626
627
                    // is this read only?
628
                    if ($this->json->isReadOnlyService()) {
629
                        $this->addAttributeToNode('read-only', 'true', $dom, $tagNode);
630
                    }
631
632
                    // router base defined?
633
                    $routerBase = $this->json->getRouterBase();
634
                    if ($routerBase !== false) {
635
                        $this->addAttributeToNode('router-base', $routerBase, $dom, $tagNode);
636
                    }
637
                }
638
639
                $attrNode->appendChild($tagNode);
640
            }
641
642
            $this->addArgumentsToService($arguments, $dom, $attrNode);
643
644
            $servicesNode->appendChild($attrNode);
645
        }
646
647
        return $dom;
648
    }
649
650
    /**
651
     * add calls to service
652
     *
653
     * @param array        $calls info on calls to create
654
     * @param \DOMDocument $dom   current domdocument
655
     * @param \DOMElement  $node  node to add call to
656
     *
657
     * @return void
658
     */
659
    private function addCallsToService($calls, $dom, $node)
660
    {
661
        foreach ($calls as $call) {
662
            $this->addCallToService($call, $dom, $node);
663
        }
664
    }
665
666
    /**
667
     * add call to service
668
     *
669
     * @param array        $call info on call node to create
670
     * @param \DOMDocument $dom  current domdocument
671
     * @param \DOMElement  $node node to add call to
672
     *
673
     * @return void
674
     */
675
    private function addCallToService($call, $dom, $node)
676
    {
677
        $callNode = $dom->createElement('call');
678
679
        $attr = $dom->createAttribute('method');
680
        $attr->value = $call['method'];
681
        $callNode->appendChild($attr);
682
683
        $argNode = $dom->createElement('argument');
684
685
        $attr = $dom->createAttribute('type');
686
        $attr->value = 'service';
687
        $argNode->appendChild($attr);
688
689
        $attr = $dom->createAttribute('id');
690
        $attr->value = $call['service'];
691
        $argNode->appendChild($attr);
692
693
        $callNode->appendChild($argNode);
694
695
        $node->appendChild($callNode);
696
    }
697
698
    /**
699
     * add arguments to servie
700
     *
701
     * @param array        $arguments arguments to create
702
     * @param \DOMDocument $dom       dom document to add to
703
     * @param \DOMElement  $node      node to use as parent
704
     *
705
     * @return void
706
     */
707
    private function addArgumentsToService($arguments, $dom, $node)
708
    {
709
        foreach ($arguments as $argument) {
710
            $this->addArgumentToService($argument, $dom, $node);
711
        }
712
    }
713
714
    /**
715
     * add argument to service
716
     *
717
     * @param array        $argument info on argument to create
718
     * @param \DOMDocument $dom      dom document to add to
719
     * @param \DOMElement  $node     node to use as parent
720
     *
721
     * @return void
722
     */
723
    private function addArgumentToService($argument, $dom, $node)
724
    {
725
        $isService = $argument['type'] == 'service';
726
727
        if ($isService) {
728
            $argNode = $dom->createElement('argument');
729
730
            $idArg = $dom->createAttribute('id');
731
            $idArg->value = $argument['id'];
732
            $argNode->appendChild($idArg);
733
        } else {
734
            $argNode = $dom->createElement('argument', $argument['value']);
735
        }
736
737
        $argType = $dom->createAttribute('type');
738
        $argType->value = $argument['type'];
739
        $argNode->appendChild($argType);
740
741
        $node->appendChild($argNode);
742
    }
743
744
    /**
745
     * generate serializer part of a resource
746
     *
747
     * @param array  $parameters twig parameters
748
     * @param string $dir        base bundle dir
749
     * @param string $document   document name
750
     *
751
     * @return void
752
     */
753
    protected function generateSerializer(array $parameters, $dir, $document)
754
    {
755
        // @TODO in Embedded and document just render the differences..
756
        $this->renderFile(
757
            'serializer/Document.xml.twig',
758
            $dir . '/Resources/config/serializer/Document.' . $document . 'Embedded.xml',
759
            array_merge(
760
                $parameters,
761
                [
762
                    'document' => $document.'Embedded',
763
                    'noIdField' => true,
764
                    'realIdField' => true
765
                ]
766
            )
767
        );
768
769
        foreach ($parameters['fields'] as $key => $field) {
770
            if (substr($field['serializerType'], 0, 14) == 'array<Graviton' &&
771
                strpos($field['serializerType'], '\\Entity') === false &&
772
                $field['relType'] == 'embed'
773
            ) {
774
                $parameters['fields'][$key]['serializerType'] = substr($field['serializerType'], 0, -1).'Embedded>';
775
            } elseif (substr($field['serializerType'], 0, 8) == 'Graviton' &&
776
                strpos($field['serializerType'], '\\Entity') === false &&
777
                $field['relType'] == 'embed'
778
            ) {
779
                $parameters['fields'][$key]['serializerType'] = $field['serializerType'].'Embedded';
780
            }
781
        }
782
        $this->renderFile(
783
            'serializer/Document.xml.twig',
784
            $dir . '/Resources/config/serializer/Document.' . $document . '.xml',
785
            array_merge(
786
                $parameters,
787
                [
788
                    'realIdField' => false
789
                ]
790
            )
791
        );
792
        $this->renderFile(
793
            'serializer/Document.xml.twig',
794
            $dir . '/Resources/config/serializer/Document.' . $document . 'Base.xml',
795
            array_merge(
796
                $parameters,
797
                [
798
                    'document' => $document.'Base',
799
                    'realIdField' => false
800
                ]
801
            )
802
        );
803
    }
804
805
    /**
806
     * generate model part of a resource
807
     *
808
     * @param array  $parameters twig parameters
809
     * @param string $dir        base bundle dir
810
     * @param string $document   document name
811
     *
812
     * @return void
813
     */
814
    protected function generateModel(array $parameters, $dir, $document)
815
    {
816
        $this->renderFile(
817
            'model/Model.php.twig',
818
            $dir . '/Model/' . $document . '.php',
819
            $parameters
820
        );
821
        $this->renderFile(
822
            'model/schema.json.twig',
823
            $dir . '/Resources/config/schema/' . $document . '.json',
824
            $parameters
825
        );
826
827
        // embedded versions
828
        $this->renderFile(
829
            'model/Model.php.twig',
830
            $dir . '/Model/' . $document . 'Embedded.php',
831
            array_merge($parameters, ['document' => $document.'Embedded'])
832
        );
833
        $this->renderFile(
834
            'model/schema.json.twig',
835
            $dir . '/Resources/config/schema/' . $document . 'Embedded.json',
836
            array_merge($parameters, ['document' => $document.'Embedded'])
837
        );
838
839
        $services = $this->loadServices($dir);
840
841
        $bundleParts = explode('\\', $parameters['base']);
842
        $shortName = strtolower($bundleParts[0]);
843
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
844
        $paramName = implode('.', array($shortName, $shortBundle, 'model', strtolower($parameters['document'])));
845
        $repoName = implode('.', array($shortName, $shortBundle, 'repository', strtolower($parameters['document'])));
846
847
        $this->addXmlParameter($parameters['base'] . 'Model\\' . $parameters['document'], $paramName . '.class');
848
849
        // normal service
850
        $this->addService(
851
            $services,
852
            $paramName,
853
            'graviton.rest.model',
854
            array(
855
                [
856
                    'method' => 'setRepository',
857
                    'service' => $repoName
858
                ],
859
            ),
860
            null
861
        );
862
863
        // embedded service
864
        $this->addXmlParameter(
865
            $parameters['base'] . 'Model\\' . $parameters['document'] . 'Embedded',
866
            $paramName . 'embedded.class'
867
        );
868
869
        $this->addService(
870
            $services,
871
            $paramName . 'embedded',
872
            'graviton.rest.model',
873
            array(
874
                [
875
                    'method' => 'setRepository',
876
                    'service' => $repoName . 'embedded'
877
                ],
878
            ),
879
            null
880
        );
881
882
        $this->persistServicesXML($dir);
883
    }
884
885
    /**
886
     * generate RESTful controllers ans service configs
887
     *
888
     * @param array  $parameters twig parameters
889
     * @param string $dir        base bundle dir
890
     * @param string $document   document name
891
     *
892
     * @return void
893
     */
894
    protected function generateController(array $parameters, $dir, $document)
895
    {
896
        $this->renderFile(
897
            'controller/DocumentController.php.twig',
898
            $dir . '/Controller/' . $document . 'Controller.php',
899
            $parameters
900
        );
901
902
        $services = $this->loadServices($dir);
903
904
        $bundleParts = explode('\\', $parameters['base']);
905
        $shortName = strtolower($bundleParts[0]);
906
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
907
        $paramName = implode('.', array($shortName, $shortBundle, 'controller', strtolower($parameters['document'])));
908
909
        $this->addXmlParameter(
910
            $parameters['base'] . 'Controller\\' . $parameters['document'] . 'Controller',
911
            $paramName . '.class'
912
        );
913
914
        $this->addService(
915
            $services,
916
            $paramName,
917
            $parameters['parent'],
918
            array(
919
                array(
920
                    'method' => 'setModel',
921
                    'service' => implode(
922
                        '.',
923
                        array($shortName, $shortBundle, 'model', strtolower($parameters['document']))
924
                    )
925
                )
926
            ),
927
            'graviton.rest'
928
        );
929
930
        $this->persistServicesXML($dir);
931
    }
932
933
    /**
934
     * generates fixtures
935
     *
936
     * @param array  $parameters twig parameters
937
     * @param string $dir        base bundle dir
938
     * @param string $document   document name
939
     *
940
     * @return void
941
     */
942
    protected function generateFixtures(array $parameters, $dir, $document)
943
    {
944
        $parameters['fixtures_json'] = addcslashes(json_encode($this->json->getFixtures()), "'");
945
        $parameters['fixtureOrder'] = $this->json->getFixtureOrder();
946
947
        $this->renderFile(
948
            'fixtures/LoadFixtures.php.twig',
949
            $dir . '/DataFixtures/MongoDB/Load' . $document . 'Data.php',
950
            $parameters
951
        );
952
    }
953
}
954