Completed
Push — master ( 11b317...37df4d )
by Lucas
09:27
created

ResourceGenerator   C

Complexity

Total Complexity 59

Size/Duplication

Total Lines 935
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 32.55%

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 59
lcom 1
cbo 6
dl 0
loc 935
ccs 153
cts 470
cp 0.3255
rs 5
c 2
b 0
f 1

24 Methods

Rating   Name   Duplication   Size   Complexity  
B generate() 0 51 5
C addService() 0 64 8
A __construct() 0 14 1
A setJson() 0 4 1
A setGenerateController() 0 4 1
A persistServicesXML() 0 6 1
B generateDocument() 0 40 1
B generateServices() 0 112 2
B generateParameters() 0 19 5
A addXmlParameter() 0 16 3
A loadServices() 0 11 2
A addParam() 0 14 2
A addCollectionParam() 0 20 4
A parameterNodeExists() 0 7 1
B addNodeIfMissing() 0 26 4
A addAttributeToNode() 0 8 2
A addCallsToService() 0 6 2
A addCallToService() 0 22 1
A addArgumentsToService() 0 6 2
A addArgumentToService() 0 20 2
B generateSerializer() 0 49 6
B generateModel() 0 78 1
B generateController() 0 39 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 Doctrine\Common\Collections\ArrayCollection;
9
use Graviton\GeneratorBundle\Definition\JsonDefinition;
10
use Graviton\GeneratorBundle\Generator\ResourceGenerator\FieldMapper;
11
use Graviton\GeneratorBundle\Generator\ResourceGenerator\ParameterBuilder;
12
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
13
use Symfony\Component\Filesystem\Filesystem;
14
use Symfony\Component\HttpKernel\HttpKernelInterface;
15
use Doctrine\Bundle\DoctrineBundle\Registry as DoctrineRegistry;
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
 * @todo     split all the xml handling on services.conf into a Manipulator
29
 */
