Passed
Pull Request — master (#39)
by Alexander
12:58 queued 10:30
created

ApplicationRunner::getConfiguration()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 2
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Runner;
6
7
use ErrorException;
8
use Psr\Container\ContainerExceptionInterface;
9
use Psr\Container\ContainerInterface;
10
use Psr\Container\NotFoundExceptionInterface;
11
use RuntimeException;
12
use Yiisoft\Config\Config;
13
use Yiisoft\Config\ConfigInterface;
14
use Yiisoft\Config\ConfigPaths;
15
use Yiisoft\Config\Modifier\RecursiveMerge;
16
use Yiisoft\Config\Modifier\ReverseMerge;
17
use Yiisoft\Definitions\Exception\InvalidConfigException;
18
use Yiisoft\Di\Container;
19
use Yiisoft\Di\ContainerConfig;
20
use Yiisoft\Yii\Event\ListenerConfigurationChecker;
21
22
/**
23
 * Provides basic functionality for creating adapters.
24
 */
25
abstract class ApplicationRunner implements RunnerInterface
26
{
27
    private ?ConfigInterface $config = null;
28
    private ?ContainerInterface $container = null;
29
30
    /**
31
     * @param string $rootPath The absolute path to the project root.
32
     * @param bool $debug Whether the debug mode is enabled.
33
     * @param string|null $environment The environment name.
34
     *
35
     * @psalm-param list<string> $nestedParamsGroups
36
     * @psalm-param list<string> $nestedEventsGroups
37
     */
38 11
    public function __construct(
39
        protected string $rootPath,
40
        protected bool $debug,
41
        protected bool $checkEvents,
42
        protected ?string $environment,
43
        protected string $bootstrapGroup,
44
        protected string $eventsGroup,
45
        protected string $diGroup,
46
        protected string $diProvidersGroup,
47
        protected string $diDelegatesGroup,
48
        protected string $diTagsGroup,
49
        protected string $paramsGroup,
50
        protected array $nestedParamsGroups,
51
        protected array $nestedEventsGroups,
52
    ) {
53 11
    }
54
55
    abstract public function run(): void;
56
57
    /**
58
     * Returns a new instance with the specified config instance {@see ConfigInterface}.
59
     *
60
     * @param ConfigInterface $config The config instance.
61
     */
62 3
    final public function withConfig(ConfigInterface $config): static
63
    {
64 3
        $new = clone $this;
65 3
        $new->config = $config;
66 3
        return $new;
67
    }
68
69
    /**
70
     * Returns a new instance with the specified container instance {@see ContainerInterface}.
71
     *
72
     * @param ContainerInterface $container The container instance.
73
     */
74 4
    final public function withContainer(ContainerInterface $container): static
75
    {
76 4
        $new = clone $this;
77 4
        $new->container = $container;
78 4
        return $new;
79
    }
80
81
    /**
82
     * @throws ErrorException|RuntimeException
83
     */
84 3
    final protected function runBootstrap(): void
85
    {
86 3
        $bootstrapList = $this->getConfiguration($this->bootstrapGroup);
87 3
        if (empty($bootstrapList)) {
88
            return;
89
        }
90
91 3
        (new BootstrapRunner($this->getContainer(), $bootstrapList))->run();
92
    }
93
94
    /**
95
     * @throws ContainerExceptionInterface|ErrorException|NotFoundExceptionInterface
96
     */
97 3
    final protected function checkEvents(): void
98
    {
99
        if (
100 3
            $this->debug
101 3
            && $this->checkEvents
102 3
            && null !== $configuration = $this->getConfiguration($this->eventsGroup)
103
        ) {
104
            /** @psalm-suppress MixedMethodCall */
105 3
            $this->getContainer()
106 3
                ->get(ListenerConfigurationChecker::class)
107 3
                ->check($configuration);
108
        }
109
    }
110
111
    /**
112
     * @throws ErrorException
113
     */
114 8
    final protected function getConfig(): ConfigInterface
115
    {
116 8
        return $this->config ??= $this->createDefaultConfig();
117
    }
118
119
    /**
120
     * @throws ErrorException|InvalidConfigException
121
     */
122 8
    final protected function getContainer(): ContainerInterface
123
    {
124 8
        $this->container ??= $this->createDefaultContainer();
125
126 8
        if ($this->container instanceof Container) {
127 7
            return $this->container->get(ContainerInterface::class);
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

127
            return $this->container->/** @scrutinizer ignore-call */ get(ContainerInterface::class);

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...
128
        }
129
130 1
        return $this->container;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->container could return the type null which is incompatible with the type-hinted return Psr\Container\ContainerInterface. Consider adding an additional type-check to rule them out.
Loading history...
131
    }
132
133 6
    final protected function getConfiguration(string $name): ?array
134
    {
135 6
        $config = $this->getConfig();
136 6
        return $config->has($name) ? $config->get($name) : null;
137
    }
138
139
    /**
140
     * @throws ErrorException
141
     */
142 6
    private function createDefaultConfig(): Config
143
    {
144 6
        $paramsGroups = [$this->paramsGroup, ...$this->nestedParamsGroups];
145 6
        $eventsGroups = [$this->eventsGroup, ...$this->nestedEventsGroups];
146
147 6
        return new Config(
148 6
            new ConfigPaths($this->rootPath, 'config'),
149 6
            $this->environment,
150 6
            [
151 6
                ReverseMerge::groups(...$eventsGroups),
0 ignored issues
show
Bug introduced by
It seems like $eventsGroups can also be of type array; however, parameter $groups of Yiisoft\Config\Modifier\ReverseMerge::groups() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

151
                ReverseMerge::groups(/** @scrutinizer ignore-type */ ...$eventsGroups),
Loading history...
152 6
                RecursiveMerge::groups(...$paramsGroups, ...$eventsGroups),
0 ignored issues
show
Bug introduced by
It seems like $paramsGroups can also be of type array; however, parameter $groups of Yiisoft\Config\Modifier\RecursiveMerge::groups() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
                RecursiveMerge::groups(/** @scrutinizer ignore-type */ ...$paramsGroups, ...$eventsGroups),
Loading history...
153 6
            ],
154 6
            $this->paramsGroup,
155 6
        );
156
    }
157
158
    /**
159
     * @throws ErrorException|InvalidConfigException
160
     */
161 5
    private function createDefaultContainer(): Container
162
    {
163 5
        $containerConfig = ContainerConfig::create()->withValidate($this->debug);
164
165 5
        $config = $this->getConfig();
166
167 5
        if (null !== $definitions = $this->getConfiguration($this->diGroup)) {
168 5
            $containerConfig = $containerConfig->withDefinitions($definitions);
169
        }
170
171 5
        if (null !== $providers = $this->getConfiguration($this->diProvidersGroup)) {
172 5
            $containerConfig = $containerConfig->withProviders($providers);
173
        }
174
175 5
        if (null !== $delegates = $this->getConfiguration($this->diDelegatesGroup)) {
176 5
            $containerConfig = $containerConfig->withDelegates($delegates);
177
        }
178
179 5
        if (null !== $tags = $this->getConfiguration($this->diTagsGroup)) {
180 5
            $containerConfig = $containerConfig->withTags($tags);
181
        }
182
183 5
        $containerConfig = $containerConfig->withDefinitions(
184 5
            array_merge($containerConfig->getDefinitions(), [ConfigInterface::class => $config])
185 5
        );
186
187 5
        return new Container($containerConfig);
188
    }
189
}
190