Completed
Push — feature/EVO-7964_fundInfo-exte... ( cf9459...eda009 )
by Bastian
15:13 queued 08:52
created

GenerateDynamicBundleCommand::getTemplateHash()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 0
cts 9
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 0
crap 6
1
<?php
2
/**
3
 * generate dynamic bundles
4
 */
5
6
namespace Graviton\GeneratorBundle\Command;
7
8
use Graviton\GeneratorBundle\CommandRunner;
9
use Graviton\GeneratorBundle\Definition\JsonDefinition;
10
use Graviton\GeneratorBundle\Definition\JsonDefinitionArray;
11
use Graviton\GeneratorBundle\Definition\JsonDefinitionHash;
12
use Graviton\GeneratorBundle\Generator\DynamicBundleBundleGenerator;
13
use Graviton\GeneratorBundle\Manipulator\File\XmlManipulator;
14
use Graviton\GeneratorBundle\Definition\Loader\LoaderInterface;
15
use JMS\Serializer\SerializerInterface;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputInterface;
18
use Symfony\Component\Console\Input\InputOption;
19
use Symfony\Component\Console\Output\OutputInterface;
20
use Symfony\Component\Filesystem\Filesystem;
21
use Symfony\Component\Finder\Finder;
22
use Symfony\Component\Finder\SplFileInfo;
23
24
/**
25
 * Here, we generate all "dynamic" Graviton bundles..
26
 *
27
 * @todo     create a new Application in-situ
28
 * @todo     see if we can get rid of container dependency..
29
 *
30
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
31
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
32
 * @link     http://swisscom.ch
33
 */
