Completed
Push — master ( 714b6a...f9d007 )
by Narcotic
06:13
created

ResourceGenerator   C

Complexity

Total Complexity 60

Size/Duplication

Total Lines 917
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 44.62%

Importance

Changes 0
Metric Value
wmc 60
lcom 1
cbo 7
dl 0
loc 917
ccs 174
cts 390
cp 0.4462
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 generateServices() 0 108 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
C addService() 0 62 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  http://opensource.org/licenses/gpl-license.php GNU Public 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 4
    public function __construct(
81
        Filesystem $filesystem,
82
        HttpKernelInterface $kernel,
83
        FieldMapper $mapper,
84
        ParameterBuilder $parameterBuilder
85
    ) {
86 4
        $this->filesystem = $filesystem;
87 4
        $this->kernel = $kernel;
88 4
        $this->mapper = $mapper;
89 4
        $this->parameterBuilder = $parameterBuilder;
90 4
        $this->xmlParameters = new ArrayCollection();
91 4
    }
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
            array(),
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
            array(),
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 = array(),
583
        $tag = null,
584
        array $arguments = array(),
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('class', '%' . $id . '.class%', $dom, $attrNode);
599
            $this->addAttributeToNode('parent', $parent, $dom, $attrNode);
600
            if ($factoryService && $factoryMethod) {
601
                $factoryNode = $dom->createElement('factory');
602
                $this->addAttributeToNode('service', $factoryService, $dom, $factoryNode);
603
                $this->addAttributeToNode('method', $factoryMethod, $dom, $factoryNode);
604
                $attrNode->appendChild($factoryNode);
605
            }
606
            $this->addCallsToService($calls, $dom, $attrNode);
607
608
            if ($tag) {
609
                $tagNode = $dom->createElement('tag');
610
611
                $this->addAttributeToNode('name', $tag, $dom, $tagNode);
612
613
                // get stuff from json definition
614
                if ($this->json instanceof JsonDefinition) {
615
                    // id is also name of collection in mongodb
616
                    $this->addAttributeToNode('collection', $this->json->getId(), $dom, $tagNode);
617
618
                    // is this read only?
619
                    if ($this->json->isReadOnlyService()) {
620
                        $this->addAttributeToNode('read-only', 'true', $dom, $tagNode);
621
                    }
622
623
                    // router base defined?
624
                    $routerBase = $this->json->getRouterBase();
625
                    if ($routerBase !== false) {
626
                        $this->addAttributeToNode('router-base', $routerBase, $dom, $tagNode);
627
                    }
628
                }
629
630
                $attrNode->appendChild($tagNode);
631
            }
632
633
            $this->addArgumentsToService($arguments, $dom, $attrNode);
634
635
            $servicesNode->appendChild($attrNode);
636
        }
637
638
        return $dom;
639
    }
640
641
    /**
642
     * add calls to service
643
     *
644
     * @param array        $calls info on calls to create
645
     * @param \DOMDocument $dom   current domdocument
646
     * @param \DOMElement  $node  node to add call to
647
     *
648
     * @return void
649
     */
650
    private function addCallsToService($calls, $dom, $node)
651
    {
652
        foreach ($calls as $call) {
653
            $this->addCallToService($call, $dom, $node);
654
        }
655
    }
656
657
    /**
658
     * add call to service
659
     *
660
     * @param array        $call info on call node 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 addCallToService($call, $dom, $node)
667
    {
668
        $callNode = $dom->createElement('call');
669
670
        $attr = $dom->createAttribute('method');
671
        $attr->value = $call['method'];
672
        $callNode->appendChild($attr);
673
674
        $argNode = $dom->createElement('argument');
675
676
        $attr = $dom->createAttribute('type');
677
        $attr->value = 'service';
678
        $argNode->appendChild($attr);
679
680
        $attr = $dom->createAttribute('id');
681
        $attr->value = $call['service'];
682
        $argNode->appendChild($attr);
683
684
        $callNode->appendChild($argNode);
685
686
        $node->appendChild($callNode);
687
    }
688
689
    /**
690
     * add arguments to servie
691
     *
692
     * @param array        $arguments arguments to create
693
     * @param \DOMDocument $dom       dom document to add to
694
     * @param \DOMElement  $node      node to use as parent
695
     *
696
     * @return void
697
     */
