FallbackContainer   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 15
eloc 27
c 3
b 0
f 0
dl 0
loc 78
ccs 28
cts 28
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A reset() 0 12 3
A __construct() 0 4 1
A has() 0 9 4
A fallback() 0 5 1
A get() 0 23 6
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of DivineNii opensource projects.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2021 DivineNii (https://divinenii.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Rade\DI;
19
20
use Psr\Container\{ContainerExceptionInterface, ContainerInterface};
21
use Rade\DI\Exceptions\{ContainerResolutionException, NotFoundServiceException};
22
use Symfony\Contracts\Service\ResetInterface;
23
24
/**
25
 * A container supporting multiple PSR-11 containers.
26
 *
27
 * @author Divine Niiquaye Ibok <[email protected]>
28
 */
29
class FallbackContainer extends Container
30
{
31
    /** @var ContainerInterface[] A list of fallback PSR-11 containers */
32
    protected array $fallbacks = [];
33
34 6
    public function __construct()
35
    {
36 6
        parent::__construct();
37 6
        $this->types += [self::class => ['container']]; // Autowire this container
38 6
    }
39
40
    /**
41
     * Register a PSR-11 fallback container.
42
     */
43 5
    public function fallback(ContainerInterface $fallback): self
44
    {
45 5
        $this->fallbacks[\get_class($fallback)] = $fallback;
46
47 5
        return $this;
48
    }
49
50
    /**
51
     * {@inheritdoc}
52
     */
53 6
    public function get(string $id, int $invalidBehavior = /* self::EXCEPTION_ON_MULTIPLE_SERVICE */ 1)
54
    {
55
        try {
56 6
            $service = $this->fallbacks[$id] ?? parent::get($id, $invalidBehavior);
57 4
        } catch (NotFoundServiceException $e) {
58 4
            foreach ($this->fallbacks as $container) {
59
                try {
60 3
                    return self::$services[$id] = $container->get($id);
61 1
                } catch (ContainerExceptionInterface $e) {
62
                    // Fallback services not allowed to throw a PSR-11 exception.
63
                }
64
            }
65
66 2
            if (\class_exists($id)) {
67
                try {
68 1
                    return $this->resolver->resolveClass($id);
69 1
                } catch (ContainerResolutionException $e) {
70
                    // Only resolves class string and not throw it's error.
71
                }
72
            }
73
        }
74
75 6
        return $service ?? $this->createNotFound($id, true);
76
    }
77
78
    /**
79
     * {@inheritdoc}
80
     */
81 4
    public function has(string $id): bool
82
    {
83 4
        foreach ($this->fallbacks as $container) {
84 4
            if ($container->has($id)) {
85 2
                return true;
86
            }
87
        }
88
89 3
        return isset($this->fallbacks[$id]) || parent::has($id);
90
    }
91
92
    /**
93
     * {@inheritdoc}
94
     */
95 1
    public function reset(): void
96
    {
97 1
        parent::reset();
98
99
        // A container such as Symfony DI support reset ...
100 1
        foreach ($this->fallbacks as $fallback) {
101 1
            if ($fallback instanceof ResetInterface) {
102 1
                $fallback->reset();
103
            }
104
        }
105
106 1
        $this->fallbacks = [];
107 1
    }
108
}
109