34
class GenerateDynamicBundleCommand extends Command
35
{
36
37
    /** @var  string */
38
    const BUNDLE_NAMESPACE = 'GravitonDyn';
39
40
    /** @var  string */
41
    const BUNDLE_NAME_MASK = self::BUNDLE_NAMESPACE.'/%sBundle';
42
43
    /** @var  string */
44
    const GENERATION_HASHFILE_FILENAME = 'genhash';
45
46
    /** @var  string */
47
    private $bundleBundleNamespace;
48
49
    /** @var  string */
50
    private $bundleBundleDir;
51
52
    /** @var  string */
53
    private $bundleBundleClassname;
54
55
    /** @var  string */
56
    private $bundleBundleClassfile;
57
58
    /** @var  array */
59
    private $bundleBundleList = [];
60
61
    /** @var array|null */
62
    private $bundleAdditions = null;
63
64
    /** @var array|null */
65
    private $serviceWhitelist = null;
66
67
    /**
68
     * @var CommandRunner
69
     */
70
    private $runner;
71
    /**
72
     * @var LoaderInterface
73
     */
74
    private $definitionLoader;
75
    /**
76
     * @var XmlManipulator
77
     */
78
    private $xmlManipulator;
79
    /**
80
     * @var SerializerInterface
81
     */
82
    private $serializer;
83
84
85
    /**
86
     * @param CommandRunner       $runner           Runs a console command.
87
     * @param XmlManipulator      $xmlManipulator   Helper to change the content of a xml file.
88
     * @param LoaderInterface     $definitionLoader JSON definition loader
89
     * @param SerializerInterface $serializer       Serializer
90
     * @param string|null         $bundleAdditions  Additional bundles list in JSON format
91
     * @param string|null         $serviceWhitelist Service whitelist in JSON format
92
     * @param string|null         $name             The name of the command; passing null means it must be set in
93
     *                                              configure()
94
     */
95 6
    public function __construct(
96
        CommandRunner       $runner,
97
        XmlManipulator      $xmlManipulator,
98
        LoaderInterface     $definitionLoader,
99
        SerializerInterface $serializer,
100
        $bundleAdditions = null,
101
        $serviceWhitelist = null,
102
        $name = null
103
    ) {
104 6
        parent::__construct($name);
105
106 6
        $this->runner = $runner;
107 6
        $this->xmlManipulator = $xmlManipulator;
108 6
        $this->definitionLoader = $definitionLoader;
109 6
        $this->serializer = $serializer;
110
111 6
        if ($bundleAdditions !== null && $bundleAdditions !== '') {
112
            $this->bundleAdditions = $bundleAdditions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $bundleAdditions of type string is incompatible with the declared type array|null of property $bundleAdditions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
113
        }
114 6
        if ($serviceWhitelist !== null && $serviceWhitelist !== '') {
115
            $this->serviceWhitelist = $serviceWhitelist;
0 ignored issues
show
Documentation Bug introduced by
It seems like $serviceWhitelist of type string is incompatible with the declared type array|null of property $serviceWhitelist.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
116
        }
117 6
    }
118
119
    /**
120
     * {@inheritDoc}
121
     *
122
     * @return void
123
     */
124 6
    protected function configure()
125
    {
126 6
        parent::configure();
127
128 6
        $this->addOption(
129 6
            'json',
130 6
            '',
131 6
            InputOption::VALUE_OPTIONAL,
132 3
            'Path to the json definition.'
133 3
        )
134 6
            ->addOption(
135 6
                'srcDir',
136 6
                '',
137 6
                InputOption::VALUE_OPTIONAL,
138 6
                'Src Dir',
139 6
                dirname(__FILE__) . '/../../../'
140 3
            )
141 6
            ->addOption(
142 6
                'bundleBundleName',
143 6
                '',
144 6
                InputOption::VALUE_OPTIONAL,
145 6
                'Which BundleBundle to manipulate to add our stuff',
146 3
                'GravitonDynBundleBundle'
147 3
            )
148 6
            ->addOption(
149 6
                'bundleFormat',
150 6
                '',
151 6
                InputOption::VALUE_OPTIONAL,
152 6
                'Which format',
153 3
                'xml'
154 3
            )
155 6
            ->setName('graviton:generate:dynamicbundles')
156 6
            ->setDescription(
157
                'Generates all dynamic bundles in the GravitonDyn namespace. Either give a path
158 3
                    to a single JSON file or a directory path containing multiple files.'
159 3
            );
160 6
    }
161
162
    /**
163
     * {@inheritDoc}
164
     *
165
     * @param InputInterface  $input  input
166
     * @param OutputInterface $output output
167
     *
168
     * @return void
169
     */
170 2
    protected function execute(InputInterface $input, OutputInterface $output)
171
    {
172
        /**
173
         * GENERATE THE BUNDLEBUNDLE
174
         */
175 2
        $namespace = sprintf(self::BUNDLE_NAME_MASK, 'Bundle');
176
177
        // GravitonDynBundleBundle
178 2
        $bundleName = str_replace('/', '', $namespace);
179
180
        // bundlebundle stuff..
181 2
        $this->bundleBundleNamespace = $namespace;
182 2
        $this->bundleBundleDir = $input->getOption('srcDir') . $namespace;
183 2
        $this->bundleBundleClassname = $bundleName;
184 2
        $this->bundleBundleClassfile = $this->bundleBundleDir . '/' . $this->bundleBundleClassname . '.php';
185
186 2
        $filesToWorkOn = $this->definitionLoader->load($input->getOption('json'));
187
188 2
        if (count($filesToWorkOn) < 1) {
189 2
            throw new \LogicException("Could not find any usable JSON files.");
190
        }
191
192
        $fs = new Filesystem();
193
194
        $this->createInitialBundleBundle($input->getOption('srcDir'));
195
196
        $templateHash = $this->getTemplateHash();
197
        $existingBundles = $this->getExistingBundleHashes($input->getOption('srcDir'));
198
199
        /**
200
         * GENERATE THE BUNDLE(S)
201
         */
202
        foreach ($filesToWorkOn as $jsonDef) {
203
            $thisIdName = $jsonDef->getId();
204
            $namespace = sprintf(self::BUNDLE_NAME_MASK, $thisIdName);
205
206
            $jsonDef->setNamespace($namespace);
207
208
            $bundleName = str_replace('/', '', $namespace);
209
            $this->bundleBundleList[] = $namespace;
210
211
            try {
212
                $bundleDir = $input->getOption('srcDir').$namespace;
213
                $thisHash = sha1($templateHash.PATH_SEPARATOR.serialize($jsonDef));
214
215
                $needsGeneration = true;
216
                if (isset($existingBundles[$bundleDir])) {
217
                    if ($existingBundles[$bundleDir] == $thisHash) {
218
                        $needsGeneration = false;
219
                    }
220
                    unset($existingBundles[$bundleDir]);
221
                }
222
223
                if ($needsGeneration) {
224
                    $this->generateBundle($namespace, $bundleName, $input, $output, $bundleDir);
225
                    $this->generateGenerationHashFile($bundleDir, $thisHash);
226
                }
227
228
                $this->generateBundleBundleClass();
229
230
                if ($needsGeneration) {
231
                    $this->generateSubResources($output, $jsonDef, $this->xmlManipulator, $bundleName, $namespace);
232
                    $this->generateMainResource($output, $jsonDef, $bundleName);
233
                    $this->generateValidationXml(
234
                        $this->xmlManipulator,
235
                        $this->getGeneratedValidationXmlPath($namespace)
236
                    );
237
238
                    $output->write(
239
                        PHP_EOL.
240
                        sprintf('<info>Generated "%s" from definition %s</info>', $bundleName, $jsonDef->getId()).
241
                        PHP_EOL
242
                    );
243
                } else {
244
                    $output->write(
245
                        PHP_EOL.
246
                        sprintf('<info>Using pre-existing "%s"</info>', $bundleName).
247
                        PHP_EOL
248
                    );
249
                }
250
            } catch (\Exception $e) {
251
                $output->writeln(
252
                    sprintf('<error>%s</error>', $e->getMessage())
253
                );
254
255
                // remove failed bundle from list
256
                array_pop($this->bundleBundleList);
257
            }
258
259
            $this->xmlManipulator->reset();
260
        }
261
262
        // whatever is left in $existingBundles is not defined anymore and needs to be deleted..
263
        foreach ($existingBundles as $dirName => $hash) {
264
            $fs->remove($dirName);
265
            $output->write(
266
                PHP_EOL.
267
                sprintf('<info>Deleted obsolete bundle "%s"</info>', $dirName).
268
                PHP_EOL
269
            );
270
        }
271
    }
272
273
    /**
274
     * scans through all existing dynamic bundles, checks if there is a generation hash and collect that
275
     * all in an array that can be used for fast checking.
276
     *
277
     * @param string $baseDir base directory of dynamic bundles
278
     *
279
     * @return array key is bundlepath, value is the current hash
280
     */
281
    private function getExistingBundleHashes($baseDir)
282
    {
283
        $existingBundles = [];
284
        $fs = new Filesystem();
285
        $bundleBaseDir = $baseDir.self::BUNDLE_NAMESPACE;
286
287
        if (!$fs->exists($bundleBaseDir)) {
288
            return $existingBundles;
289
        }
290
291
        $bundleFinder = $this->getBundleFinder($baseDir);
292
293
        foreach ($bundleFinder as $bundleDir) {
0 ignored issues
show
Bug introduced by
The expression $bundleFinder of type null|object<Symfony\Component\Finder\Finder> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
294
            $genHash = '';
295
            $hashFileFinder = new Finder();
296
            $hashFileIterator = $hashFileFinder
297
                ->files()
298
                ->in($bundleDir->getPathname())
299
                ->name(self::GENERATION_HASHFILE_FILENAME)
300
                ->depth('== 0')
301
                ->getIterator();
302
303
            $hashFileIterator->rewind();
304
305
            $hashFile = $hashFileIterator->current();
306
            if ($hashFile instanceof SplFileInfo) {
307
                $genHash = $hashFile->getContents();
308
            }
309
310
            $existingBundles[$bundleDir->getPathname()] = $genHash;
311
        }
312
313
        return $existingBundles;
314
    }
315
316
    /**
317
     * we cannot just delete the BundleBundle at the beginning, we need to prefill
318
     * it with all existing dynamic bundles..
319
     *
320
     * @param string $baseDir base dir
321
     *
322
     * @return void
323
     */
324
    private function createInitialBundleBundle($baseDir)
325
    {
326
        $bundleFinder = $this->getBundleFinder($baseDir);
327
328
        if (!$bundleFinder) {
329
            return;
330
        }
331
332
        foreach ($bundleFinder as $bundleDir) {
333
            $name = $bundleDir->getFilename();
334 View Code Duplication
            if (substr($name, -6) == 'Bundle') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
335
                $name = substr($name, 0, -6);
336
            }
337
            $this->bundleBundleList[] = sprintf(self::BUNDLE_NAME_MASK, $name);
338
        }
339
340
        $this->generateBundleBundleClass();
341
    }
