Completed
Branch 2.0 (63d421)
by Anton
05:39
created

Core::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 15
rs 9.7666
c 0
b 0
f 0
1
<?php
2
/**
3
 * Spiral Framework.
4
 *
5
 * @license   MIT
6
 * @author    Anton Titov (Wolfy-J)
7
 */
8
9
namespace Spiral\Framework;
10
11
use Spiral\Core\BootloadManager;
12
use Spiral\Core\Container;
13
use Spiral\Core\ContainerScope;
14
use Spiral\Framework\Bootloaders\CoreBootloader;
15
use Spiral\Framework\Exceptions\FrameworkException;
16
17
/**
18
 * Core responsible for application initialization, bootloading of all required services, environment and directory
19
 * management, exception handling.
20
 */
21
abstract class Core
22
{
23
    /**
24
     * Defines list of bootloaders to be used for core initialisation and all system components.
25
     */
26
    protected const SYSTEM = [CoreBootloader::class];
27
28
    /**
29
     * List of bootloaders to be called on application initialization (before `serve` method).
30
     * This constant must be redefined in child application.
31
     */
32
    protected const LOAD = [];
33
34
    /** @var Container */
35
    protected $container;
36
37
    /** @var BootloadManager */
38
    protected $bootloader;
39
40
    /** @var DispatcherInterface[] */
41
    private $dispatchers = [];
42
43
    /**
44
     * @param Container $container
45
     * @param array     $directories
46
     */
47
    public function __construct(Container $container, array $directories)
48
    {
49
        $this->container = $container;
50
51
        $this->container->bindSingleton(self::class, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Spiral\Framework\Core>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
52
        $this->container->bindSingleton(static::class, $this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Spiral\Framework\Core>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
53
54
        $this->container->bindSingleton(
55
            DirectoriesInterface::class,
56
            new Directories($this->mapDirectories($directories))
0 ignored issues
show
Documentation introduced by
new \Spiral\Framework\Di...ectories($directories)) is of type object<Spiral\Framework\Directories>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
57
        );
58
59
        $this->bootloader = new BootloadManager($this->container);
60
        $this->bootloader->bootload(static::SYSTEM);
61
    }
62
63
    /**
64
     * Add new dispatcher. This method must only be called before method `serve`
65
     * will be invoked.
66
     *
67
     * @param DispatcherInterface $dispatcher
68
     */
69
    public function addDispatcher(DispatcherInterface $dispatcher)
70
    {
71
        $this->dispatchers[] = $dispatcher;
72
    }
73
74
    /**
75
     * Start application and serve user requests using selected dispatcher or throw
76
     * an exception.
77
     *
78
     * @throws FrameworkException
79
     */
80
    public function serve()
81
    {
82
        foreach ($this->dispatchers as $dispatcher) {
83
            if ($dispatcher->canServe()) {
84
                $dispatcher->serve();
85
                return;
86
            }
87
        }
88
89
        throw new FrameworkException("Unable to locate active dispatcher.");
90
    }
91
92
    /**
93
     * Bootstrap application. Must be executed before start method.
94
     */
95
    abstract protected function bootstrap();
96
97
    /**
98
     * Normalizes directory list and adds all required alises.
99
     *
100
     * @param array $directories
101
     * @return array
102
     */
103
    protected function mapDirectories(array $directories): array
104
    {
105
        if (!isset($directories['root'])) {
106
            throw new FrameworkException("Missing required directory `root`.");
107
        }
108
109
        if (!isset($directories['app'])) {
110
            $directories['app'] = $directories['root'] . '/app/';
111
        }
112
113
        return array_merge($directories, [
114
            // public root
115
            'public'    => $directories['root'] . '/public/',
116
117
            // application directories
118
            'config'    => $directories['app'] . '/config/',
119
            'resources' => $directories['app'] . '/resources/',
120
121
            // data directories
122
            'runtime'   => $directories['app'] . '/runtime/',
123
            'cache'     => $directories['app'] . '/runtime/cache/',
124
        ]);
125
    }
126
127
    /**
128
     * Bootload all registered classes using BootloadManager.
129
     *
130
     * @return self
131
     */
132
    private function bootload(): self
133
    {
134
        $this->bootloader->bootload(static::LOAD);
135
        return $this;
136
    }
137
138
    /**
139
     * Initiate application core.
140
     *
141
     * @param array                $directories  Spiral directories should include root, libraries and application
142
     *                                           directories.
143
     * @param EnvironmentInterface $environment  Application specific environment if any.
144
     * @param bool                 $handleErrors Enable global error handling.
145
     * @return self
146
     */
147
    public static function init(
148
        array $directories,
149
        EnvironmentInterface $environment = null,
150
        bool $handleErrors = true
151
    ): self {
152
        if ($handleErrors) {
153
            ExceptionHandler::register();
154
        }
155
156
        $core = new static(new Container(), $directories);
157
        $core->container->bindSingleton(
158
            EnvironmentInterface::class,
159
            $environment ?? new Environment()
0 ignored issues
show
Documentation introduced by
$environment ?? new \Spi...Framework\Environment() is of type object<Spiral\Framework\EnvironmentInterface>, but the function expects a callable.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
160
        );
161
162
        try {
163
            ContainerScope::runScope($core->container, function () use ($core) {
164
                $core->bootload()->bootstrap();
165
            });
166
        } catch (\Throwable $e) {
167
            ExceptionHandler::handleException($e);
168
        }
169
170
        return $core;
171
    }
172
}