AbstractKernel   D
last analyzed

Complexity

Total Complexity 35

Size/Duplication

Total Lines 342
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 24

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 342
rs 4.7142
c 1
b 0
f 0
wmc 35
lcom 2
cbo 24

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A getEnvironmentManager() 0 4 1
A getBundleManager() 0 4 1
A getContainer() 0 4 1
A setContainer() 0 5 1
A getServiceLocator() 0 8 2
A getMiddleware() 0 4 1
A getRequest() 0 4 1
A listen() 0 8 1
B boot() 0 25 4
A shutdown() 0 22 3
A getKernelParameters() 0 17 2
A setErrorHandler() 0 6 2
A handleFatalError() 0 13 2
A initialize() 0 6 2
A registerProcessors() 0 4 1
A importEnvironmentFile() 0 14 3
A getKernelProcessors() 0 14 1
A bootBundle() 0 7 2
A sendException() 0 16 3
1
<?php
2
/*
3
 * This file is part of the Borobudur-Kernel package.
4
 *
5
 * (c) Hexacodelabs <http://hexacodelabs.com>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Borobudur\Kernel;
12
13
use Borobudur\Config\FileLoader;
14
use Borobudur\DependencyInjection\ContainerBuilder;
15
use Borobudur\DependencyInjection\Definition;
16
use Borobudur\DependencyInjection\ParameterBag;
17
use Borobudur\EventDispatcher\Subscriber\SubscriberTrait;
18
use Borobudur\Http\Request;
19
use Borobudur\Http\Response;
20
use Borobudur\Kernel\Bundling\BundleManager;
21
use Borobudur\Kernel\Event\KernelEvent;
22
use Borobudur\Kernel\Event\ResponseExceptionEvent;
23
use Borobudur\Kernel\Exception\ErrorException;
24
use Borobudur\Kernel\Exception\FatalErrorException;
25
use Borobudur\Kernel\Exception\RuntimeException;
26
use Borobudur\Kernel\Middleware\MiddlewareContainer;
27
use Borobudur\Kernel\Processor\BundleProcessor;
28
use Borobudur\Kernel\Processor\ConfigurationProcessor;
29
use Borobudur\Kernel\Processor\ContainerProcessor;
30
use Borobudur\Kernel\Processor\EnvironmentProcessor;
31
use Borobudur\Kernel\Processor\ExtensionProcessor;
32
use Borobudur\Kernel\Processor\MiddlewareProcessor;
33
use Borobudur\Kernel\Processor\ProcessorInterface;
34
use Exception;
35
36
/**
37
 * @author      Iqbal Maulana <[email protected]>
38
 * @created     8/7/15
39
 */