342
343
    /**
344
     * returns a finder that iterates all bundle directories
345
     *
346
     * @param string $baseDir the base dir to search
347
     *
348
     * @return Finder|null finder or null if basedir does not exist
349
     */
350
    private function getBundleFinder($baseDir)
351
    {
352
        $bundleBaseDir = $baseDir.self::BUNDLE_NAMESPACE;
353
354
        if (!(new Filesystem())->exists($bundleBaseDir)) {
355
            return null;
356
        }
357
358
        $bundleFinder = new Finder();
359
        $bundleFinder->directories()->in($bundleBaseDir)->depth('== 0')->notName('BundleBundle');
360
361
        return $bundleFinder;
362
    }
363
364
    /**
365
     * Calculates a hash of all templates that generator uses to output it's file.
366
     * That way a regeneration will be triggered when one of them changes..
367
     *
368
     * @return string hash
369
     */
370
    private function getTemplateHash()
371
    {
372
        $templateDir = __DIR__ . '/../Resources/skeleton';
373
        $resourceFinder = new Finder();
374
        $resourceFinder->in($templateDir)->files()->sortByName();
375
        $templateTimes = '';
376
        foreach ($resourceFinder as $file) {
377
            $templateTimes .= PATH_SEPARATOR . $file->getMTime();
378
        }
379
        return sha1($templateTimes);
380
    }
