Failed Conditions
Pull Request — master (#56)
by Bernhard
11:07
created

src/Discovery/DiscoveryManagerImpl.php (10 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the puli/manager package.
5
 *
6
 * (c) Bernhard Schussek <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Puli\Manager\Discovery;
13
14
use Exception;
15
use Psr\Log\LoggerInterface;
16
use Psr\Log\NullLogger;
17
use Puli\Discovery\Api\Binding\Binding;
18
use Puli\Discovery\Api\EditableDiscovery;
19
use Puli\Manager\Api\Context\ProjectContext;
20
use Puli\Manager\Api\Discovery\BindingDescriptor;
21
use Puli\Manager\Api\Discovery\BindingTypeDescriptor;
22
use Puli\Manager\Api\Discovery\DiscoveryManager;
23
use Puli\Manager\Api\Discovery\DiscoveryNotEmptyException;
24
use Puli\Manager\Api\Discovery\DuplicateBindingException;
25
use Puli\Manager\Api\Discovery\DuplicateTypeException;
26
use Puli\Manager\Api\Discovery\NoSuchBindingException;
27
use Puli\Manager\Api\Discovery\NoSuchTypeException;
28
use Puli\Manager\Api\Discovery\TypeNotEnabledException;
29
use Puli\Manager\Api\Module\InstallInfo;
30
use Puli\Manager\Api\Module\Module;
31
use Puli\Manager\Api\Module\ModuleList;
32
use Puli\Manager\Api\Module\RootModule;
33
use Puli\Manager\Api\Module\RootModuleFile;
34
use Puli\Manager\Api\NonRootModuleExpectedException;
35
use Puli\Manager\Assert\Assert;
36
use Puli\Manager\Discovery\Binding\AddBinding;
37
use Puli\Manager\Discovery\Binding\AddBindingDescriptorToModuleFile;
38
use Puli\Manager\Discovery\Binding\BindingDescriptorCollection;
39
use Puli\Manager\Discovery\Binding\DisableBindingUuid;
40
use Puli\Manager\Discovery\Binding\EnableBindingUuid;
41
use Puli\Manager\Discovery\Binding\LoadBindingDescriptor;
42
use Puli\Manager\Discovery\Binding\ReloadBindingDescriptorsByTypeName;
43
use Puli\Manager\Discovery\Binding\RemoveBindingDescriptorFromModuleFile;
44
use Puli\Manager\Discovery\Binding\SyncBinding;
45
use Puli\Manager\Discovery\Binding\UnloadBindingDescriptor;
46
use Puli\Manager\Discovery\Type\AddBindingType;
47
use Puli\Manager\Discovery\Type\AddTypeDescriptorToModuleFile;
48
use Puli\Manager\Discovery\Type\BindingTypeDescriptorCollection;
49
use Puli\Manager\Discovery\Type\LoadTypeDescriptor;
50
use Puli\Manager\Discovery\Type\RemoveTypeDescriptorFromModuleFile;
51
use Puli\Manager\Discovery\Type\SyncTypeName;
52
use Puli\Manager\Discovery\Type\UnloadTypeDescriptor;
53
use Puli\Manager\Discovery\Type\UpdateDuplicateMarksForTypeName;
54
use Puli\Manager\Json\JsonStorage;
55
use Puli\Manager\Transaction\InterceptedOperation;
56
use Puli\Manager\Transaction\Transaction;
57
use Rhumsaa\Uuid\Uuid;
58
use Webmozart\Expression\Expr;
59
use Webmozart\Expression\Expression;
60
61
/**
62
 * @since  1.0
63
 *
64
 * @author Bernhard Schussek <[email protected]>
65
 */
66
class DiscoveryManagerImpl implements DiscoveryManager
67
{
68
    /**
69
     * @var ProjectContext
70
     */
71
    private $context;
72
73
    /**
74
     * @var LoggerInterface
75
     */
76
    private $logger;
77
78
    /**
79
     * @var EditableDiscovery
80
     */
81
    private $discovery;
82
83
    /**
84
     * @var ModuleList
85
     */
86
    private $modules;
87
88
    /**
89
     * @var JsonStorage
90
     */
91
    private $jsonStorage;
92
93
    /**
94
     * @var RootModule
95
     */
96
    private $rootModule;
97
98
    /**
99
     * @var RootModuleFile
100
     */
101
    private $rootModuleFile;
102
103
    /**
104
     * @var BindingTypeDescriptorCollection
105
     */
106
    private $typeDescriptors;
107
108
    /**
109
     * @var BindingDescriptorCollection
110
     */
111
    private $bindingDescriptors;
112
113
    /**
114
     * Creates a tag manager.
115
     *
116
     * @param ProjectContext       $context
117
     * @param EditableDiscovery    $discovery
118
     * @param ModuleList           $modules
119
     * @param JsonStorage          $jsonStorage
120
     * @param LoggerInterface|null $logger
121
     */
122 98
    public function __construct(
123
        ProjectContext $context,
124
        EditableDiscovery $discovery,
125
        ModuleList $modules,
126
        JsonStorage $jsonStorage,
127
        LoggerInterface $logger = null
128
    ) {
129 98
        $this->context = $context;
130 98
        $this->discovery = $discovery;
131 98
        $this->modules = $modules;
132 98
        $this->jsonStorage = $jsonStorage;
133 98
        $this->rootModule = $modules->getRootModule();
134 98
        $this->rootModuleFile = $context->getRootModuleFile();
135 98
        $this->logger = $logger ?: new NullLogger();
136 98
    }
137
138
    /**
139
     * {@inheritdoc}
140
     */
141 1
    public function getContext()
142
    {
143 1
        return $this->context;
144
    }
145
146
    /**
147
     * {@inheritdoc}
148
     */
149 5
    public function addRootTypeDescriptor(BindingTypeDescriptor $typeDescriptor, $flags = 0)
150
    {
151 5
        Assert::integer($flags, 'The argument $flags must be a boolean.');
152
153 5
        $this->assertModulesLoaded();
154 5
        $this->emitWarningForDuplicateTypes();
155
156 5
        $typeName = $typeDescriptor->getTypeName();
157
158 5
        if (!($flags & self::OVERRIDE) && $this->typeDescriptors->contains($typeName)) {
159 1
            throw DuplicateTypeException::forTypeName($typeName);
160
        }
161
162 4
        $tx = new Transaction();
163
164
        try {
165 4
            $syncBindingOps = array();
166
167 4 View Code Duplication
            foreach ($this->getUuidsByTypeName($typeName) as $uuid) {
0 ignored issues
show
The method getUuidsByTypeName() does not seem to exist on object<Puli\Manager\Disc...y\DiscoveryManagerImpl>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
168
                $syncBindingOp = $this->syncBinding($uuid);
169
                $syncBindingOp->takeSnapshot();
170
                $syncBindingOps[] = $syncBindingOp;
171
            }
172
173
            $syncOp = $this->syncTypeName($typeName);
174
            $syncOp->takeSnapshot();
175
176
            $tx->execute($this->loadTypeDescriptor($typeDescriptor, $this->rootModule));
177
            $tx->execute($this->addTypeDescriptorToModuleFile($typeDescriptor));
178
            $tx->execute($syncOp);
179
180
            foreach ($syncBindingOps as $syncBindingOp) {
181
                $tx->execute($syncBindingOp);
182
            }
183
184
            $this->saveRootModuleFile();
185
186
            $tx->commit();
187 4
        } catch (Exception $e) {
188
            $tx->rollback();
189
190
            throw $e;
191
        }
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 11
    public function removeRootTypeDescriptor($typeName)
198
    {
199
        // Only check that this is a string. The error message "not found" is
200
        // more helpful than e.g. "type name must contain /".
201 11
        Assert::string($typeName, 'The type name must be a string');
202
203 11
        $this->assertModulesLoaded();
204
205 11
        if (!$this->typeDescriptors->contains($typeName, $this->rootModule->getName())) {
206 2
            return;
207
        }
208
209 9
        $typeDescriptor = $this->typeDescriptors->get($typeName, $this->rootModule->getName());
210 9
        $tx = new Transaction();
211
212
        try {
213 9
            $tx->execute($this->removeTypeDescriptorFromModuleFile($typeName));
214
215 9
            $syncBindingOps = array();
216
217 9 View Code Duplication
            foreach ($this->getUuidsByTypeName($typeName) as $uuid) {
0 ignored issues
show
The method getUuidsByTypeName() does not seem to exist on object<Puli\Manager\Disc...y\DiscoveryManagerImpl>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
218
                $syncBindingOp = $this->syncBinding($uuid);
219
                $syncBindingOp->takeSnapshot();
220
                $syncBindingOps[] = $syncBindingOp;
221
            }
222
223
            $syncOp = $this->syncTypeName($typeName);
224
            $syncOp->takeSnapshot();
225
226
            $tx->execute($this->unloadTypeDescriptor($typeDescriptor));
227
            $tx->execute($syncOp);
228
229
            foreach ($syncBindingOps as $syncBindingOp) {
230
                $tx->execute($syncBindingOp);
231
            }
232
233
            $this->saveRootModuleFile();
234
235
            $tx->commit();
236 9
        } catch (Exception $e) {
237
            $tx->rollback();
238
239
            throw $e;
240
        }
241
242
        $this->emitWarningForDuplicateTypes();
243
    }
244
245
    /**
246
     * {@inheritdoc}
247
     */
248 4
    public function removeRootTypeDescriptors(Expression $expr)
249
    {
250 4
        $this->assertModulesLoaded();
251
252 4
        $tx = new Transaction();
253 4
        $syncBindingOps = array();
254
255
        try {
256 4
            foreach ($this->getRootTypeDescriptors() as $typeDescriptor) {
257 4
                if ($expr->evaluate($typeDescriptor)) {
258 4
                    $typeName = $typeDescriptor->getTypeName();
259
260 4
                    $tx->execute($this->removeTypeDescriptorFromModuleFile($typeName));
261
262 4 View Code Duplication
                    foreach ($this->getUuidsByTypeName($typeName) as $uuid) {
0 ignored issues
show
The method getUuidsByTypeName() does not seem to exist on object<Puli\Manager\Disc...y\DiscoveryManagerImpl>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
263
                        $syncBindingOp = $this->syncBinding($uuid);
264
                        $syncBindingOp->takeSnapshot();
265
                        $syncBindingOps[] = $syncBindingOp;
266
                    }
267
268
                    $syncOp = $this->syncTypeName($typeName);
269
                    $syncOp->takeSnapshot();
270
271
                    $tx->execute($this->unloadTypeDescriptor($typeDescriptor));
272
                    $tx->execute($syncOp);
273
                }
274
            }
275
276
            foreach ($syncBindingOps as $syncBindingOp) {
277
                $tx->execute($syncBindingOp);
278
            }
279
280
            $this->saveRootModuleFile();
281
282
            $tx->commit();
283 4
        } catch (Exception $e) {
284
            $tx->rollback();
285
286
            throw $e;
287
        }
288
289
        $this->emitWarningForDuplicateTypes();
290
    }
291
292
    /**
293
     * {@inheritdoc}
294
     */
295 1
    public function clearRootTypeDescriptors()
296
    {
297 1
        $this->removeRootTypeDescriptors(Expr::true());
298
    }
299
300
    /**
301
     * {@inheritdoc}
302
     */
303 2
    public function getRootTypeDescriptor($typeName)
304
    {
305 2
        return $this->getTypeDescriptor($typeName, $this->rootModule->getName());
306
    }
307
308
    /**
309
     * {@inheritdoc}
310
     */
311 5 View Code Duplication
    public function getRootTypeDescriptors()
312
    {
313 5
        $this->assertModulesLoaded();
314
315 5
        $types = array();
316 5
        $rootModuleName = $this->rootModule->getName();
317
318 5
        foreach ($this->typeDescriptors->toArray() as $typeName => $typesByModule) {
319 5
            if (isset($typesByModule[$rootModuleName])) {
320 5
                $types[] = $typesByModule[$rootModuleName];
321
            }
322
        }
323
324 5
        return $types;
325
    }
326
327
    /**
328
     * {@inheritdoc}
329
     */
330 1 View Code Duplication
    public function findRootTypeDescriptors(Expression $expr)
331
    {
332 1
        $expr = Expr::method('getContainingModule', Expr::same($this->rootModule))
333 1
            ->andX($expr);
334
335 1
        return $this->findTypeDescriptors($expr);
336
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341 1
    public function hasRootTypeDescriptor($typeName)
342
    {
343 1
        return $this->hasTypeDescriptor($typeName, $this->rootModule->getName());
344
    }
345
346
    /**
347
     * {@inheritdoc}
348
     */
349 1 View Code Duplication
    public function hasRootTypeDescriptors(Expression $expr = null)
350
    {
351 1
        $expr2 = Expr::method('getContainingModule', Expr::same($this->rootModule));
352
353 1
        if ($expr) {
354 1
            $expr2 = $expr2->andX($expr);
355
        }
356
357 1
        return $this->hasTypeDescriptors($expr2);
358
    }
359
360
    /**
361
     * {@inheritdoc}
362
     */
363 6
    public function getTypeDescriptor($typeName, $moduleName)
364
    {
365 6
        Assert::string($typeName, 'The type name must be a string. Got: %s');
366 5
        Assert::string($moduleName, 'The module name must be a string. Got: %s');
367
368 4
        $this->assertModulesLoaded();
369
370 4
        if (!$this->typeDescriptors->contains($typeName, $moduleName)) {
371 2
            throw NoSuchTypeException::forTypeName($typeName);
372
        }
373
374 2
        return $this->typeDescriptors->get($typeName, $moduleName);
375
    }
376
377
    /**
378
     * {@inheritdoc}
379
     */
380 2
    public function getTypeDescriptors()
381
    {
382 2
        $this->assertModulesLoaded();
383
384 2
        $types = array();
385
386 2
        foreach ($this->typeDescriptors->toArray() as $typeName => $typesByModule) {
387 1
            foreach ($typesByModule as $type) {
388 1
                $types[] = $type;
389
            }
390
        }
391
392 2
        return $types;
393
    }
394
395
    /**
396
     * {@inheritdoc}
397
     */
398 2 View Code Duplication
    public function findTypeDescriptors(Expression $expr)
399
    {
400 2
        $this->assertModulesLoaded();
401
402 2
        $typeDescriptors = array();
403
404 2
        foreach ($this->typeDescriptors->toArray() as $typeName => $descriptorsByModule) {
405 2
            foreach ($descriptorsByModule as $typeDescriptor) {
406 2
                if ($expr->evaluate($typeDescriptor)) {
407 2
                    $typeDescriptors[] = $typeDescriptor;
408
                }
409
            }
410
        }
411
412 2
        return $typeDescriptors;
413
    }
414
415
    /**
416
     * {@inheritdoc}
417
     */
418 3
    public function hasTypeDescriptor($typeName, $moduleName = null)
419
    {
420 3
        Assert::nullOrString($moduleName, 'The module name must be a string or null. Got: %s');
421
422 2
        $this->assertModulesLoaded();
423
424 2
        return $this->typeDescriptors->contains($typeName, $moduleName);
425
    }
426
427
    /**
428
     * {@inheritdoc}
429
     */
430 3
    public function hasTypeDescriptors(Expression $expr = null)
431
    {
432 3
        $this->assertModulesLoaded();
433
434 3
        if (!$expr) {
435 2
            return !$this->typeDescriptors->isEmpty();
436
        }
437
438 2
        foreach ($this->typeDescriptors->toArray() as $typeName => $descriptorsByModule) {
439 2
            foreach ($descriptorsByModule as $typeDescriptor) {
440 2
                if ($expr->evaluate($typeDescriptor)) {
441 2
                    return true;
442
                }
443
            }
444
        }
445
446 2
        return false;
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452 12
    public function addRootBindingDescriptor(BindingDescriptor $bindingDescriptor, $flags = 0)
453
    {
454 12
        $this->assertModulesLoaded();
455
456 12
        $typeName = $bindingDescriptor->getTypeName();
457 12
        $typeExists = $this->typeDescriptors->contains($typeName);
458
459 12
        if (!($flags & self::IGNORE_TYPE_NOT_FOUND) && !$typeExists) {
460 2
            throw NoSuchTypeException::forTypeName($typeName);
461
        }
462
463 10
        if (!($flags & self::IGNORE_TYPE_NOT_ENABLED) && $typeExists && !$this->typeDescriptors->getFirst($typeName)->isEnabled()) {
464 2
            throw TypeNotEnabledException::forTypeName($typeName);
465
        }
466
467 8
        $binding = $bindingDescriptor->getBinding();
468 8
        $exists = $this->bindingDescriptors->contains($binding);
469 8
        $existsInNonRoot = $exists
470 3
            ? !$this->bindingDescriptors->contains($binding, $this->rootModule->getName())
471 8
            : false;
472
473
        // We can only override bindings in the root module
474 8
        if ($existsInNonRoot || ($exists && !($flags & self::OVERRIDE))) {
475 2
            throw DuplicateBindingException::forUuid($binding);
476
        }
477
478 6
        $tx = new Transaction();
479
480
        try {
481 6
            $syncOp = $this->syncBinding($binding);
482 6
            $syncOp->takeSnapshot();
483
484 6
            $tx->execute($this->loadBindingDescriptor($bindingDescriptor, $this->rootModule));
485
486 6
            $this->assertBindingValid($bindingDescriptor);
487
488 5
            $tx->execute($this->addBindingDescriptorToModuleFile($bindingDescriptor));
489 5
            $tx->execute($syncOp);
490
491 5
            $this->saveRootModuleFile();
492
493 3
            $tx->commit();
494 3
        } catch (Exception $e) {
495 3
            $tx->rollback();
496
497
            throw $e;
498
        }
499 3
    }
500
501
    /**
502
     * {@inheritdoc}
503
     */
504 3 View Code Duplication
    public function removeRootBindingDescriptors(Expression $expr)
505
    {
506 3
        $this->assertModulesLoaded();
507
508 3
        $tx = new Transaction();
509
510
        try {
511 3
            foreach ($this->getRootBindingDescriptors() as $bindingDescriptor) {
512
                if ($expr->evaluate($bindingDescriptor)) {
513
                    $syncOp = $this->syncBinding($bindingDescriptor->getUuid());
0 ignored issues
show
The method getUuid() does not seem to exist on object<Puli\Manager\Api\...very\BindingDescriptor>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
514
                    $syncOp->takeSnapshot();
515
516
                    $tx->execute($this->unloadBindingDescriptor($bindingDescriptor));
517
                    $tx->execute($syncOp);
518
                    $tx->execute($this->removeBindingDescriptorFromModuleFile($bindingDescriptor->getUuid()));
0 ignored issues
show
The method getUuid() does not seem to exist on object<Puli\Manager\Api\...very\BindingDescriptor>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
519
                }
520
            }
521
522
            $this->saveRootModuleFile();
523
524
            $tx->commit();
525 3
        } catch (Exception $e) {
526
            $tx->rollback();
527
528
            throw $e;
529
        }
530
    }
531
532
    /**
533
     * {@inheritdoc}
534
     */
535 1
    public function clearRootBindingDescriptors()
536
    {
537 1
        $this->removeRootBindingDescriptors(Expr::true());
538
    }
539
540
    /**
541
     * {@inheritdoc}
542
     */
543 3 View Code Duplication
    public function getRootBindingDescriptors()
544
    {
545 3
        $this->assertModulesLoaded();
546
547 3
        $bindings = array();
548
549 3
        foreach ($this->bindingDescriptors->toArray() as $binding) {
550 3
            if ($binding->getContainingModule() instanceof RootModule) {
0 ignored issues
show
The method getContainingModule cannot be called on $binding (of type array<integer,object<Pul...ery\BindingDescriptor>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
551
                $bindings[] = $binding;
552
            }
553
        }
554
555
        return $bindings;
556
    }
557
558
    /**
559
     * {@inheritdoc}
560
     */
561 1 View Code Duplication
    public function findRootBindingDescriptors(Expression $expr)
562
    {
563 1
        $expr = Expr::method('getContainingModule', Expr::same($this->rootModule))
564 1
            ->andX($expr);
565
566 1
        return $this->findBindingDescriptors($expr);
567
    }
568
569
    /**
570
     * {@inheritdoc}
571
     */
572 1 View Code Duplication
    public function hasRootBindingDescriptors(Expression $expr = null)
573
    {
574 1
        $expr2 = Expr::method('getContainingModule', Expr::same($this->rootModule));
575
576 1
        if ($expr) {
577
            $expr2 = $expr2->andX($expr);
578
        }
579
580 1
        return $this->hasBindingDescriptors($expr2);
581
    }
582
583
    /**
584
     * {@inheritdoc}
585
     */
586 1
    public function getBindingDescriptors()
587
    {
588 1
        $this->assertModulesLoaded();
589
590 1
        return array_values($this->bindingDescriptors->toArray());
591
    }
592
593
    /**
594
     * {@inheritdoc}
595
     */
596 2 View Code Duplication
    public function findBindingDescriptors(Expression $expr)
597
    {
598 2
        $this->assertModulesLoaded();
599
600 2
        $descriptors = array();
601
602 2
        foreach ($this->bindingDescriptors->toArray() as $descriptor) {
603 2
            if ($expr->evaluate($descriptor)) {
604 2
                $descriptors[] = $descriptor;
605
            }
606
        }
607
608 2
        return $descriptors;
609
    }
610
611
    /**
612
     * {@inheritdoc}
613
     */
614 3 View Code Duplication
    public function hasBindingDescriptors(Expression $expr = null)
615
    {
616 3
        $this->assertModulesLoaded();
617
618 3
        if (!$expr) {
619 2
            return !$this->bindingDescriptors->isEmpty();
620
        }
621
622 2
        foreach ($this->bindingDescriptors->toArray() as $bindingDescriptor) {
623 2
            if ($expr->evaluate($bindingDescriptor)) {
624 2
                return true;
625
            }
626
        }
627
628 2
        return false;
629
    }
630
631
    /**
632
     * {@inheritdoc}
633
     */
634 7
    public function buildDiscovery()
635
    {
636 7
        $this->assertModulesLoaded();
637 7
        $this->emitWarningForDuplicateTypes();
638 7
        $this->emitWarningForInvalidBindings();
639
640 3
        if ($this->discovery->hasBindings() || $this->discovery->hasBindingTypes()) {
641 2
            throw new DiscoveryNotEmptyException('The discovery is not empty.');
642
        }
643
644 1
        $tx = new Transaction();
645
646
        try {
647 1
            foreach ($this->typeDescriptors->toArray() as $typeName => $descriptorsByModule) {
648 1
                foreach ($descriptorsByModule as $typeDescriptor) {
649 1
                    if ($typeDescriptor->isEnabled()) {
650 1
                        $tx->execute($this->addBindingType($typeDescriptor));
651
                    }
652
                }
653
            }
654
655 1
            foreach ($this->bindingDescriptors->toArray() as $bindingDescriptor) {
656
                if ($bindingDescriptor->isEnabled()) {
0 ignored issues
show
The method isEnabled cannot be called on $bindingDescriptor (of type array<integer,object<Pul...ery\BindingDescriptor>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
657
                    $tx->execute($this->addBinding($bindingDescriptor));
658
                }
659
            }
660
661 1
            $tx->commit();
662
        } catch (Exception $e) {
663
            $tx->rollback();
664
665
            throw $e;
666
        }
667 1
    }
668
669
    /**
670
     * {@inheritdoc}
671
     */
672 1
    public function clearDiscovery()
673
    {
674 1
        $this->discovery->removeBindingTypes();
675 1
    }
676
677 61
    private function assertModulesLoaded()
678
    {
679 61
        if (!$this->typeDescriptors) {
680 61
            $this->loadModules();
681
        }
682 61
    }
683
684 6
    private function assertBindingValid(BindingDescriptor $bindingDescriptor)
685
    {
686 6
        if ($bindingDescriptor->isTypeNotFound() || $bindingDescriptor->isTypeNotEnabled()) {
687 2
            return;
688
        }
689
690 4
        foreach ($bindingDescriptor->getLoadErrors() as $exception) {
691 1
            throw $exception;
692
        }
693 3
    }
694
695 61
    private function loadModules()
696
    {
697 61
        $this->typeDescriptors = new BindingTypeDescriptorCollection();
698 61
        $this->bindingDescriptors = new BindingDescriptorCollection();
699
700
        // First load all the types
701 61 View Code Duplication
        foreach ($this->modules as $module) {
702 61
            if (null === $module->getModuleFile()) {
703 1
                continue;
704
            }
705
706 61
            foreach ($module->getModuleFile()->getTypeDescriptors() as $typeDescriptor) {
707 61
                $this->loadTypeDescriptor($typeDescriptor, $module)->execute();
708
            }
709
        }
710
711
        // Then the bindings for the loaded types
712 61
        foreach ($this->modules as $module) {
713 61
            if (null === $module->getModuleFile()) {
714 1
                continue;
715
            }
716
717 61
            foreach ($module->getModuleFile()->getBindingDescriptors() as $bindingDescriptor) {
718 61
                $this->loadBindingDescriptor($bindingDescriptor, $module)->execute();
719
            }
720
        }
721 61
    }
722
723 12
    private function emitWarningForDuplicateTypes()
724
    {
725 12
        foreach ($this->typeDescriptors->getTypeNames() as $typeName) {
726 7
            $moduleNames = $this->typeDescriptors->getModuleNames($typeName);
727
728 7
            if (count($moduleNames) > 1) {
729 1
                $lastModuleName = array_pop($moduleNames);
730
731 1
                $this->logger->warning(sprintf(
732
                    'The modules "%s" and "%s" contain type definitions for '.
733 1
                    'the same type "%s". The type has been disabled.',
734 7
                    implode('", "', $moduleNames),
735
                    $lastModuleName,
736
                    $typeName
737
                ));
738
            }
739
        }
740 12
    }
741
742 7
    private function emitWarningForInvalidBindings()
743
    {
744 7
        foreach ($this->bindingDescriptors->toArray() as $binding) {
745 4
            foreach ($binding->getLoadErrors() as $exception) {
0 ignored issues
show
The method getLoadErrors cannot be called on $binding (of type array<integer,object<Pul...ery\BindingDescriptor>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
746
                $this->logger->warning(sprintf(
747
                    'The binding "%s" in module "%s" is invalid: %s',
748
                    $binding->getUuid()->toString(),
0 ignored issues
show
The method getUuid cannot be called on $binding (of type array<integer,object<Pul...ery\BindingDescriptor>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
749
                    $binding->getContainingModule()->getName(),
0 ignored issues
show
The method getContainingModule cannot be called on $binding (of type array<integer,object<Pul...ery\BindingDescriptor>>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
750
                    $exception->getMessage()
751
                ));
752
            }
753
        }
754 3
    }
755
756 5
    private function saveRootModuleFile()
757
    {
758 5
        $this->jsonStorage->saveRootModuleFile($this->rootModuleFile);
759 3
    }
760
761
    private function addTypeDescriptorToModuleFile(BindingTypeDescriptor $typeDescriptor)
762
    {
763
        return new AddTypeDescriptorToModuleFile($typeDescriptor, $this->rootModuleFile);
764
    }
765
766 13
    private function removeTypeDescriptorFromModuleFile($typeName)
767
    {
768 13
        return new RemoveTypeDescriptorFromModuleFile($typeName, $this->rootModuleFile);
769
    }
770
771 48 View Code Duplication
    private function loadTypeDescriptor(BindingTypeDescriptor $typeDescriptor, Module $module)
772
    {
773 48
        $typeName = $typeDescriptor->getTypeName();
774
775 48
        return new InterceptedOperation(
776 48
            new LoadTypeDescriptor($typeDescriptor, $module, $this->typeDescriptors),
777
            array(
778 48
                new UpdateDuplicateMarksForTypeName($typeName, $this->typeDescriptors),
779 48
                new ReloadBindingDescriptorsByTypeName($typeName, $this->bindingDescriptors, $this->typeDescriptors),
780
            )
781
        );
782
    }
783
784 View Code Duplication
    private function unloadTypeDescriptor(BindingTypeDescriptor $typeDescriptor)
785
    {
786
        $typeName = $typeDescriptor->getTypeName();
787
788
        return new InterceptedOperation(
789
            new UnloadTypeDescriptor($typeDescriptor, $this->typeDescriptors),
790
            array(
791
                new UpdateDuplicateMarksForTypeName($typeName, $this->typeDescriptors),
792
                new ReloadBindingDescriptorsByTypeName($typeName, $this->bindingDescriptors, $this->typeDescriptors),
793
            )
794
        );
795
    }
796
797
    private function addBindingType(BindingTypeDescriptor $typeDescriptor)
798
    {
799
        return new AddBindingType($typeDescriptor, $this->discovery);
800
    }
801
802
    private function syncTypeName($typeName)
803
    {
804
        return new SyncTypeName($typeName, $this->discovery, $this->typeDescriptors);
805
    }
806
807 5
    private function addBindingDescriptorToModuleFile(BindingDescriptor $bindingDescriptor)
808
    {
809 5
        return new AddBindingDescriptorToModuleFile($bindingDescriptor, $this->rootModuleFile);
810
    }
811
812
    private function removeBindingDescriptorFromModuleFile(Uuid $uuid)
813
    {
814
        return new RemoveBindingDescriptorFromModuleFile($uuid, $this->rootModuleFile);
815
    }
816
817 24
    private function loadBindingDescriptor(BindingDescriptor $bindingDescriptor, Module $module)
818
    {
819 24
        return new LoadBindingDescriptor($bindingDescriptor, $module, $this->bindingDescriptors, $this->typeDescriptors);
820
    }
821
822
    private function unloadBindingDescriptor(BindingDescriptor $bindingDescriptor)
823
    {
824
        return new UnloadBindingDescriptor($bindingDescriptor, $this->bindingDescriptors);
825
    }
826
827
    private function addBinding(BindingDescriptor $bindingDescriptor)
828
    {
829
        return new AddBinding($bindingDescriptor, $this->discovery);
830
    }
831
832 6
    private function syncBinding(Binding $binding)
833
    {
834 6
        return new SyncBinding($binding, $this->discovery, $this->bindingDescriptors);
835
    }
836
}
837