Completed
Pull Request — develop (#645)
by Narcotic
126:37 queued 61:38
created

ResourceGenerator::generateDocument()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 62
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 41
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 62
ccs 41
cts 41
cp 1
rs 9.4743
c 0
b 0
f 0
cc 1
eloc 25
nc 1
nop 3
crap 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
17
/**
18
 * bundle containing various code generators
19
 *
20
 * This code is more or less loosley based on SensioBundleGenerator. It could
21
 * use some refactoring to duplicate less for that, but this is how i finally
22
 * got a working version.
23
 *
24
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
25
 * @license  https://opensource.org/licenses/MIT MIT License
26
 * @link     http://swisscom.ch
27
 */
28
class ResourceGenerator extends AbstractGenerator
29
{
30
    /**
31
     * @private Filesystem
32
     */
33
    private $filesystem;
34
35
    /**
36
     * @private HttpKernelInterface
37
     */
38
    private $kernel;
39
40
    /**
41
     * our json file definition
42
     *
43
     * @var JsonDefinition|null
44
     */
45
    private $json = null;
46
47
    /**
48
     * @var ArrayCollection
49
     */
50
    protected $xmlParameters;
51
52
    /**
53
     * @var \DomDocument
54
     */
55
    private $serviceDOM;
56
57
    /**
58
     * @var FieldMapper
59
     */
60
    private $mapper;
61
62
    /**
63
     * @var boolean
64
     */
65
    private $generateController = false;
66
67
    /**
68
     * @var ParameterBuilder
69
     */
70
    private $parameterBuilder;
71
72
    /**
73
     * Instantiates generator object
74
     *
75
     * @param Filesystem          $filesystem       fs abstraction layer
76
     * @param HttpKernelInterface $kernel           app kernel
77
     * @param FieldMapper         $mapper           field type mapper
78
     * @param ParameterBuilder    $parameterBuilder param builder
79
     */
80 2
    public function __construct(
81
        Filesystem $filesystem,
82
        HttpKernelInterface $kernel,
83
        FieldMapper $mapper,
84
        ParameterBuilder $parameterBuilder
85
    ) {
86 2
        $this->filesystem = $filesystem;
87 2
        $this->kernel = $kernel;
88 2
        $this->mapper = $mapper;
89 2
        $this->parameterBuilder = $parameterBuilder;
90 2
        $this->xmlParameters = new ArrayCollection();
91 2
    }
92
93
    /**
94
     * @param JsonDefinition $json optional JsonDefinition object
95
     *
96
     * @return void
97
     */
98
    public function setJson(JsonDefinition $json)
99
    {
100
        $this->json = $json;
101
    }
102
103
    /**
104
     * @param boolean $generateController should the controller be generated or not
105
     *
106
     * @return void
107
     */
108
    public function setGenerateController($generateController)
109
    {
110
        $this->generateController = $generateController;
111
    }
112
113
    /**
114
     * generate the resource with all its bits and parts
115
     *
116
     * @param BundleInterface $bundle   bundle
117
     * @param string          $document document name
118
     * @param string          $format   format of config files (please use xml)
119
     * @param array           $fields   fields to add
120
     *
121
     * @return EntityGeneratorResult
122
     */
123
    public function generate(
124
        BundleInterface $bundle,
125
        $document,
126
        $format,
127
        array $fields
128
    ) {
129
        $dir = $bundle->getPath();
130
        $basename = $this->getBundleBaseName($document);
131
        $bundleNamespace = substr(get_class($bundle), 0, 0 - strlen($bundle->getName()));
132
133
        if (!is_null($this->json)) {
134
            $this->json->setNamespace($bundleNamespace);
135
        }
136
137
        // add more info to the fields array
138
        $mapper = $this->mapper;
139
        $fields = array_map(
140
            function ($field) use ($mapper) {
141
                return $mapper->map($field, $this->json);
142
            },
143
            $this->mapper->buildFields($this->json)
0 ignored issues
show
Bug introduced by
It seems like $this->json can be null; however, buildFields() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

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