381
382
    /**
383
     * Generate Bundle entities
384
     *
385
     * @param OutputInterface $output         Instance to sent text to be displayed on stout.
386
     * @param JsonDefinition  $jsonDef        Configuration to be generated the entity from.
387
     * @param XmlManipulator  $xmlManipulator Helper to safe the validation xml file.
388
     * @param string          $bundleName     Name of the bundle the entity shall be generated for.
389
     * @param string          $namespace      Absolute path to the bundle root dir.
390
     *
391
     * @return void
392
     * @throws \Exception
393
     */
394 4
    protected function generateSubResources(
395
        OutputInterface $output,
396
        JsonDefinition $jsonDef,
397
        XmlManipulator $xmlManipulator,
398
        $bundleName,
399
        $namespace
400
    ) {
401 4
        foreach ($this->getSubResources($jsonDef) as $subRecource) {
402
            $arguments = [
403
                'graviton:generate:resource',
404
                '--no-debug' => null,
405
                '--entity' => $bundleName . ':' . $subRecource->getId(),
406
                '--format' => 'xml',
407
                '--json' => $this->serializer->serialize($subRecource->getDef(), 'json'),
408
                '--fields' => $this->getFieldString($subRecource),
409
                '--no-controller' => 'true',
410
            ];
411
            $this->generateResource($arguments, $output, $jsonDef);
412
413
            // look for validation.xml and save it from over-writing ;-)
414
            // we basically get the xml content that was generated in order to save them later..
415
            $validationXml = $this->getGeneratedValidationXmlPath($namespace);
416
            if (file_exists($validationXml)) {
417
                $xmlManipulator->addNodes(file_get_contents($validationXml));
418
            }
419 2
        }
420 4
    }
421
422
    /**
423
     * Generate the actual Bundle
424
     *
425
     * @param OutputInterface $output     Instance to sent text to be displayed on stout.
426
     * @param JsonDefinition  $jsonDef    Configuration to be generated the entity from.
427
     * @param string          $bundleName Name of the bundle the entity shall be generated for.
428
     *
429
     * @return void
430
     */
431
    protected function generateMainResource(OutputInterface $output, JsonDefinition $jsonDef, $bundleName)
432
    {
433
        $fields = $jsonDef->getFields();
434
        if (!empty($fields)) {
435
            $arguments = array(
436
                'graviton:generate:resource',
437
                '--no-debug' => null,
438
                '--entity' => $bundleName . ':' . $jsonDef->getId(),
439
                '--json' => $this->serializer->serialize($jsonDef->getDef(), 'json'),
440
                '--format' => 'xml',
441
                '--fields' => $this->getFieldString($jsonDef)
442
            );
443
444
            $this->generateResource($arguments, $output, $jsonDef);
445
        }
446
    }
