ApplicationRunner::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 17
dl 0
loc 19
ccs 1
cts 1
cp 1
crap 1
rs 10

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 bool $checkEvents Whether to check events' configuration.
34
     * @param string|null $environment The environment name.
35
     * @param string $bootstrapGroup The bootstrap configuration group name.
36
     * @param string $eventsGroup The events' configuration group name.
37
     * @param string $diGroup The container definitions' configuration group name.
38
     * @param string $diProvidersGroup The container providers' configuration group name.
39
     * @param string $diDelegatesGroup The container delegates' configuration group name.
40
     * @param string $diTagsGroup The container tags' configuration group name.
41
     * @param string $paramsGroup The configuration parameters group name.
42
     * @param array $nestedParamsGroups Configuration group names that are included into configuration parameters group.
43
     * This is needed for recursive merging of parameters.
44
     * @param array $nestedEventsGroups Configuration group names that are included into events' configuration group.
45
     * This is needed for reverse and recursive merge of events' configurations.
46
     * @param object[] $configModifiers Modifiers for {@see Config}.
47
     * @param string $configDirectory The relative path from {@see $rootPath} to the configuration storage location.
48
     * @param string $vendorDirectory The relative path from {@see $rootPath} to the vendor directory.
49
     * @param string $configMergePlanFile The relative path from {@see $configDirectory} to merge plan.
50
     *
51
     * @psalm-param list<string> $nestedParamsGroups
52
     * @psalm-param list<string> $nestedEventsGroups
53
     * @psalm-param list<object> $configModifiers
54
     */
55 18
    public function __construct(
56
        protected string $rootPath,
57
        protected bool $debug,
58
        protected bool $checkEvents,
59
        protected ?string $environment,
60
        protected string $bootstrapGroup,
61
        protected string $eventsGroup,
62
        protected string $diGroup,
63
        protected string $diProvidersGroup,
64
        protected string $diDelegatesGroup,
65
        protected string $diTagsGroup,
66
        protected string $paramsGroup,
67
        protected array $nestedParamsGroups,
68
        protected array $nestedEventsGroups,
69
        protected array $configModifiers = [],
70
        protected string $configDirectory = 'config',
71
        protected string $vendorDirectory = 'vendor',
72
        protected string $configMergePlanFile = '.merge-plan.php',
73
    ) {
74 18
    }
75
76
    abstract public function run(): void;
77
78
    /**
79
     * Returns a new instance with the specified config instance {@see ConfigInterface}.
80
     *
81
     * @param ConfigInterface $config The config instance.
82
     */
83 4
    final public function withConfig(ConfigInterface $config): static
84
    {
85 4
        $new = clone $this;
86 4
        $new->config = $config;
87 4
        return $new;
88
    }
89
90
    /**
91
     * Returns a new instance with the specified container instance {@see ContainerInterface}.
92
     *
93
     * @param ContainerInterface $container The container instance.
94
     */
95 4
    final public function withContainer(ContainerInterface $container): static
96
    {
97 4
        $new = clone $this;
98 4
        $new->container = $container;
99 4
        return $new;
100
    }
101
102
    /**
103
     * @throws ErrorException|RuntimeException
104
     */
105 4
    final protected function runBootstrap(): void
106
    {
107 4
        $bootstrapList = $this->getConfiguration($this->bootstrapGroup);
108 4
        if (empty($bootstrapList)) {
109 1
            return;
110
        }
111
112 3
        (new BootstrapRunner($this->getContainer(), $bootstrapList))->run();
113
    }
114
115
    /**
116
     * @throws ContainerExceptionInterface|ErrorException|NotFoundExceptionInterface
117
     */
118 4
    final protected function checkEvents(): void
119
    {
120
        if (
121 4
            $this->checkEvents
122 4
            && null !== $configuration = $this->getConfiguration($this->eventsGroup)
123
        ) {
124
            /** @psalm-suppress MixedMethodCall */
125 3
            $this->getContainer()
126 3
                ->get(ListenerConfigurationChecker::class)
127 3
                ->check($configuration);
128
        }
129
    }
130
131
    /**
132
     * @throws ErrorException
133
     */
134 14
    final public function getConfig(): ConfigInterface
135
    {
136 14
        return $this->config ??= $this->createDefaultConfig();
137
    }
138
139
    /**
140
     * @throws ErrorException|InvalidConfigException
141
     */
142 9
    final public function getContainer(): ContainerInterface
143
    {
144 9
        $this->container ??= $this->createDefaultContainer();
145
146 9
        if ($this->container instanceof Container) {
147 8
            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

147
            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...
148
        }
149
150 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...
151
    }
152
153 8
    final protected function getConfiguration(string $name): ?array
154
    {
155 8
        $config = $this->getConfig();
156 8
        return $config->has($name) ? $config->get($name) : null;
157
    }
158
159
    /**
160
     * @throws ErrorException
161
     */
162 11
    private function createDefaultConfig(): Config
163
    {
164 11
        $paramsGroups = [$this->paramsGroup, ...$this->nestedParamsGroups];
165 11
        $eventsGroups = [$this->eventsGroup, ...$this->nestedEventsGroups];
166
167 11
        return new Config(
168 11
            new ConfigPaths($this->rootPath, $this->configDirectory, $this->vendorDirectory),
169 11
            $this->environment,
170 11
            [
171 11
                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

171
                ReverseMerge::groups(/** @scrutinizer ignore-type */ ...$eventsGroups),
Loading history...
172 11
                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

172
                RecursiveMerge::groups(/** @scrutinizer ignore-type */ ...$paramsGroups, ...$eventsGroups),
Loading history...
173 11
                ...$this->configModifiers,
174 11
            ],
175 11
            $this->paramsGroup,
176 11
            $this->configMergePlanFile,
177 11
        );
178
    }
179
180
    /**
181
     * @throws ErrorException|InvalidConfigException
182
     */
183 6
    private function createDefaultContainer(): Container
184
    {
185 6
        $containerConfig = ContainerConfig::create()->withValidate($this->debug);
186
187 6
        $config = $this->getConfig();
188
189 6
        if (null !== $definitions = $this->getConfiguration($this->diGroup)) {
190 6
            $containerConfig = $containerConfig->withDefinitions($definitions);
191
        }
192
193 6
        if (null !== $providers = $this->getConfiguration($this->diProvidersGroup)) {
194 6
            $containerConfig = $containerConfig->withProviders($providers);
195
        }
196
197 6
        if (null !== $delegates = $this->getConfiguration($this->diDelegatesGroup)) {
198 6
            $containerConfig = $containerConfig->withDelegates($delegates);
199
        }
200
201 6
        if (null !== $tags = $this->getConfiguration($this->diTagsGroup)) {
202 6
            $containerConfig = $containerConfig->withTags($tags);
203
        }
204
205 6
        $containerConfig = $containerConfig->withDefinitions(
206 6
            array_merge($containerConfig->getDefinitions(), [ConfigInterface::class => $config])
207 6
        );
208
209 6
        return new Container($containerConfig);
210
    }
211
}
212