40
abstract class AbstractKernel implements KernelInterface
41
{
42
    use IdentifierTrait, SubscriberTrait;
43
44
    /**
45
     * @var ContainerBuilder
46
     */
47
    protected $container;
48
49
    /**
50
     * @var Request|null
51
     */
52
    protected $request;
53
54
    /**
55
     * @var KernelServiceLocator
56
     */
57
    protected $serviceLocator;
58
59
    /**
60
     * @var MiddlewareContainer
61
     */
62
    protected $middleware;
63
64
    /**
65
     * @var EnvironmentManager
66
     */
67
    protected $envManager;
68
69
    /**
70
     * @var BundleManager
71
     */
72
    protected $bundleManager;
73
74
    /**
75
     * @var bool
76
     */
77
    protected $booted = false;
78
79
    /**
80
     * @var string
81
     */
82
    protected $envFile = '.env';
83
84
    /**
85
     * @var array
86
     */
87
    private $envs = array();
88
89
    /**
90
     * Constructor.
91
     *
92
     * @param string|null $env Active environment.
93
     */
94
    final public function __construct($env = null)
95
    {
96
        $this->importEnvironmentFile();
97
        $this->envManager = new EnvironmentManager(env('APP_ENV', $env));
98
        $this->bundleManager = new BundleManager();
99
        $this->middleware = new MiddlewareContainer();
100
        error_reporting(0);
101
102
        set_error_handler(array($this, 'setErrorHandler'));
103
        register_shutdown_function(array($this, 'handleFatalError'));
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function getEnvironmentManager()
110
    {
111
        return $this->envManager;
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117
    public function getBundleManager()
118
    {
119
        return $this->bundleManager;
120
    }
121
122
    /**
123
     * {@inheritdoc}
124
     */
125
    public function getContainer()
126
    {
127
        return $this->container;
128
    }
129
130
    /**
131
     * {@inheritdoc}
132
     */
133
    public function setContainer(ContainerBuilder $container)
134
    {
135
        $this->container = $container;
136
        $this->serviceLocator = new KernelServiceLocator($container);
137
    }
138
139
    /**
140
     * {@inheritdoc}
141
     */
142
    public function getServiceLocator()
143
    {
144
        if (null === $this->serviceLocator) {
145
            throw new RuntimeException('Undefined service locator.');
146
        }
147
148
        return $this->serviceLocator;
149
    }
150
151
    /**
152
     * {@inheritdoc}
153
     */
154
    public function getMiddleware()
155
    {
156
        return $this->middleware;
157
    }
158
159
    /**
160
     * {@inheritdoc}
161
     */
162
    public function getRequest()
163
    {
164
        return $this->request;
165
    }
166
167
    /**
168
     * Listen request.
169
     *
170
     * @param Request $request
171
     *
172
     * @return $this
173
     */
174
    public function listen(Request $request)
175
    {
176
        $this->request = $request;
177
178
        $this->addListenerOnce(KernelEvents::BOOTED, array(new HttpKernelListener(), 'onBooted'));
179
180
        return $this;
181
    }
182
183
    /**
184
     * Boot kernel.
185
     */
186
    public function boot()
187
    {
188
        if (true === $this->booted) {
189
            return;
190
        }
191
192
        $this->booted = true;
193
194
        try {
195
            $this->initialize();
196
197
            // boot environment
198
            $this->getEnvironmentManager()->getEnvInstance()->boot();
199
200
            // boot bundle
201
            $this->bootBundle();
202
            $this->fireEvent(KernelEvents::BOOTED, new KernelEvent($this, $this->request));
203
        } catch (\Exception $e) {
204
            if (!$this->hasListener(KernelEvents::EXCEPTION)) {
205
                throw $e;
206
            }
207
208
            $this->sendException($e);
209
        }
210
    }
211
212
    /**
213
     * Shutdown current kernel.
214
     */
215
    public function shutdown()
216
    {
217
        if (false === $this->booted) {
218
            return;
219
        }
220
221
        $this->booted = false;
222
223
        // shutdown environment
224
        $this->getEnvironmentManager()->getEnvInstance()->shutdown();
225
226
        // shutdown bundle
227
        foreach ($this->getBundleManager()->all() as $bundle) {
228
            $bundle->shutdown();
229
            $bundle->setContainer(null);
230
        }
231
232
        $this->envs = array();
233
        $this->container = null;
234
        $this->request = null;
235
        $this->envManager = null;
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function getKernelParameters()
242
    {
243
        $bundles = array();
244
        $env = $this->envManager->getEnvInstance();
245
        foreach ($this->getBundleManager()->all() as $name => $bundle) {
246
            $bundles[$name] = $bundle->getFullName();
247
        }
248
249
        return array_merge(
250
            array(
251
                'kernel.root_dir'    => $this->getPath(),
252
                'kernel.environment' => $this->envManager->getEnv(),
253
                'kernel.bundles'     => $bundles,
254
            ),
255
            $env->getEnvParameters()
256
        );
257
    }
258
259
    /**
260
     * Error handler.
261
     *
262
     * @param int    $severity
263
     * @param string $errMessage
264
     * @param string $file
265
     * @param int    $line
266
     */
267
    public function setErrorHandler($severity, $errMessage, $file, $line)
268
    {
269
        if (E_WARNING !== $severity) {
270
            $this->sendException(new ErrorException($errMessage, 0, $severity, $file, $line));
271
        }
272
    }
273
274
    /**
275
     * Handle fatal error.
276
     */
277
    public function handleFatalError()
278
    {
279
        $error = error_get_last();
280
281
        if( $error !== NULL) {
282
            $severity = $error["type"];
283
            $file = $error["file"];
284
            $line = $error["line"];
285
            $errMessage = $error["message"];
286
287
            $this->sendException(new FatalErrorException($errMessage, 0, $severity, $file, $line));
288
        }
289
    }
290
291
    /**
292
     * Initialize kernel.
293
     */
294
    protected function initialize()
295
    {
296
        foreach ($this->getKernelProcessors() as $processor) {
297
            $processor->initialize($this);
298
        }
299
    }
300
301
    /**
302
     * Register processors.
303
     *
304
     * @return array
305
     */
306
    protected function registerProcessors()
307
    {
308
        return array();
309
    }
310
311
    /**
312
     * Import environment file.
313
     */
314
    private function importEnvironmentFile()
315
    {
316
        $envFile = $this->getPath() . '/' . $this->envFile;
317
        if (file_exists($envFile)) {
318
            $loader = new FileLoader();
319
            $vars = $loader->import(new FileLoader\FileLocator($envFile));
320
321
            foreach ($vars as $name => $value) {
322
                $name = strtolower($name);
323
                $this->envs[$name] = $value;
324
                setenv($name, $value);
325
            }
326
        }
327
    }
328
329
    /**
330
     * Get kernel processors.
331
     *
332
     * @return ProcessorInterface[]
333
     */
334
    private function getKernelProcessors()
335
    {
336
        return array_merge(
337
            array(
338
                new EnvironmentProcessor(),
339
                new BundleProcessor(),
340
                new ContainerProcessor(),
341
                new ConfigurationProcessor($this->envs),
342
                new ExtensionProcessor(),
343
                new MiddlewareProcessor(),
344
            ),
345
            (array) $this->registerProcessors()
346
        );
347
    }
348
349
    /**
350
     * Boot bundle.
351
     */
352
    private function bootBundle()
353
    {
354
        foreach ($this->getBundleManager()->all() as $bundle) {
355
            $bundle->setContainer($this->container);
356
            $bundle->boot();
357
        }
358
    }
359
360
    /**
361
     * Send exception.
362
     *
363
     * @param Exception $e
364
     */
365
    private function sendException(Exception $e)
366
    {
367
        $evt = new ResponseExceptionEvent($this, $this->request);
368
        $evt->setException($e);
369
        $this->fireEvent(KernelEvents::EXCEPTION, $evt);
370
371
        if (false !== $this->booted) {
372
            if (!$evt->hasResponse()) {
373
                throw new RuntimeException(sprintf(
374
                    'There are no response found. Did you forgot add a return statement?'
375
                ));
376
            }
377
378
            $evt->getResponse()->send();
379
        }
380
    }
381
}
382