447
448
    /**
449
     * Get all sub hashes
450
     *
451
     * @param JsonDefinition $definition Main JSON definition
452
     * @return JsonDefinition[]
453
     */
454 6
    protected function getSubResources(JsonDefinition $definition)
455
    {
456 6
        $resources = [];
457 6
        foreach ($definition->getFields() as $field) {
458 4
            while ($field instanceof JsonDefinitionArray) {
459 4
                $field = $field->getElement();
460 2
            }
461 4
            if (!$field instanceof JsonDefinitionHash) {
462 4
                continue;
463
            }
464
465 2
            $subDefiniton = $field->getJsonDefinition();
466
467 2
            $resources = array_merge($this->getSubResources($subDefiniton), $resources);
468 2
            $resources[] = $subDefiniton;
469 3
        }
470
471 6
        return $resources;
472
    }
473
474
    /**
475
     * Gathers data for the command to run.
476
     *
477
     * @param array           $arguments Set of cli arguments passed to the command
478
     * @param OutputInterface $output    Output channel to send messages to.
479
     * @param JsonDefinition  $jsonDef   Configuration of the service
480
     *
481
     * @return void
482
     * @throws \LogicException
483
     */
484
    private function generateResource(array $arguments, OutputInterface $output, JsonDefinition $jsonDef)
485
    {
486
        // controller?
487
        $routerBase = $jsonDef->getRouterBase();
488
        if ($routerBase === false || $this->isNotWhitelistedController($routerBase)) {
489
            $arguments['--no-controller'] = 'true';
490
        }
491
492
        $this->runner->executeCommand($arguments, $output, 'Create resource call failed, see above. Exiting.');
493
    }
494
495
    /**
496
     * Generates a Bundle via command line (wrapping graviton:generate:bundle)
497
     *
498
     * @param string          $namespace    Namespace
499
     * @param string          $bundleName   Name of bundle
500
     * @param InputInterface  $input        Input
501
     * @param OutputInterface $output       Output
502
     * @param string          $deleteBefore Delete before directory
0 ignored issues
show
Documentation introduced by
Should the type for parameter $deleteBefore 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...
503
     *
504
     * @return void
505
     *
506
     * @throws \LogicException
507
     */
508
    private function generateBundle(
509
        $namespace,
510
        $bundleName,
511
        InputInterface $input,
512
        OutputInterface $output,
513
        $deleteBefore = null
514
    ) {
515
        // first, create the bundle
516
        $arguments = array(
517
            'graviton:generate:bundle',
518
            '--no-debug' => null,
519
            '--namespace' => $namespace,
520
            '--bundle-name' => $bundleName,
521
            '--dir' => $input->getOption('srcDir'),
522
            '--format' => $input->getOption('bundleFormat'),
523
            '--doUpdateKernel' => 'false',
524
            '--loaderBundleName' => $input->getOption('bundleBundleName'),
525
        );
526
527
        if (!is_null($deleteBefore)) {
528
            $arguments['--deleteBefore'] = $deleteBefore;
529
        }
530
531
        $this->runner->executeCommand(
532
            $arguments,
533
            $output,
534
            'Create bundle call failed, see above. Exiting.'
535
        );
536
    }
537
538
    /**
539
     * Generates our BundleBundle for dynamic bundles.
540
     * It basically replaces the Bundle main class that got generated
541
     * by the Sensio bundle task and it includes all of our bundles there.
542
     *
543
     * @return void
544
     */
545
    private function generateBundleBundleClass()
546
    {
547
        $dbbGenerator = new DynamicBundleBundleGenerator();
548
549
        // add optional bundles if defined by parameter.
550
        if ($this->bundleAdditions !== null) {
551
            $dbbGenerator->setAdditions($this->bundleAdditions);
552
        }
553
554
        $dbbGenerator->generate(
555
            $this->bundleBundleList,
556
            $this->bundleBundleNamespace,
557
            $this->bundleBundleClassname,
558
            $this->bundleBundleClassfile
559
        );
560
    }
561
562
    /**
563
     * Returns the path to the generated validation.xml
564
     *
565
     * @param string $namespace Namespace
566
     *
567
     * @return string path
568
     */