30
class ResourceGenerator extends AbstractGenerator
31
{
32
    /**
33
     * @private Filesystem
34
     */
35
    private $filesystem;
36
37
    /**
38
     * @private DoctrineRegistry
39
     */
40
    private $doctrine;
41
42
    /**
43
     * @private HttpKernelInterface
44
     */
45
    private $kernel;
46
47
    /**
48
     * our json file definition
49
     *
50
     * @var JsonDefinition|null
51
     */
52
    private $json = null;
53
54
    /**
55
     * @var ArrayCollection
56
     */
57
    protected $xmlParameters;
58
59
    /**
60
     * @var \DomDocument
61
     */
62
    private $serviceDOM;
63
64
    /**
65
     * @var FieldMapper
66
     */
67
    private $mapper;
68
69
    /**
70
     * @var boolean
71
     */
72
    private $generateController = false;
73
74
    /**
75
     * @var ParameterBuilder
76
     */
77
    private $parameterBuilder;
78
79
    /**
80
     * Instantiates generator object
81
     *
82
     * @param Filesystem          $filesystem       fs abstraction layer
83
     * @param DoctrineRegistry    $doctrine         odm registry
84
     * @param HttpKernelInterface $kernel           app kernel
85
     * @param FieldMapper         $mapper           field type mapper
86
     * @param ParameterBuilder    $parameterBuilder param builder
87
     */
88 2
    public function __construct(
89
        Filesystem $filesystem,
90
        DoctrineRegistry $doctrine,
91
        HttpKernelInterface $kernel,
92
        FieldMapper $mapper,
93
        ParameterBuilder $parameterBuilder
94
    ) {
95 2
        $this->filesystem = $filesystem;
96 2
        $this->doctrine = $doctrine;
97 2
        $this->kernel = $kernel;
98 2
        $this->mapper = $mapper;
99 2
        $this->parameterBuilder = $parameterBuilder;
100 2
        $this->xmlParameters = new ArrayCollection();
101 2
    }
102
103
    /**
104
     * @param JsonDefinition $json optional JsonDefinition object
105
     *
106
     * @return void
107
     */
108
    public function setJson(JsonDefinition $json)
109
    {
110
        $this->json = $json;
111
    }
112
113
    /**
114
     * @param boolean $generateController should the controller be generated or not
115
     *
116
     * @return void
117
     */
118
    public function setGenerateController($generateController)
119
    {
120
        $this->generateController = $generateController;
121
    }
122
123
    /**
124
     * generate the resource with all its bits and parts
125
     *
126
     * @param BundleInterface $bundle         bundle
127
     * @param string          $document       document name
128
     * @param string          $format         format of config files (please use xml)
129
     * @param array           $fields         fields to add
130
     * @param boolean         $withRepository generate repository class
131
     *
132
     * @return void
133
     */
134
    public function generate(
135
        BundleInterface $bundle,
136
        $document,
137
        $format,
138
        array $fields,
139
        $withRepository
140
    ) {
141
        $dir = $bundle->getPath();
142
        $basename = $this->getBundleBaseName($document);
143
        $bundleNamespace = substr(get_class($bundle), 0, 0 - strlen($bundle->getName()));
144
145
        if (!is_null($this->json)) {
146
            $this->json->setNamespace($bundleNamespace);
147
        }
148
149
        // add more info to the fields array
150
        $mapper = $this->mapper;
151
        $fields = array_map(
152
            function ($field) use ($mapper) {
153
                return $mapper->map($field, $this->json);
154
            },
155
            $fields
156
        );
157
        $parameters = $this->parameterBuilder
158
            ->setParameter('document', $document)
159
            ->setParameter('base', $bundleNamespace)
160
            ->setParameter('bundle', $bundle->getName())
161
            ->setParameter('format', $format)
162
            ->setParameter('json', $this->json)
163
            ->setParameter('fields', $fields)
164
            ->setParameter('basename', $basename)
165
            ->setParameter('isrecordOriginFlagSet', $this->json->isRecordOriginFlagSet())
166
            ->setParameter('recordOriginModifiable', $this->json->isRecordOriginModifiable())
167
            ->setParameter('collection', $this->json->getServiceCollection())
168
            ->setParameter('indexes', $this->json->getIndexes())
169
            ->getParameters();
170
171
        $this->generateDocument($parameters, $dir, $document, $withRepository);
172
        $this->generateSerializer($parameters, $dir, $document);
173
        $this->generateModel($parameters, $dir, $document);
174
175
        if ($this->json instanceof JsonDefinition && $this->json->hasFixtures() === true) {
176
            $this->generateFixtures($parameters, $dir, $document);
177
        }
178
179
        if ($this->generateController) {
180
            $this->generateController($parameters, $dir, $document);
181
        }
182
183
        $this->generateParameters($dir);
184
    }
185
186
    /**
187
     * Writes the current services definition to a file.
188
     *
189
     * @param string $dir base bundle dir
190
     *
191
     * @return void
192
     */
193 8
    protected function persistServicesXML($dir)
194
    {
195 8
        $services = $this->loadServices($dir);
196
197 8
        file_put_contents($dir . '/Resources/config/services.xml', $services->saveXML());
198 8
    }
199
200
    /**
201
     * generate document part of a resource
202
     *
203
     * @param array   $parameters     twig parameters
204
     * @param string  $dir            base bundle dir
205
     * @param string  $document       document name
206
     * @param boolean $withRepository generate repository class
207
     *
208
     * @return void
209
     */
210 6
    protected function generateDocument($parameters, $dir, $document, $withRepository)
211
    {
212
        // doctrine mapping normal class
213 6
        $this->renderFile(
214 6
            'document/Document.mongodb.xml.twig',
215 6
            $dir . '/Resources/config/doctrine/' . $document . '.mongodb.xml',
216
            $parameters
217 3
        );
218
219
        // doctrine mapping embedded
220 6
        $this->renderFile(
221 6
            'document/Document.mongodb.xml.twig',
222 6
            $dir . '/Resources/config/doctrine/' . $document . 'Embedded.mongodb.xml',
223 3
            array_merge(
224 3
                $parameters,
225
                [
226 6
                    'document' => $document.'Embedded',
227 3
                    'docType' => 'embedded-document'
228 3
                ]
229 3
            )
230 3
        );
231
232 6
        $this->renderFile(
233 6
            'document/Document.php.twig',
234 6
            $dir . '/Document/' . $document . '.php',
235
            $parameters
236 3
        );
237 6
        $this->renderFile(
238 6
            'document/DocumentEmbedded.php.twig',
239 6
            $dir . '/Document/' . $document . 'Embedded.php',
240
            $parameters
241 3
        );
242 6
        $this->renderFile(
243 6
            'document/DocumentBase.php.twig',
244 6
            $dir . '/Document/' . $document . 'Base.php',
245
            $parameters
246 3
        );
247
248 6
        $this->generateServices($parameters, $dir, $document, $withRepository);
249 6
    }
250
251
    /**
252
     * update xml services
253
     *
254
     * @param array   $parameters     twig parameters
255
     * @param string  $dir            base bundle dir
256
     * @param string  $document       document name
257
     * @param boolean $withRepository generate repository class
258
     *
259
     * @return void
260
     */
261 6
    protected function generateServices($parameters, $dir, $document, $withRepository)
262
    {
263 6
        $services = $this->loadServices($dir);
264
265 6
        $bundleParts = explode('\\', $parameters['base']);
266 6
        $shortName = $bundleParts[0];
267 6
        $shortBundle = $this->getBundleBaseName($bundleParts[1]);
268
269 6
        $docName = implode(
270 6
            '.',
271
            array(
272 6
                strtolower($shortName),
273 6
                strtolower($shortBundle),
274 6
                'document',
275 6
                strtolower($parameters['document'])
276 3
            )
277 3
        );
278
279 6
        $this->addXMLParameter(
280 6
            $parameters['base'] . 'Document\\' . $parameters['document'],
281 3
            $docName . '.class'
282 3
        );
283
284 6
        $this->addXMLParameter(
285 6
            $parameters['json']->getRoles(),
286 6
            $docName . '.roles',
287 3
            'collection'
288 3
        );
289
290 6
        $services = $this->addService(
291 3
            $services,
292
            $docName
293 3
        );
294
295 6
        if ($withRepository) {
296
            $repoName = implode(
297
                '.',
298
                array(
299
                    strtolower($shortName),
300
                    strtolower($shortBundle),
301
                    'repository',
302
                    strtolower($parameters['document'])
303
                )
304
            );
305
306
            // normal repo service
307
            $services = $this->addParam(
308
                $services,
309
                $repoName . '.class',
310
                $parameters['base'] . 'Repository\\' . $parameters['document']
311
            );
312
313
            $this->addService(
314
                $services,
315
                $repoName,
316
                null,
317
                null,
318
                array(),
319
                null,
320
                array(
321
                    array(
322
                        'type' => 'string',
323
                        'value' => $parameters['bundle'] . ':' . $document
324
                    )
325
                ),
326
                'doctrine_mongodb.odm.default_document_manager',
327
                'getRepository'
328
            );
329
330
            // embedded repo service
331
            $services = $this->addParam(
332
                $services,
333
                $repoName . 'embedded.class',
334
                $parameters['base'] . 'Repository\\' . $parameters['document'] . 'Embedded'
335
            );
336
337
            $this->addService(
338
                $services,
339
                $repoName . 'embedded',
340
                null,
341
                null,
342
                array(),
343
                null,
344
                array(
345
                    array(
346
                        'type' => 'string',
347
                        'value' => $parameters['bundle'] . ':' . $document . 'Embedded'
348
                    )
349
                ),
350
                'doctrine_mongodb.odm.default_document_manager',
351
                'getRepository'
352
            );
353
354
            $this->renderFile(
355
                'document/DocumentRepository.php.twig',
356
                $dir . '/Repository/' . $document . 'Repository.php',
357
                $parameters
358
            );
359
            $this->renderFile(
360
                'document/DocumentRepository.php.twig',
361
                $dir . '/Repository/' . $document . 'EmbeddedRepository.php',
362
                array_merge(
363
                    $parameters,
364
                    [
365
                        'document' => $document.'Embedded',
366
                    ]
367
                )
368
            );
369
        }
370
371 6
        $this->persistServicesXML($dir);
372 6
    }
373
374
    /**
375
     * Generates the parameters section of the services.xml file.
376
     *
377
     * @param string $dir base bundle dir
378
     *
379
     * @return void
380
     */
381 2
    protected function generateParameters($dir)
382
    {
383 2
        if ($this->xmlParameters->count() > 0) {
384 2
            $services = $this->loadServices($dir);
385
386 2
            foreach ($this->xmlParameters as $parameter) {
387 2
                switch ($parameter['type']) {
388 2
                    case 'collection':
389 2
                        $this->addCollectionParam($services, $parameter['key'], $parameter['content']);
390 2
                        break;
391 2
                    case 'string':
392 1
                    default:
393 2
                        $this->addParam($services, $parameter['key'], $parameter['content']);
394 1
                }
395 1
            }
396 1
        }
397
398 2
        $this->persistServicesXML($dir);
399 2
    }
400
401
    /**
402
     * Registers information to be generated to a parameter tag.
403
     *
404
     * @param mixed  $value Content of the tag
405
     * @param string $key   Content of the key attribute
406
     * @param string $type  Type of the tag
407
     *
408
     * @return void
409
     */
410 2
    protected function addXmlParameter($value, $key, $type = 'string')
411
    {
412
        $element = array(
413 2
            'content' => $value,
414 2
            'key' => $key,
415 2
            'type' => strtolower($type),
416 1
        );
417
418 2
        if (!isset($this->xmlParameters)) {
419
            $this->xmlParameters = new ArrayCollection();
420
        }
421
422 2
        if (!$this->xmlParameters->contains($element)) {
423 2
            $this->xmlParameters->add($element);
424 1
        }
425 2
    }
426
427
    /**
428
     * load services.xml
429
     *
430
     * @param string $dir base dir
431
     *
432
     * @return \DOMDocument
433
     */
434 4
    protected function loadServices($dir)
435
    {
436 4
        if (empty($this->serviceDOM)) {
437 4
            $this->serviceDOM = new \DOMDocument;
438 4
            $this->serviceDOM->formatOutput = true;
439 4
            $this->serviceDOM->preserveWhiteSpace = false;
440 4
            $this->serviceDOM->load($dir . '/Resources/config/services.xml');
441 2
        }
442
443 4
        return $this->serviceDOM;
444
    }
445
446
    /**
447
     * add param to services.xml
448
     *
449
     * @param \DOMDocument $dom   services.xml document
450
     * @param string       $key   parameter key
451
     * @param string       $value parameter value
452
     *
453
     * @return \DOMDocument
454
     */
455 6
    protected function addParam(\DOMDocument $dom, $key, $value)
456
    {
457 6
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
458
459 6
        if (!$this->parameterNodeExists($dom, $key)) {
460 6
            $attrNode = $dom->createElement('parameter', $value);
461
462 6
            $this->addAttributeToNode('key', $key, $dom, $attrNode);
463
464 6
            $paramNode->appendChild($attrNode);
465 3
        }
466
467 6
        return $dom;
468
    }
469
470
    /**
471
     * Adds a new parameter tag to parameters section reflecting the defined roles.
472
     *
473
     * @param \DOMDocument $dom    services.xml document
474
     * @param string       $key    parameter key
475
     * @param array        $values parameter value
476
     *
477
     * @return void
478
     *
479
     * @link http://symfony.com/doc/current/book/service_container.html#array-parameters
480
     */
481 4
    protected function addCollectionParam(\DomDocument $dom, $key, array $values)
482
    {
483 4
        $paramNode = $this->addNodeIfMissing($dom, 'parameters', '//services');
484
485 4
        if (!$this->parameterNodeExists($dom, $key)) {
486 4
            if (!empty($values)) {
487 4
                $rolesNode = $dom->createElement('parameter');
488 4
                $this->addAttributeToNode('key', $key, $dom, $rolesNode);
489 4
                $this->addAttributeToNode('type', 'collection', $dom, $rolesNode);
490
491 4
                foreach ($values as $item) {
492 4
                    $roleNode = $dom->createElement('parameter', $item);
493 4
                    $rolesNode->appendChild($roleNode);
494 2
                }
495
496 4
                $paramNode->appendChild($rolesNode);
497 2
            }
498 2
        }
499
500 4
    }
501
502
    /**
503
     * Determines, if the provided key attribute was already claimed by a parameter node.
504
     *
505
     * @param \DomDocument $dom Current document
506
     * @param string       $key Key to be found in document
507
     *
508
     * @return bool
509
     */
510 8
    private function parameterNodeExists(\DomDocument $dom, $key)
0 ignored issues
show
Coding Style introduced by
function parameterNodeExists() does not seem to conform to the naming convention (^(?:is|has|should|may|supports)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
511
    {
512 8
        $xpath = new \DomXpath($dom);
513 8
        $nodes = $xpath->query('//parameters/parameter[@key="' . $key . '"]');
514
515 8
        return $nodes->length > 0;
516
    }
517
518
    /**
519
     * add node if missing
520
     *
521
     * @param \DOMDocument $dom          document
522
     * @param string       $element      name for new node element
523
     * @param string       $insertBefore xPath query of the new node shall be added before
524
     * @param string       $container    name of container tag
525
     *
526
     * @return \DOMNode new element node
527
     */
528 8
    private function addNodeIfMissing(&$dom, $element, $insertBefore = '', $container = 'container')
529
    {
530 8
        $container = $dom->getElementsByTagName($container)
531 8
            ->item(0);
532 8
        $nodes = $dom->getElementsByTagName($element);
533 8
        if ($nodes->length < 1) {
534 8
            $newNode = $dom->createElement($element);
535
536 8
            if (!empty($insertBefore)) {
537 8
                $xpath = new \DomXpath($dom);
538 8
                $found = $xpath->query($insertBefore);
539
540 8
                if ($found->length > 0) {
541
                    $container->insertBefore($newNode, $found->item(0));
542
                } else {
543 8
                    $container->appendChild($newNode);
544
                }
545 4
            } else {
546 4
                $container->appendChild($newNode);
547
            }
548 4
        } else {
549 4
            $newNode = $nodes->item(0);
550
        }
551
552 8
        return $newNode;
553
    }
554
555
    /**
556
     * add attribute to node if needed
557
     *
558
     * @param string       $name  attribute name
559
     * @param string       $value attribute value
560
     * @param \DOMDocument $dom   document
561
     * @param \DOMElement  $node  parent node
562
     *
563
     * @return void
564
     */
565 8
    private function addAttributeToNode($name, $value, $dom, $node)
566
    {
567 8
        if ($value) {
568 8
            $attr = $dom->createAttribute($name);
569 8
            $attr->value = $value;
570 8
            $node->appendChild($attr);
571 4
        }
572 8
    }
573
574
    /**
575
     * add service to services.xml
576
     *
577
     * @param \DOMDocument $dom            services.xml dom
578
     * @param string       $id             id of new service
579
     * @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...
580
     * @param string       $scope          scope of service
0 ignored issues
show
Documentation introduced by
Should the type for parameter $scope not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

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