Completed
Pull Request — develop (#552)
by
unknown
28:27 queued 23:25
created

ResourceGenerator::addXmlParameter()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3.0416

Importance

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