Completed
Pull Request — develop (#487)
by Lucas
100:12 queued 61:52
created

ResourceGenerator::addNodeIfMissing()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4.074

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 26
ccs 15
cts 18
cp 0.8333
rs 8.5806
cc 4
eloc 18
nc 4
nop 4
crap 4.074
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
 * @todo     split all the xml handling on services.conf into a Manipulator
30
 */
31
class ResourceGenerator extends AbstractGenerator
32
{
33
    /**
34
     * @private Filesystem
35
     */
36
    private $filesystem;
37
38
    /**
39
     * @private DoctrineRegistry
40
     */
41
    private $doctrine;
42
43
    /**
44
     * @private HttpKernelInterface
45
     */
46
    private $kernel;
47
48
    /**
49
     * our json file definition
50
     *
51
     * @var JsonDefinition|null
52
     */
53
    private $json = null;
54
55
    /**
56
     * @var ArrayCollection
57
     */
58
    protected $xmlParameters;
59
60
    /**
61
     * @var \DomDocument
62
     */
63
    private $serviceDOM;
64
65
    /**
66
     * @var FieldMapper
67
     */
68
    private $mapper;
69
70
    /**
71
     * @var boolean
72
     */
73
    private $generateController = false;
74
75
    /**
76
     * @var ParameterBuilder
77
     */
78
    private $parameterBuilder;
79
80
    /**
81
     * Instantiates generator object
82
     *
83
     * @param Filesystem          $filesystem       fs abstraction layer
84
     * @param DoctrineRegistry    $doctrine         odm registry
85
     * @param HttpKernelInterface $kernel           app kernel
86
     * @param FieldMapper         $mapper           field type mapper
87
     * @param ParameterBuilder    $parameterBuilder param builder
88
     */
89 4
    public function __construct(
90
        Filesystem $filesystem,
91
        DoctrineRegistry $doctrine,
92
        HttpKernelInterface $kernel,
93
        FieldMapper $mapper,
94
        ParameterBuilder $parameterBuilder
95
    ) {
96 4
        $this->filesystem = $filesystem;
97 4
        $this->doctrine = $doctrine;
98 4
        $this->kernel = $kernel;
99 4
        $this->mapper = $mapper;
100 4
        $this->parameterBuilder = $parameterBuilder;
101 4
        $this->xmlParameters = new ArrayCollection();
102 4
    }
103
104
    /**
105
     * @param JsonDefinition $json optional JsonDefinition object
106
     *
107
     * @return void
108
     */
109
    public function setJson(JsonDefinition $json)
110
    {
111
        $this->json = $json;
112
    }
113
114
    /**
115
     * @param boolean $generateController should the controller be generated or not
116
     *
117
     * @return void
118
     */
119
    public function setGenerateController($generateController)
120
    {
121
        $this->generateController = $generateController;
122
    }
123
124
    /**
125
     * generate the resource with all its bits and parts
126
     *
127
     * @param BundleInterface $bundle   bundle
128
     * @param string          $document document name
129
     * @param string          $format   format of config files (please use xml)
130
     * @param array           $fields   fields to add
131
     *
132
     * @return EntityGeneratorResult
133
     */
134
    public function generate(
135
        BundleInterface $bundle,
136
        $document,
137
        $format,
138
        array $fields
139
    ) {
140
        $dir = $bundle->getPath();
141
        $basename = $this->getBundleBaseName($document);
142
        $bundleNamespace = substr(get_class($bundle), 0, 0 - strlen($bundle->getName()));
143
144
        if (!is_null($this->json)) {
145
            $this->json->setNamespace($bundleNamespace);
146
        }
147
148
        // add more info to the fields array
149
        $mapper = $this->mapper;
150
        $fields = array_map(
151
            function ($field) use ($mapper) {
152
                return $mapper->map($field, $this->json);
153
            },
154
            $fields
155
        );
156
        
157
        $parameters = $this->parameterBuilder
158
            ->setParameter('document', $document)
159
            ->setParameter('base', $bundleNamespace)
160
            ->setParameter('bundle', $bundle->getName())
161
            ->setParameter('format', $format)
162
            ->setParameter('json', $this->json)
163
            ->setParameter('fields', $fields)
164
            ->setParameter('basename', $basename)
165
            ->setParameter('isrecordOriginFlagSet', $this->json->isRecordOriginFlagSet())
166
            ->setParameter('recordOriginModifiable', $this->json->isRecordOriginModifiable())
167
            ->setParameter('collection', $this->json->getServiceCollection())
168
            ->setParameter('indexes', $this->json->getIndexes())
169
            ->setParameter('textIndexes', $this->json->getAllTextIndexes())
170
            ->getParameters();
171
172
        $this->generateDocument($parameters, $dir, $document);
173
        $this->generateSerializer($parameters, $dir, $document);
174
        $this->generateModel($parameters, $dir, $document);
175
176
        if ($this->json instanceof JsonDefinition && $this->json->hasFixtures() === true) {
177
            $this->generateFixtures($parameters, $dir, $document);
178
        }
179
180
        if ($this->generateController) {
181
            $this->generateController($parameters, $dir, $document);
182
        }
183
184
        $this->generateParameters($dir);
185
186
        return new EntityGeneratorResult(
187
            $dir . '/Document/' . $document . '.php',
188
            $dir . '/Repository/' . $document . 'Repository.php',
189
            $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml'
190
        );
191
    }
192
193
    /**
194
     * Writes the current services definition to a file.
195
     *
196
     * @param string $dir base bundle dir
197
     *
198
     * @return void
199
     */
200 8
    protected function persistServicesXML($dir)
201
    {
202 8
        $services = $this->loadServices($dir);
203
204 8
        file_put_contents($dir . '/Resources/config/services.xml', $services->saveXML());
205 8
    }
206
207
    /**
208
     * generate document part of a resource
209
     *
210
     * @param array  $parameters twig parameters
211
     * @param string $dir        base bundle dir
212
     * @param string $document   document name
213
     *
214
     * @return void
215
     */
216 6
    protected function generateDocument($parameters, $dir, $document)
217
    {
218
        // doctrine mapping normal class
219 6
        $this->renderFile(
220 6
            'document/Document.mongodb.xml.twig',
221 6
            $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml',
222
            $parameters
223 6
        );
224
225
        // doctrine mapping embedded
226 6
        $this->renderFile(
227 6
            'document/Document.mongodb.xml.twig',
228 6
            $dir . '/Resources/config/doctrine/' . $document . 'Embedded.mongodb.xml',
229 6
            array_merge(
230 6
                $parameters,
231
                [
232 6
                    'document' => $document.'Embedded',
233
                    'docType' => 'embedded-document'
234 6
                ]
235 6
            )
236 6
        );
237
238 6
        $this->renderFile(
239 6
            'document/Document.php.twig',
240 6
            $dir . '/Document/' . $document . '.php',
241
            $parameters
242 6
        );
243 6
        $this->renderFile(
244 6
            'document/DocumentEmbedded.php.twig',
245 6
            $dir . '/Document/' . $document . 'Embedded.php',
246
            $parameters
247 6
        );
248 6
        $this->renderFile(
249 6
            'document/DocumentBase.php.twig',
250 6
            $dir . '/Document/' . $document . 'Base.php',
251
            $parameters
252 6
        );
253
254 6
        $this->generateServices($parameters, $dir, $document);
255 6
    }
256
257
    /**
258
     * update xml services
259
     *
260
     * @param array  $parameters twig parameters
261
     * @param string $dir        base bundle dir
262
     * @param string $document   document name
263
     *
264
     * @return void
265
     */
266 6
    protected function generateServices($parameters, $dir, $document)
267
    {
268 6
        $services = $this->loadServices($dir);
269
270 6
        $bundleParts = explode('\\', $parameters['base']);
271 6
        $shortName = $bundleParts[0];
272 6
        $shortBundle = $this->getBundleBaseName($bundleParts[1]);
273
274 6
        $docName = implode(
275 6
            '.',
276
            array(
277 6
                strtolower($shortName),
278 6
                strtolower($shortBundle),
279 6
                'document',
280 6
                strtolower($parameters['document'])
281 6
            )
282 6
        );
283
284 6
        $this->addXMLParameter(
285 6
            $parameters['base'] . 'Document\\' . $parameters['document'],
286
            $docName . '.class'
287 6
        );
288
289 6
        $this->addXMLParameter(
290 6
            $parameters['json']->getRoles(),
291 6
            $docName . '.roles',
292
            'collection'
293 6
        );
294
295 6
        $services = $this->addService(
296 6
            $services,
297
            $docName
298 6
        );
299
300 6
        $repoName = implode(
301 6
            '.',
302
            array(
303 6
                strtolower($shortName),
304 6
                strtolower($shortBundle),
305 6
                'repository',
306 6
                strtolower($parameters['document'])
307 6
            )
308 6
        );
309
310
        // normal repo service
311 6
        $services = $this->addParam(
312 6
            $services,
313 6
            $repoName . '.class',
314 6
            $parameters['base'] . 'Repository\\' . $parameters['document']
315 6
        );
316
317 6
        $this->addService(
318 6
            $services,
319 6
            $repoName,
320 6
            null,
321 6
            null,
322 6
            array(),
323 6
            null,
324
            array(
325
                array(
326 6
                    'type' => 'string',
327 6
                    'value' => $parameters['bundle'] . ':' . $document
328 6
                )
329 6
            ),
330 6
            'doctrine_mongodb.odm.default_document_manager',
331
            'getRepository'
332 6
        );
333
334
        // embedded repo service
335 6
        $services = $this->addParam(
336 6
            $services,
337 6
            $repoName . 'embedded.class',
338 6
            $parameters['base'] . 'Repository\\' . $parameters['document'] . 'Embedded'
339 6
        );
340
341 6
        $this->addService(
342 6
            $services,
343 6
            $repoName . 'embedded',
344 6
            null,
345 6
            null,
346 6
            array(),
347 6
            null,
348
            array(
349
                array(
350 6
                    'type' => 'string',
351 6
                    'value' => $parameters['bundle'] . ':' . $document . 'Embedded'
352 6
                )
353 6
            ),
354 6
            'doctrine_mongodb.odm.default_document_manager',
355
            'getRepository'
356 6
        );
357
358 6
        $this->renderFile(
359 6
            'document/DocumentRepository.php.twig',
360 6
            $dir . '/Repository/' . $document . 'Repository.php',
361
            $parameters
362 6
        );
363 6
        $this->renderFile(
364 6
            'document/DocumentRepository.php.twig',
365 6
            $dir . '/Repository/' . $document . 'EmbeddedRepository.php',
366 6
            array_merge(
367 6
                $parameters,
368
                [
369 6
                    'document' => $document.'Embedded',
370
                ]
371 6
            )
372 6
        );
373
374 6
        $this->persistServicesXML($dir);
375 6
    }
376
377
    /**
378
     * Generates the parameters section of the services.xml file.
379
     *
380
     * @param string $dir base bundle dir
381
     *
382
     * @return void
383
     */
384 2
    protected function generateParameters($dir)
385
    {
386 2
        if ($this->xmlParameters->count() > 0) {
387 2
            $services = $this->loadServices($dir);
388
389 2
            foreach ($this->xmlParameters as $parameter) {
390 2
                switch ($parameter['type']) {
391 2
                    case 'collection':
392 2
                        $this->addCollectionParam($services, $parameter['key'], $parameter['content']);
393 2
                        break;
394 2
                    case 'string':
395 2
                    default:
396 2
                        $this->addParam($services, $parameter['key'], $parameter['content']);
397 2
                }
398 2
            }
399 2
        }
400
401 2
        $this->persistServicesXML($dir);
402 2
    }
403
404
    /**
405
     * Registers information to be generated to a parameter tag.
406
     *
407
     * @param mixed  $value Content of the tag
408
     * @param string $key   Content of the key attribute
409
     * @param string $type  Type of the tag
410
     *
411
     * @return void
412
     */
413 2
    protected function addXmlParameter($value, $key, $type = 'string')
414
    {
415
        $element = array(
416 2
            'content' => $value,
417 2
            'key' => $key,
418 2
            'type' => strtolower($type),
419 2
        );
420
421 2
        if (!isset($this->xmlParameters)) {
422
            $this->xmlParameters = new ArrayCollection();
423
        }
424
425 2
        if (!$this->xmlParameters->contains($element)) {
426 2
            $this->xmlParameters->add($element);
427 2
        }
428 2
    }
429
430
    /**
431
     * load services.xml
432
     *
433
     * @param string $dir base dir
434
     *
435
     * @return \DOMDocument
436
     */
437 4
    protected function loadServices($dir)
438
    {
439 4
        if (empty($this->serviceDOM)) {
440 4
            $this->serviceDOM = new \DOMDocument;
441 4
            $this->serviceDOM->formatOutput = true;
442 4
            $this->serviceDOM->preserveWhiteSpace = false;
443 4
            $this->serviceDOM->load($dir . '/Resources/config/services.xml');
444 4
        }
445
446 4
        return $this->serviceDOM;
447
    }
448
449
    /**
450
     * add param to services.xml
451
     *
452
     * @param \DOMDocument $dom   services.xml document
453
     * @param string       $key   parameter key
454
     * @param string       $value parameter value
455
     *
456
     * @return \DOMDocument
457
     */
458 12
    protected function addParam(\DOMDocument $dom, $key, $value)
459
    {
460 12
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
461
462 12
        if (!$this->parameterNodeExists($dom, $key)) {
463 12
            $attrNode = $dom->createElement('parameter', $value);
464
465 12
            $this->addAttributeToNode('key', $key, $dom, $attrNode);
466
467 12
            $paramNode->appendChild($attrNode);
468 12
        }
469
470 12
        return $dom;
471
    }
472
473
    /**
474
     * Adds a new parameter tag to parameters section reflecting the defined roles.
475
     *
476
     * @param \DOMDocument $dom    services.xml document
477
     * @param string       $key    parameter key
478
     * @param array        $values parameter value
479
     *
480
     * @return void
481
     *
482
     * @link http://symfony.com/doc/current/book/service_container.html#array-parameters
483
     */
484 4
    protected function addCollectionParam(\DomDocument $dom, $key, array $values)
485
    {
486 4
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
487
488 4
        if (!$this->parameterNodeExists($dom, $key)) {
489 4
            if (!empty($values)) {
490 4
                $rolesNode = $dom->createElement('parameter');
491 4
                $this->addAttributeToNode('key', $key, $dom, $rolesNode);
492 4
                $this->addAttributeToNode('type', 'collection', $dom, $rolesNode);
493
494 4
                foreach ($values as $item) {
495 4
                    $roleNode = $dom->createElement('parameter', $item);
496 4
                    $rolesNode->appendChild($roleNode);
497 4
                }
498
499 4
                $paramNode->appendChild($rolesNode);
500 4
            }
501 4
        }
502 4
    }
503
504
    /**
505
     * Determines, if the provided key attribute was already claimed by a parameter node.
506
     *
507
     * @param \DomDocument $dom Current document
508
     * @param string       $key Key to be found in document
509
     *
510
     * @return bool
511
     */
512 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...
513
    {
514 14
        $xpath = new \DomXpath($dom);
515 14
        $nodes = $xpath->query('//parameters/parameter[@key="' . $key . '"]');
516
517 14
        return $nodes->length > 0;
518
    }
519
520
    /**
521
     * add node if missing
522
     *
523
     * @param \DOMDocument $dom          document
524
     * @param string       $element      name for new node element
525
     * @param string       $insertBefore xPath query of the new node shall be added before
526
     * @param string       $container    name of container tag
527
     *
528
     * @return \DOMNode new element node
529
     */
530 14
    private function addNodeIfMissing(&$dom, $element, $insertBefore = '', $container = 'container')
531
    {
532 14
        $container = $dom->getElementsByTagName($container)
533 14
            ->item(0);
534 14
        $nodes = $dom->getElementsByTagName($element);
535 14
        if ($nodes->length < 1) {
536 14
            $newNode = $dom->createElement($element);
537
538 14
            if (!empty($insertBefore)) {
539 14
                $xpath = new \DomXpath($dom);
540 14
                $found = $xpath->query($insertBefore);
541
542 14
                if ($found->length > 0) {
543
                    $container->insertBefore($newNode, $found->item(0));
544
                } else {
545 14
                    $container->appendChild($newNode);
546
                }
547 14
            } else {
548
                $container->appendChild($newNode);
549
            }
550 14
        } else {
551 4
            $newNode = $nodes->item(0);
552
        }
553
554 14
        return $newNode;
555
    }
556
557
    /**
558
     * add attribute to node if needed
559
     *
560
     * @param string       $name  attribute name
561
     * @param string       $value attribute value
562
     * @param \DOMDocument $dom   document
563
     * @param \DOMElement  $node  parent node
564
     *
565
     * @return void
566
     */
567 14
    private function addAttributeToNode($name, $value, $dom, $node)
568
    {
569 14
        if ($value) {
570 14
            $attr = $dom->createAttribute($name);
571 14
            $attr->value = $value;
572 14
            $node->appendChild($attr);
573 14
        }
574 14
    }
575
576
    /**
577
     * add service to services.xml
578
     *
579
     * @param \DOMDocument $dom            services.xml dom
580
     * @param string       $id             id of new service
581
     * @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...
582
     * @param string       $scope          scope of service
0 ignored issues
show
Documentation introduced by
Should the type for parameter $scope 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 array        $calls          methodCalls to add
584
     * @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...
585
     * @param array        $arguments      service arguments
586
     * @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...
587
     * @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...
588
     *
589
     * @return \DOMDocument
590
     */
591
    protected function addService(
592
        $dom,
593
        $id,
594
        $parent = null,
595
        $scope = null,
596
        array $calls = array(),
597
        $tag = null,
598
        array $arguments = array(),
599
        $factoryService = null,
600
        $factoryMethod = null
601
    ) {
602
        $servicesNode = $this->addNodeIfMissing($dom, 'services');
603
604
        $xpath = new \DomXpath($dom);
605
606
        // add controller to services
607
        $nodes = $xpath->query('//services/service[@id="' . $id . '"]');
608
        if ($nodes->length < 1) {
609
            $attrNode = $dom->createElement('service');
610
611
            $this->addAttributeToNode('id', $id, $dom, $attrNode);
612
            $this->addAttributeToNode('class', '%' . $id . '.class%', $dom, $attrNode);
613
            $this->addAttributeToNode('parent', $parent, $dom, $attrNode);
614
            $this->addAttributeToNode('scope', $scope, $dom, $attrNode);
615
            if ($factoryService && $factoryMethod) {
616
                $factoryNode = $dom->createElement('factory');
617
                $this->addAttributeToNode('service', $factoryService, $dom, $factoryNode);
618
                $this->addAttributeToNode('method', $factoryMethod, $dom, $factoryNode);
619
                $attrNode->appendChild($factoryNode);
620
            }
621
            $this->addCallsToService($calls, $dom, $attrNode);
622
623
            if ($tag) {
624
                $tagNode = $dom->createElement('tag');
625
626
                $this->addAttributeToNode('name', $tag, $dom, $tagNode);
627
628
                // get stuff from json definition
629
                if ($this->json instanceof JsonDefinition) {
630
                    // id is also name of collection in mongodb
631
                    $this->addAttributeToNode('collection', $this->json->getId(), $dom, $tagNode);
632
633
                    // is this read only?
634
                    if ($this->json->isReadOnlyService()) {
635
                        $this->addAttributeToNode('read-only', 'true', $dom, $tagNode);
636
                    }
637
638
                    // router base defined?
639
                    $routerBase = $this->json->getRouterBase();
640
                    if ($routerBase !== false) {
641
                        $this->addAttributeToNode('router-base', $routerBase, $dom, $tagNode);
642
                    }
643
                }
644
645
                $attrNode->appendChild($tagNode);
646
            }
647
648
            $this->addArgumentsToService($arguments, $dom, $attrNode);
649
650
            $servicesNode->appendChild($attrNode);
651
        }
652
653
        return $dom;
654
    }
655
656
    /**
657
     * add calls to service
658
     *
659
     * @param array        $calls info on calls to create
660
     * @param \DOMDocument $dom   current domdocument
661
     * @param \DOMElement  $node  node to add call to
662
     *
663
     * @return void
664
     */
665
    private function addCallsToService($calls, $dom, $node)
666
    {
667
        foreach ($calls as $call) {
668
            $this->addCallToService($call, $dom, $node);
669
        }
670
    }
671
672
    /**
673
     * add call to service
674
     *
675
     * @param array        $call info on call node to create
676
     * @param \DOMDocument $dom  current domdocument
677
     * @param \DOMElement  $node node to add call to
678
     *
679
     * @return void
680
     */
681
    private function addCallToService($call, $dom, $node)
682
    {
683
        $callNode = $dom->createElement('call');
684
685
        $attr = $dom->createAttribute('method');
686
        $attr->value = $call['method'];
687
        $callNode->appendChild($attr);
688
689
        $argNode = $dom->createElement('argument');
690
691
        $attr = $dom->createAttribute('type');
692
        $attr->value = 'service';
693
        $argNode->appendChild($attr);
694
695
        $attr = $dom->createAttribute('id');
696
        $attr->value = $call['service'];
697
        $argNode->appendChild($attr);
698
699
        $callNode->appendChild($argNode);
700
701
        $node->appendChild($callNode);
702
    }
703
704
    /**
705
     * add arguments to servie
706
     *
707
     * @param array        $arguments arguments to create
708
     * @param \DOMDocument $dom       dom document to add to
709
     * @param \DOMElement  $node      node to use as parent
710
     *
711
     * @return void
712
     */
713
    private function addArgumentsToService($arguments, $dom, $node)
714
    {
715
        foreach ($arguments as $argument) {
716
            $this->addArgumentToService($argument, $dom, $node);
717
        }
718
    }
719
720
    /**
721
     * add argument to service
722
     *
723
     * @param array        $argument info on argument to create
724
     * @param \DOMDocument $dom      dom document to add to
725
     * @param \DOMElement  $node     node to use as parent
726
     *
727
     * @return void
728
     */
729
    private function addArgumentToService($argument, $dom, $node)
730
    {
731
        $isService = $argument['type'] == 'service';
732
733
        if ($isService) {
734
            $argNode = $dom->createElement('argument');
735
736
            $idArg = $dom->createAttribute('id');
737
            $idArg->value = $argument['id'];
738
            $argNode->appendChild($idArg);
739
        } else {
740
            $argNode = $dom->createElement('argument', $argument['value']);
741
        }
742
743
        $argType = $dom->createAttribute('type');
744
        $argType->value = $argument['type'];
745
        $argNode->appendChild($argType);
746
747
        $node->appendChild($argNode);
748
    }
749
750
    /**
751
     * generate serializer part of a resource
752
     *
753
     * @param array  $parameters twig parameters
754
     * @param string $dir        base bundle dir
755
     * @param string $document   document name
756
     *
757
     * @return void
758
     */
759
    protected function generateSerializer(array $parameters, $dir, $document)
760
    {
761
        // @TODO in Embedded and document just render the differences..
762
        $this->renderFile(
763
            'serializer/Document.xml.twig',
764
            $dir . '/Resources/config/serializer/Document.' . $document . 'Embedded.xml',
765
            array_merge(
766
                $parameters,
767
                [
768
                    'document' => $document.'Embedded',
769
                    'noIdField' => true,
770
                    'realIdField' => true
771
                ]
772
            )
773
        );
774
775
        foreach ($parameters['fields'] as $key => $field) {
776
            if (substr($field['serializerType'], 0, 14) == 'array<Graviton' &&
777
                strpos($field['serializerType'], '\\Entity') === false &&
778
                $field['relType'] == 'embed'
779
            ) {
780
                $parameters['fields'][$key]['serializerType'] = substr($field['serializerType'], 0, -1).'Embedded>';
781
            } elseif (substr($field['serializerType'], 0, 8) == 'Graviton' &&
782
                strpos($field['serializerType'], '\\Entity') === false &&
783
                $field['relType'] == 'embed'
784
            ) {
785
                $parameters['fields'][$key]['serializerType'] = $field['serializerType'].'Embedded';
786
            }
787
        }
788
        $this->renderFile(
789
            'serializer/Document.xml.twig',
790
            $dir . '/Resources/config/serializer/Document.' . $document . '.xml',
791
            array_merge(
792
                $parameters,
793
                [
794
                    'realIdField' => false
795
                ]
796
            )
797
        );
798
        $this->renderFile(
799
            'serializer/Document.xml.twig',
800
            $dir . '/Resources/config/serializer/Document.' . $document . 'Base.xml',
801
            array_merge(
802
                $parameters,
803
                [
804
                    'document' => $document.'Base',
805
                    'realIdField' => false
806
                ]
807
            )
808
        );
809
    }
810
811
    /**
812
     * generate model part of a resource
813
     *
814
     * @param array  $parameters twig parameters
815
     * @param string $dir        base bundle dir
816
     * @param string $document   document name
817
     *
818
     * @return void
819
     */
820
    protected function generateModel(array $parameters, $dir, $document)
821
    {
822
        $this->renderFile(
823
            'model/Model.php.twig',
824
            $dir . '/Model/' . $document . '.php',
825
            $parameters
826
        );
827
        $this->renderFile(
828
            'model/schema.json.twig',
829
            $dir . '/Resources/config/schema/' . $document . '.json',
830
            $parameters
831
        );
832
833
        // embedded versions
834
        $this->renderFile(
835
            'model/Model.php.twig',
836
            $dir . '/Model/' . $document . 'Embedded.php',
837
            array_merge($parameters, ['document' => $document.'Embedded'])
838
        );
839
        $this->renderFile(
840
            'model/schema.json.twig',
841
            $dir . '/Resources/config/schema/' . $document . 'Embedded.json',
842
            array_merge($parameters, ['document' => $document.'Embedded'])
843
        );
844
845
        $this->renderFile(
846
            'validator/validation.xml.twig',
847
            $dir . '/Resources/config/validation.xml',
848
            $parameters
849
        );
850
851
        $services = $this->loadServices($dir);
852
853
        $bundleParts = explode('\\', $parameters['base']);
854
        $shortName = strtolower($bundleParts[0]);
855
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
856
        $paramName = implode('.', array($shortName, $shortBundle, 'model', strtolower($parameters['document'])));
857
        $repoName = implode('.', array($shortName, $shortBundle, 'repository', strtolower($parameters['document'])));
858
859
        $this->addXmlParameter($parameters['base'] . 'Model\\' . $parameters['document'], $paramName . '.class');
860
861
        // normal service
862
        $this->addService(
863
            $services,
864
            $paramName,
865
            'graviton.rest.model',
866
            null,
867
            array(
868
                [
869
                    'method' => 'setRepository',
870
                    'service' => $repoName
871
                ],
872
            ),
873
            null
874
        );
875
876
        // embedded service
877
        $this->addXmlParameter(
878
            $parameters['base'] . 'Model\\' . $parameters['document'] . 'Embedded',
879
            $paramName . 'embedded.class'
880
        );
881
882
        $this->addService(
883
            $services,
884
            $paramName . 'embedded',
885
            'graviton.rest.model',
886
            null,
887
            array(
888
                [
889
                    'method' => 'setRepository',
890
                    'service' => $repoName . 'embedded'
891
                ],
892
            ),
893
            null
894
        );
895
896
        $this->persistServicesXML($dir);
897
    }
898
899
    /**
900
     * generate RESTful controllers ans service configs
901
     *
902
     * @param array  $parameters twig parameters
903
     * @param string $dir        base bundle dir
904
     * @param string $document   document name
905
     *
906
     * @return void
907
     */
908
    protected function generateController(array $parameters, $dir, $document)
909
    {
910
        $this->renderFile(
911
            'controller/DocumentController.php.twig',
912
            $dir . '/Controller/' . $document . 'Controller.php',
913
            $parameters
914
        );
915
916
        $services = $this->loadServices($dir);
917
918
        $bundleParts = explode('\\', $parameters['base']);
919
        $shortName = strtolower($bundleParts[0]);
920
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
921
        $paramName = implode('.', array($shortName, $shortBundle, 'controller', strtolower($parameters['document'])));
922
923
        $this->addXmlParameter(
924
            $parameters['base'] . 'Controller\\' . $parameters['document'] . 'Controller',
925
            $paramName . '.class'
926
        );
927
928
        $this->addService(
929
            $services,
930
            $paramName,
931
            $parameters['parent'],
932
            'request',
933
            array(
934
                array(
935
                    'method' => 'setModel',
936
                    'service' => implode(
937
                        '.',
938
                        array($shortName, $shortBundle, 'model', strtolower($parameters['document']))
939
                    )
940
                )
941
            ),
942
            'graviton.rest'
943
        );
944
945
        $this->persistServicesXML($dir);
946
    }
947
948
    /**
949
     * generates fixtures
950
     *
951
     * @param array  $parameters twig parameters
952
     * @param string $dir        base bundle dir
953
     * @param string $document   document name
954
     *
955
     * @return void
956
     */
957
    protected function generateFixtures(array $parameters, $dir, $document)
958
    {
959
        $parameters['fixtures_json'] = addcslashes(json_encode($this->json->getFixtures()), "'");
960
        $parameters['fixtureOrder'] = $this->json->getFixtureOrder();
961
962
        $this->renderFile(
963
            'fixtures/LoadFixtures.php.twig',
964
            $dir . '/DataFixtures/MongoDB/Load' . $document . 'Data.php',
965
            $parameters
966
        );
967
    }
968
}
969