Completed
Push — master ( 367ba0...cb743d )
by
unknown
12:47
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.5%

Importance

Changes 0
Metric Value
wmc 60
c 0
b 0
f 0
lcom 1
cbo 7
dl 0
loc 925
ccs 174
cts 391
cp 0.445
rs 5

24 Methods

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

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 6
            $parameters
222
        );
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 6
            array_merge(
229 6
                $parameters,
230
                [
231 6
                    'document' => $document.'Embedded',
232 6
                    'docType' => 'embedded-document'
233
                ]
234
            )
235
        );
236
237 6
        $this->renderFile(
238 6
            'document/Document.php.twig',
239 6
            $dir . '/Document/' . $document . '.php',
240 6
            $parameters
241
        );
242 6
        $this->renderFile(
243 6
            'document/DocumentEmbedded.php.twig',
244 6
            $dir . '/Document/' . $document . 'Embedded.php',
245 6
            $parameters
246
        );
247 6
        $this->renderFile(
248 6
            'document/DocumentBase.php.twig',
249 6
            $dir . '/Document/' . $document . 'Base.php',
250 6
            $parameters
251
        );
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
            )
281
        );
282
283 6
        $this->addXMLParameter(
284 6
            $parameters['base'] . 'Document\\' . $parameters['document'],
285 6
            $docName . '.class'
286
        );
287
288 6
        $this->addXMLParameter(
289 6
            $parameters['json']->getRoles(),
290 6
            $docName . '.roles',
291 6
            'collection'
292
        );
293
294 6
        $services = $this->addService(
295 6
            $services,
296 6
            $docName
297
        );
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
            )
307
        );
308
309
        // normal repo service
310 6
        $services = $this->addParam(
311 6
            $services,
312 6
            $repoName . '.class',
313 6
            $parameters['base'] . 'Repository\\' . $parameters['document']
314
        );
315
316 6
        $this->addService(
317 6
            $services,
318 6
            $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
                )
327
            ),
328 6
            'doctrine_mongodb.odm.default_document_manager',
329 6
            'getRepository'
330
        );
331
332
        // embedded repo service
333 6
        $services = $this->addParam(
334 6
            $services,
335 6
            $repoName . 'embedded.class',
336 6
            $parameters['base'] . 'Repository\\' . $parameters['document'] . 'Embedded'
337
        );
338
339 6
        $this->addService(
340 6
            $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
                )
350
            ),
351 6
            'doctrine_mongodb.odm.default_document_manager',
352 6
            'getRepository'
353
        );
354
355 6
        $this->renderFile(
356 6
            'document/DocumentRepository.php.twig',
357 6
            $dir . '/Repository/' . $document . 'Repository.php',
358 6
            $parameters
359
        );
360 6
        $this->renderFile(
361 6
            'document/DocumentRepository.php.twig',
362 6
            $dir . '/Repository/' . $document . 'EmbeddedRepository.php',
363 6
            array_merge(
364 6
                $parameters,
365
                [
366 6
                    'document' => $document.'Embedded',
367
                ]
368
            )
369
        );
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
                    default:
393 2
                        $this->addParam($services, $parameter['key'], $parameter['content']);
394
                }
395
            }
396
        }
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
        );
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
        }
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
        }
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
        }
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
                }
495
496 4
                $paramNode->appendChild($rolesNode);
497
            }
498
        }
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)
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
            } else {
545
                $container->appendChild($newNode);
546
            }
547
        } 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
        }
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