Passed
Push — master ( d18ffa...718acb )
by Evgeniy
04:12 queued 01:50
created

ConsoleApplicationRunner::createDefaultContainer()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 17
ccs 0
cts 9
cp 0
crap 20
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Runner\Console;
6
7
use ErrorException;
8
use Exception;
9
use Psr\Container\ContainerExceptionInterface;
10
use Psr\Container\ContainerInterface;
11
use Psr\Container\NotFoundExceptionInterface;
12
use Throwable;
13
use Yiisoft\Config\Config;
14
use Yiisoft\Di\Container;
15
use Yiisoft\Di\ContainerConfig;
16
use Yiisoft\Di\NotFoundException;
17
use Yiisoft\Definitions\Exception\CircularReferenceException;
18
use Yiisoft\Definitions\Exception\InvalidConfigException;
19
use Yiisoft\Definitions\Exception\NotInstantiableException;
20
use Yiisoft\Yii\Console\Application;
21
use Yiisoft\Yii\Console\ExitCode;
22
use Yiisoft\Yii\Console\Output\ConsoleBufferedOutput;
23
use Yiisoft\Yii\Runner\BootstrapRunner;
24
use Yiisoft\Yii\Runner\ConfigFactory;
25
use Yiisoft\Yii\Runner\RunnerInterface;
26
27
/**
28
 * `ConsoleApplicationRunner` runs the Yii console application.
29
 */
30
final class ConsoleApplicationRunner implements RunnerInterface
31
{
32
    private bool $debug;
33
    private string $rootPath;
34
    private ?string $environment;
35
    private ?Config $config = null;
36
    private ?ContainerInterface $container = null;
37
    private ?string $bootstrapGroup = 'bootstrap-console';
38
39
    /**
40
     * @param string $rootPath The absolute path to the project root.
41
     * @param bool $debug Whether the debug mode is enabled.
42
     * @param string|null $environment The environment name.
43
     */
44
    public function __construct(string $rootPath, bool $debug, ?string $environment)
45
    {
46
        $this->rootPath = $rootPath;
47
        $this->debug = $debug;
48
        $this->environment = $environment;
49
    }
50
51
    /**
52
     * Returns a new instance with the specified bootstrap configuration group name.
53
     *
54
     * @param string $bootstrapGroup The bootstrap configuration group name.
55
     *
56
     * @return self
57
     */
58
    public function withBootstrap(string $bootstrapGroup): self
59
    {
60
        $new = clone $this;
61
        $new->bootstrapGroup = $bootstrapGroup;
62
        return $new;
63
    }
64
65
    /**
66
     * Returns a new instance and disables the use of bootstrap configuration group.
67
     *
68
     * @return self
69
     */
70
    public function withoutBootstrap(): self
71
    {
72
        $new = clone $this;
73
        $new->bootstrapGroup = null;
74
        return $new;
75
    }
76
77
    /**
78
     * Returns a new instance with the specified config instance {@see Config}.
79
     *
80
     * @param Config $config The config instance.
81
     *
82
     * @return self
83
     */
84
    public function withConfig(Config $config): self
85
    {
86
        $new = clone $this;
87
        $new->config = $config;
88
        return $new;
89
    }
90
91
    /**
92
     * Returns a new instance with the specified container instance {@see ContainerInterface}.
93
     *
94
     * @param ContainerInterface $container The container instance.
95
     *
96
     * @return self
97
     */
98
    public function withContainer(ContainerInterface $container): self
99
    {
100
        $new = clone $this;
101
        $new->container = $container;
102
        return $new;
103
    }
104
105
    /**
106
     * {@inheritDoc}
107
     *
108
     * @throws CircularReferenceException|ErrorException|Exception|InvalidConfigException
109
     * @throws ContainerExceptionInterface|NotFoundException|NotFoundExceptionInterface|NotInstantiableException
110
     */
111
    public function run(): void
112
    {
113
        $config = $this->config ?? ConfigFactory::create($this->rootPath, $this->environment);
114
        $container = $this->container ?? $this->createDefaultContainer($config);
115
116
        if ($container instanceof Container) {
117
            $container = $container->get(ContainerInterface::class);
118
        }
119
120
        // Run bootstrap
121
        if ($this->bootstrapGroup !== null) {
122
            $this->runBootstrap($container, $config->get($this->bootstrapGroup));
123
        }
124
125
        /** @var Application */
126
        $application = $container->get(Application::class);
127
        $exitCode = ExitCode::UNSPECIFIED_ERROR;
128
129
        try {
130
            $application->start();
131
            $exitCode = $application->run(null, new ConsoleBufferedOutput());
132
        } catch (Throwable $throwable) {
133
            $application->renderThrowable($throwable, new ConsoleBufferedOutput());
134
        } finally {
135
            $application->shutdown($exitCode);
136
            exit($exitCode);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
137
        }
138
    }
139
140
    /**
141
     * @throws ErrorException|InvalidConfigException
142
     */
143
    private function createDefaultContainer(Config $config): Container
144
    {
145
        $containerConfig = ContainerConfig::create()->withValidate($this->debug);
146
147
        if ($config->has('console')) {
148
            $containerConfig = $containerConfig->withDefinitions($config->get('console'));
149
        }
150
151
        if ($config->has('providers-console')) {
152
            $containerConfig = $containerConfig->withProviders($config->get('providers-console'));
153
        }
154
155
        if ($config->has('delegates-console')) {
156
            $containerConfig = $containerConfig->withDelegates($config->get('delegates-console'));
157
        }
158
159
        return new Container($containerConfig);
160
    }
161
162
    private function runBootstrap(ContainerInterface $container, array $bootstrapList): void
163
    {
164
        (new BootstrapRunner($container, $bootstrapList))->run();
165
    }
166
}
167