Passed
Push — master ( dae4ba...d6dea1 )
by Sergei
11:47
created

ApplicationRunner::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
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 13
dl 0
loc 15
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
     *
47
     * @psalm-param list<string> $nestedParamsGroups
48
     * @psalm-param list<string> $nestedEventsGroups
49
     */
50 13
    public function __construct(
51
        protected string $rootPath,
52
        protected bool $debug,
53
        protected bool $checkEvents,
54
        protected ?string $environment,
55
        protected string $bootstrapGroup,
56
        protected string $eventsGroup,
57
        protected string $diGroup,
58
        protected string $diProvidersGroup,
59
        protected string $diDelegatesGroup,
60
        protected string $diTagsGroup,
61
        protected string $paramsGroup,
62
        protected array $nestedParamsGroups,
63
        protected array $nestedEventsGroups,
64
    ) {
65 13
    }
66
67
    abstract public function run(): void;
68
69
    /**
70
     * Returns a new instance with the specified config instance {@see ConfigInterface}.
71
     *
72
     * @param ConfigInterface $config The config instance.
73
     */
74 4
    final public function withConfig(ConfigInterface $config): static
75
    {
76 4
        $new = clone $this;
77 4
        $new->config = $config;
78 4
        return $new;
79
    }
80
81
    /**
82
     * Returns a new instance with the specified container instance {@see ContainerInterface}.
83
     *
84
     * @param ContainerInterface $container The container instance.
85
     */
86 4
    final public function withContainer(ContainerInterface $container): static
87
    {
88 4
        $new = clone $this;
89 4
        $new->container = $container;
90 4
        return $new;
91
    }
92
93
    /**
94
     * @throws ErrorException|RuntimeException
95
     */
96 3
    final protected function runBootstrap(): void
97
    {
98 3
        $bootstrapList = $this->getConfiguration($this->bootstrapGroup);
99 3
        if (empty($bootstrapList)) {
100
            return;
101
        }
102
103 3
        (new BootstrapRunner($this->getContainer(), $bootstrapList))->run();
104
    }
105
106
    /**
107
     * @throws ContainerExceptionInterface|ErrorException|NotFoundExceptionInterface
108
     */
109 3
    final protected function checkEvents(): void
110
    {
111
        if (
112 3
            $this->checkEvents
113 3
            && null !== $configuration = $this->getConfiguration($this->eventsGroup)
114
        ) {
115
            /** @psalm-suppress MixedMethodCall */
116 3
            $this->getContainer()
117 3
                ->get(ListenerConfigurationChecker::class)
118 3
                ->check($configuration);
119
        }
120
    }
121
122
    /**
123
     * @throws ErrorException
124
     */
125 10
    final public function getConfig(): ConfigInterface
126
    {
127 10
        return $this->config ??= $this->createDefaultConfig();
128
    }
129
130
    /**
131
     * @throws ErrorException|InvalidConfigException
132
     */
133 9
    final public function getContainer(): ContainerInterface
134
    {
135 9
        $this->container ??= $this->createDefaultContainer();
136
137 9
        if ($this->container instanceof Container) {
138 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

138
            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...
139
        }
140
141 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...
142
    }
143
144 7
    final protected function getConfiguration(string $name): ?array
145
    {
146 7
        $config = $this->getConfig();
147 7
        return $config->has($name) ? $config->get($name) : null;
148
    }
149
150
    /**
151
     * @throws ErrorException
152
     */
153 7
    private function createDefaultConfig(): Config
154
    {
155 7
        $paramsGroups = [$this->paramsGroup, ...$this->nestedParamsGroups];
156 7
        $eventsGroups = [$this->eventsGroup, ...$this->nestedEventsGroups];
157
158 7
        return new Config(
159 7
            new ConfigPaths($this->rootPath, 'config'),
160 7
            $this->environment,
161 7
            [
162 7
                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

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

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