569
    private function getGeneratedValidationXmlPath($namespace)
570
    {
571
        return dirname(__FILE__) . '/../../../' . $namespace . '/Resources/config/validation.xml';
572
    }
573
574
    /**
575
     * Returns the field string as described in the json file
576
     *
577
     * @param JsonDefinition $jsonDef The json def
578
     *
579
     * @return string CommandLine string for the generator command
580
     */
581
    private function getFieldString(JsonDefinition $jsonDef)
582
    {
583
        $ret = array();
584
585
        foreach ($jsonDef->getFields() as $field) {
586
            // don't add 'id' field it seems..
587
            if ($field->getName() != 'id') {
588
                $ret[] = $field->getName() . ':' . $field->getTypeDoctrine();
589
            }
590
        }
591
592
        return implode(
593
            ' ',
594
            $ret
595
        );
596
    }
597
598
    /**
599
     * Checks an optional environment setting if this $routerBase is whitelisted there.
600
     * If something is 'not whitelisted' (return true) means that the controller should not be generated.
601
     * This serves as a lowlevel possibility to disable the generation of certain controllers.
602
     * If we have no whitelist defined, we consider that all services should be generated (default).
603
     *
604
     * @param string $routerBase router base
605
     *
606
     * @return bool true if yes, false if not
607
     */
608
    private function isNotWhitelistedController($routerBase)
609
    {
610
        if ($this->serviceWhitelist === null) {
611
            return false;
612
        }
613
614
        return !in_array($routerBase, $this->serviceWhitelist, true);
615
    }
616
617
    /**
618
     * renders and stores the validation.xml file of a bundle.
619
     *
620
     * what are we doing here?
621
     * well, when we started to generate our subclasses (hashes in our own service) as own
622
     * Document classes, i had the problem that the validation.xml always got overwritten by the
623
     * console task. sadly, validation.xml is one file for all classes in the bundle.
624
     * so here we merge the generated validation.xml we saved in the loop before back into the
625
     * final validation.xml again. the final result should be one validation.xml including all
626
     * the validation rules for all the documents in this bundle.
627
     *
628
     * @todo we might just make this an option to the resource generator, i need to grok why this was an issue
629
     *
630
     * @param XmlManipulator $xmlManipulator Helper to safe the validation xml file.
631
     * @param string         $location       Location where to store the file.
632
     *
633
     * @return void
634
     */
635
    private function generateValidationXml(XmlManipulator $xmlManipulator, $location)
636
    {
637
        if (file_exists($location)) {
638
            $xmlManipulator
639
                ->renderDocument(file_get_contents($location))
640
                ->saveDocument($location);
641
        }
642
    }
643
644
    /**
645
     * Generates the file containing the hash to determine if this bundle needs regeneration
646
     *
647
     * @param string $bundleDir directory of the bundle
648
     * @param string $hash      the hash to save
649
     *
650
     * @return void
651
     */
652
    private function generateGenerationHashFile($bundleDir, $hash)
653
    {
654
        $fs = new Filesystem();
655
        if ($fs->exists($bundleDir)) {
656
            $fs->dumpFile($bundleDir.DIRECTORY_SEPARATOR.self::GENERATION_HASHFILE_FILENAME, $hash);
657
        }
658
    }
659
660
    /**
661
     * Returns an XMLElement from a generated validation.xml that was generated during Resources generation.
662
     *
663
     * @param string $namespace Namespace, ie GravitonDyn\ShowcaseBundle
664
     *
665
     * @return \SimpleXMLElement The element
666
     *
667
     * @deprecated is this really used?
668
     */
669
    public function getGeneratedValidationXml($namespace)
670
    {
671
        $validationXmlPath = $this->getGeneratedValidationXmlPath($namespace);
672
        if (file_exists($validationXmlPath)) {
673
            $validationXml = new \SimpleXMLElement(file_get_contents($validationXmlPath));
674
            $validationXml->registerXPathNamespace('sy', 'http://symfony.com/schema/dic/constraint-mapping');
675
        } else {
676
            throw new \LogicException('Could not find ' . $validationXmlPath . ' that should be generated.');
677
        }
678
679
        return $validationXml;
680
    }
681
}
682