698
    private function addArgumentsToService($arguments, $dom, $node)
699
    {
700
        foreach ($arguments as $argument) {
701
            $this->addArgumentToService($argument, $dom, $node);
702
        }
703
    }
704
705
    /**
706
     * add argument to service
707
     *
708
     * @param array        $argument info on argument 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 addArgumentToService($argument, $dom, $node)
715
    {
716
        $isService = $argument['type'] == 'service';
717
718
        if ($isService) {
719
            $argNode = $dom->createElement('argument');
720
721
            $idArg = $dom->createAttribute('id');
722
            $idArg->value = $argument['id'];
723
            $argNode->appendChild($idArg);
724
        } else {
725
            $argNode = $dom->createElement('argument', $argument['value']);
726
        }
727
728
        $argType = $dom->createAttribute('type');
729
        $argType->value = $argument['type'];
730
        $argNode->appendChild($argType);
731
732
        $node->appendChild($argNode);
733
    }
734
735
    /**
736
     * generate serializer part of a resource
737
     *
738
     * @param array  $parameters twig parameters
739
     * @param string $dir        base bundle dir
740
     * @param string $document   document name
741
     *
742
     * @return void
743
     */
744
    protected function generateSerializer(array $parameters, $dir, $document)
745
    {
746
        // @TODO in Embedded and document just render the differences..
747
        $this->renderFile(
748
            'serializer/Document.xml.twig',
749
            $dir . '/Resources/config/serializer/Document.' . $document . 'Embedded.xml',
750
            array_merge(
751
                $parameters,
752
                [
753
                    'document' => $document.'Embedded',
754
                    'noIdField' => true,
755
                    'realIdField' => true
756
                ]
757
            )
758
        );
759
760
        foreach ($parameters['fields'] as $key => $field) {
761
            if (substr($field['serializerType'], 0, 14) == 'array<Graviton' &&
762
                strpos($field['serializerType'], '\\Entity') === false &&
763
                $field['relType'] == 'embed'
764
            ) {
765
                $parameters['fields'][$key]['serializerType'] = substr($field['serializerType'], 0, -1).'Embedded>';
766
            } elseif (substr($field['serializerType'], 0, 8) == 'Graviton' &&
767
                strpos($field['serializerType'], '\\Entity') === false &&
768
                $field['relType'] == 'embed'
769
            ) {
770
                $parameters['fields'][$key]['serializerType'] = $field['serializerType'].'Embedded';
771
            }
772
        }
773
        $this->renderFile(
774
            'serializer/Document.xml.twig',
775
            $dir . '/Resources/config/serializer/Document.' . $document . '.xml',
776
            array_merge(
777
                $parameters,
778
                [
779
                    'realIdField' => false
780
                ]
781
            )
782
        );
783
        $this->renderFile(
784
            'serializer/Document.xml.twig',
785
            $dir . '/Resources/config/serializer/Document.' . $document . 'Base.xml',
786
            array_merge(
787
                $parameters,
788
                [
789
                    'document' => $document.'Base',
790
                    'realIdField' => false
791
                ]
792
            )
793
        );
794
    }
795
796
    /**
797
     * generate model part of a resource
798
     *
799
     * @param array  $parameters twig parameters
800
     * @param string $dir        base bundle dir
801
     * @param string $document   document name
802
     *
803
     * @return void
804
     */
805
    protected function generateModel(array $parameters, $dir, $document)
