Completed
Pull Request — develop (#639)
by Narcotic
18:41 queued 12:22
created

ResourceGenerator   C

Complexity

Total Complexity 60

Size/Duplication

Total Lines 918
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 44.5%

Importance

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

24 Methods

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

How to fix   Complexity   

Complex Class

Complex classes like ResourceGenerator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ResourceGenerator, and based on these observations, apply Extract Interface, too.

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