806
    {
807
        $this->renderFile(
808
            'model/Model.php.twig',
809
            $dir . '/Model/' . $document . '.php',
810
            $parameters
811
        );
812
        $this->renderFile(
813
            'model/schema.json.twig',
814
            $dir . '/Resources/config/schema/' . $document . '.json',
815
            $parameters
816
        );
817
818
        // embedded versions
819
        $this->renderFile(
820
            'model/Model.php.twig',
821
            $dir . '/Model/' . $document . 'Embedded.php',
822
            array_merge($parameters, ['document' => $document.'Embedded'])
823
        );
824
        $this->renderFile(
825
            'model/schema.json.twig',
826
            $dir . '/Resources/config/schema/' . $document . 'Embedded.json',
827
            array_merge($parameters, ['document' => $document.'Embedded'])
828
        );
829
830
        $services = $this->loadServices($dir);
831
832
        $bundleParts = explode('\\', $parameters['base']);
833
        $shortName = strtolower($bundleParts[0]);
834
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
835
        $paramName = implode('.', array($shortName, $shortBundle, 'model', strtolower($parameters['document'])));
836
        $repoName = implode('.', array($shortName, $shortBundle, 'repository', strtolower($parameters['document'])));
837
838
        $this->addXmlParameter($parameters['base'] . 'Model\\' . $parameters['document'], $paramName . '.class');
839
840
        // normal service
841
        $this->addService(
842
            $services,
843
            $paramName,
844
            'graviton.rest.model',
845
            array(
846
                [
847
                    'method' => 'setRepository',
848
                    'service' => $repoName
849
                ],
850
            ),
851
            null
852
        );
853
854
        // embedded service
855
        $this->addXmlParameter(
856
            $parameters['base'] . 'Model\\' . $parameters['document'] . 'Embedded',
857
            $paramName . 'embedded.class'
858
        );
859
860
        $this->addService(
861
            $services,
862
            $paramName . 'embedded',
863
            'graviton.rest.model',
864
            array(
865
                [
866
                    'method' => 'setRepository',
867
                    'service' => $repoName . 'embedded'
868
                ],
869
            ),
870
            null
871
        );
872
873
        $this->persistServicesXML($dir);
874
    }
875
876
    /**
877
     * generate RESTful controllers ans service configs
878
     *
879
     * @param array  $parameters twig parameters
880
     * @param string $dir        base bundle dir
881
     * @param string $document   document name
882
     *
883
     * @return void
884
     */
885
    protected function generateController(array $parameters, $dir, $document)
886
    {
887
        $this->renderFile(
888
            'controller/DocumentController.php.twig',
889
            $dir . '/Controller/' . $document . 'Controller.php',
890
            $parameters
891
        );
892
893
        $services = $this->loadServices($dir);
894
895
        $bundleParts = explode('\\', $parameters['base']);
896
        $shortName = strtolower($bundleParts[0]);
897
        $shortBundle = strtolower(substr($bundleParts[1], 0, -6));
898
        $paramName = implode('.', array($shortName, $shortBundle, 'controller', strtolower($parameters['document'])));
899
900
        $this->addXmlParameter(
901
            $parameters['base'] . 'Controller\\' . $parameters['document'] . 'Controller',
902
            $paramName . '.class'
903
        );
904
905
        $this->addService(
906
            $services,
907
            $paramName,
908
            $parameters['parent'],
909
            array(
910
                array(
911
                    'method' => 'setModel',
912
                    'service' => implode(
913
                        '.',
914
                        array($shortName, $shortBundle, 'model', strtolower($parameters['document']))
915
                    )
916
                )
917
            ),
918
            'graviton.rest'
919
        );
920
921
        $this->persistServicesXML($dir);
922
    }
923
924
    /**
925
     * generates fixtures
926
     *
927
     * @param array  $parameters twig parameters
928
     * @param string $dir        base bundle dir
929
     * @param string $document   document name
930
     *
931
     * @return void
932
     */
933
    protected function generateFixtures(array $parameters, $dir, $document)
934
    {
935
        $parameters['fixtures_json'] = addcslashes(json_encode($this->json->getFixtures()), "'");
936
        $parameters['fixtureOrder'] = $this->json->getFixtureOrder();
937
938
        $this->renderFile(
939
            'fixtures/LoadFixtures.php.twig',
940
            $dir . '/DataFixtures/MongoDB/Load' . $document . 'Data.php',
941
            $parameters
942
        );
943
    }
944
}
945