Passed
Pull Request — 4 (#10016)
by
unknown
13:10
created

BaseKernel::activate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 6
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 10
rs 10
1
<?php
2
3
namespace SilverStripe\Core;
4
5
use InvalidArgumentException;
6
use Monolog\Handler\StreamHandler;
7
use Monolog\Logger;
8
use Psr\Log\LoggerInterface;
9
use SilverStripe\Config\Collections\CachedConfigCollection;
10
use SilverStripe\Control\Director;
11
use SilverStripe\Control\HTTPResponse;
12
use SilverStripe\Control\HTTPResponse_Exception;
13
use SilverStripe\Core\Cache\ManifestCacheFactory;
14
use SilverStripe\Core\Config\ConfigLoader;
15
use SilverStripe\Core\Config\CoreConfigFactory;
16
use SilverStripe\Core\Injector\Injector;
17
use SilverStripe\Core\Injector\InjectorLoader;
18
use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
19
use SilverStripe\Core\Manifest\ClassLoader;
20
use SilverStripe\Core\Manifest\ClassManifest;
21
use SilverStripe\Core\Manifest\ModuleLoader;
22
use SilverStripe\Core\Manifest\ModuleManifest;
23
use SilverStripe\Dev\DebugView;
24
use SilverStripe\Dev\Deprecation;
25
use SilverStripe\Logging\ErrorHandler;
26
use SilverStripe\View\PublicThemes;
27
use SilverStripe\View\SSViewer;
28
use SilverStripe\View\ThemeManifest;
29
use SilverStripe\View\ThemeResourceLoader;
30
use Exception;
31
32
/**
33
 * Simple Kernel container
34
 */
35
abstract class BaseKernel implements Kernel
36
{
37
    /**
38
     * @var Kernel
39
     */
40
    protected $nestedFrom = null;
41
42
    /**
43
     * @var Injector
44
     */
45
    protected $container = null;
46
47
    /**
48
     * @var string
49
     */
50
    protected $enviroment = null;
51
52
    /**
53
     * @var ClassLoader
54
     */
55
    protected $classLoader = null;
56
57
    /**
58
     * @var ModuleLoader
59
     */
60
    protected $moduleLoader = null;
61
62
    /**
63
     * @var ConfigLoader
64
     */
65
    protected $configLoader = null;
66
67
    /**
68
     * @var InjectorLoader
69
     */
70
    protected $injectorLoader = null;
71
72
    /**
73
     * @var ThemeResourceLoader
74
     */
75
    protected $themeResourceLoader = null;
76
77
    protected $basePath = null;
78
79
    /**
80
     * Indicates whether the Kernel has been booted already
81
     *
82
     * @var bool
83
     */
84
    private $booted = false;
85
86
87
    /**
88
     * Create a new kernel for this application
89
     *
90
     * @param string $basePath Path to base dir for this application
91
     */
92
    public function __construct($basePath)
93
    {
94
        $this->basePath = $basePath;
95
96
        // Initialise the dependency injector as soon as possible, as it is
97
        // subsequently used by some of the following code
98
        $injectorLoader = InjectorLoader::inst();
99
        $injector = new Injector(['locator' => SilverStripeServiceConfigurationLocator::class]);
100
        $injectorLoader->pushManifest($injector);
101
        $this->setInjectorLoader($injectorLoader);
102
103
        // Manifest cache factory
104
        $manifestCacheFactory = $this->buildManifestCacheFactory();
105
106
        // Class loader
107
        $classLoader = ClassLoader::inst();
108
        $classLoader->pushManifest(new ClassManifest($basePath, $manifestCacheFactory));
109
        $this->setClassLoader($classLoader);
110
111
        // Module loader
112
        $moduleLoader = ModuleLoader::inst();
113
        $moduleManifest = new ModuleManifest($basePath, $manifestCacheFactory);
114
        $moduleLoader->pushManifest($moduleManifest);
115
        $this->setModuleLoader($moduleLoader);
116
117
        // Config loader
118
        // @todo refactor CoreConfigFactory
119
        $configFactory = new CoreConfigFactory($manifestCacheFactory);
120
        $configManifest = $configFactory->createRoot();
121
        $configLoader = ConfigLoader::inst();
122
        $configLoader->pushManifest($configManifest);
123
        $this->setConfigLoader($configLoader);
124
125
        // Load template manifest
126
        $themeResourceLoader = ThemeResourceLoader::inst();
127
        $themeResourceLoader->addSet(SSViewer::PUBLIC_THEME, new PublicThemes());
128
        $themeResourceLoader->addSet(SSViewer::DEFAULT_THEME, new ThemeManifest(
129
            $basePath,
130
            null, // project is defined in config, and this argument is deprecated
131
            $manifestCacheFactory
132
        ));
133
        $this->setThemeResourceLoader($themeResourceLoader);
134
    }
135
136
    /**
137
     * Initialise PHP with default variables
138
     */
139
    protected function bootPHP()
140
    {
141
        if ($this->getEnvironment() === self::LIVE) {
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\BaseKernel::getEnvironment() has been deprecated: 5.0 use Director::get_environment_type() instead. Since 5.0 it should return only if kernel overrides. No checking SESSION or Environment. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

141
        if (/** @scrutinizer ignore-deprecated */ $this->getEnvironment() === self::LIVE) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
142
            // limited to fatal errors and warnings in live mode
143
            error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
144
        } else {
145
            // Report all errors in dev / test mode
146
            error_reporting(E_ALL | E_STRICT);
147
        }
148
149
        /**
150
         * Ensure we have enough memory
151
         */
152
        Environment::increaseMemoryLimitTo('64M');
153
154
        // Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
155
        if (function_exists('xdebug_enable')) {
156
            $current = ini_get('xdebug.max_nesting_level');
157
            if ((int)$current < 200) {
158
                ini_set('xdebug.max_nesting_level', 200);
159
            }
160
        }
161
162
        /**
163
         * Set default encoding
164
         */
165
        mb_http_output('UTF-8');
166
        mb_internal_encoding('UTF-8');
167
        mb_regex_encoding('UTF-8');
168
169
        /**
170
         * Enable better garbage collection
171
         */
172
        gc_enable();
173
    }
174
175
    /**
176
     * Boot all manifests
177
     *
178
     * @param bool $flush
179
     */
180
    /**
181
     * Boot all manifests
182
     *
183
     * @param bool $flush
184
     */
185
    protected function bootManifests($flush)
186
    {
187
        // Setup autoloader
188
        $this->getClassLoader()->init(
189
            $this->getIncludeTests(),
190
            $flush,
191
            $this->getIgnoredCIConfigs()
192
        );
193
194
        // Find modules
195
        $this->getModuleLoader()->init(
196
            $this->getIncludeTests(),
197
            $flush,
198
            $this->getIgnoredCIConfigs()
199
        );
200
201
        // Flush config
202
        if ($flush) {
203
            $config = $this->getConfigLoader()->getManifest();
204
            if ($config instanceof CachedConfigCollection) {
205
                $config->setFlush(true);
206
            }
207
        }
208
        // tell modules to sort, now that config is available
209
        $this->getModuleLoader()->getManifest()->sort();
210
211
        // Find default templates
212
        $defaultSet = $this->getThemeResourceLoader()->getSet('$default');
213
        if ($defaultSet instanceof ThemeManifest) {
214
            $defaultSet->setProject(
215
                ModuleManifest::config()->get('project')
216
            );
217
            $defaultSet->init(
218
                $this->getIncludeTests(),
219
                $flush,
220
                $this->getIgnoredCIConfigs()
221
            );
222
        }
223
    }
224
225
    /**
226
     * Include all _config.php files
227
     */
228
    protected function bootConfigs()
229
    {
230
        global $project;
231
        $projectBefore = $project;
232
        $config = ModuleManifest::config();
233
        // After loading all other app manifests, include _config.php files
234
        $this->getModuleLoader()->getManifest()->activateConfig();
235
        if ($project && $project !== $projectBefore) {
236
            Deprecation::notice('5.0', '$project global is deprecated');
237
            $config->set('project', $project);
238
        }
239
    }
240
241
    /**
242
     * Turn on error handling
243
     * @throws Exception
244
     */
245
    protected function bootErrorHandling()
246
    {
247
        // Register error handler
248
        $errorHandler = Injector::inst()->get(ErrorHandler::class);
249
        $errorHandler->start();
250
251
        // Register error log file
252
        $errorLog = Environment::getEnv('SS_ERROR_LOG');
253
        if ($errorLog) {
254
            $logger = Injector::inst()->get(LoggerInterface::class);
255
            if ($logger instanceof Logger) {
256
                $logger->pushHandler(new StreamHandler($this->basePath . '/' . $errorLog, Logger::WARNING));
257
            } else {
258
                user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
259
            }
260
        }
261
    }
262
263
264
265
    /**
266
     * Get the environment type
267
     *
268
     * @return string
269
     *
270
     * @deprecated 5.0 use Director::get_environment_type() instead. Since 5.0 it should return only if kernel overrides. No checking SESSION or Environment.
271
     */
272
    public function getEnvironment()
273
    {
274
        // Check set
275
        if ($this->enviroment) {
276
            return $this->enviroment;
277
        }
278
279
        // Check saved session
280
        $env = $this->sessionEnvironment();
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\BaseKernel::sessionEnvironment() has been deprecated: 5.0 Use Director::get_session_environment_type() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

280
        $env = /** @scrutinizer ignore-deprecated */ $this->sessionEnvironment();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
281
        if ($env) {
282
            return $env;
283
        }
284
285
        // Check getenv
286
        if ($env = Environment::getEnv('SS_ENVIRONMENT_TYPE')) {
287
            return $env;
288
        }
289
290
        return self::LIVE;
291
    }
292
293
    /**
294
     * Check or update any temporary environment specified in the session.
295
     *
296
     * @return null|string
297
     *
298
     * @deprecated 5.0 Use Director::get_session_environment_type() instead
299
     */
300
    protected function sessionEnvironment()
301
    {
302
        if (!$this->booted) {
303
            // session is not initialyzed yet, neither is manifest
304
            return null;
305
        }
306
307
        return Director::get_session_environment_type();
308
    }
309
310
    abstract public function boot($flush = false);
311
312
    abstract public function isFlushed();
313
314
    /**
315
     * Check if there's a legacy _ss_environment.php file
316
     *
317
     * @throws HTTPResponse_Exception
318
     */
319
    protected function detectLegacyEnvironment()
320
    {
321
        // Is there an _ss_environment.php file?
322
        if (!file_exists($this->basePath . '/_ss_environment.php') &&
323
            !file_exists(dirname($this->basePath) . '/_ss_environment.php')
324
        ) {
325
            return;
326
        }
327
328
        // Build error response
329
        $dv = new DebugView();
330
        $body = implode([
331
            $dv->renderHeader(),
332
            $dv->renderInfo(
333
                "Configuration Error",
334
                Director::absoluteBaseURL()
335
            ),
336
            $dv->renderParagraph(
337
                'You need to replace your _ss_environment.php file with a .env file, or with environment variables.<br><br>'
338
                . 'See the <a href="https://docs.silverstripe.org/en/4/getting_started/environment_management/">'
339
                . 'Environment Management</a> docs for more information.'
340
            ),
341
            $dv->renderFooter()
342
        ]);
343
344
        // Raise error
345
        $response = new HTTPResponse($body, 500);
346
        throw new HTTPResponse_Exception($response);
347
    }
348
349
    /**
350
     * If missing configuration, redirect to install.php if it exists.
351
     * Otherwise show a server error to the user.
352
     *
353
     * @param string $msg Optional message to show to the user on an installed project (install.php missing).
354
     */
355
    protected function redirectToInstaller($msg = '')
356
    {
357
        // Error if installer not available
358
        if (!file_exists(Director::publicFolder() . '/install.php')) {
359
            throw new HTTPResponse_Exception(
360
                $msg,
361
                500
362
            );
363
        }
364
365
        // Redirect to installer
366
        $response = new HTTPResponse();
367
        $response->redirect(Director::absoluteURL('install.php'));
368
        throw new HTTPResponse_Exception($response);
369
    }
370
371
    /**
372
     * @return ManifestCacheFactory
373
     */
374
    protected function buildManifestCacheFactory()
375
    {
376
        return new ManifestCacheFactory([
377
            'namespace' => 'manifestcache',
378
            'directory' => TEMP_PATH,
379
        ]);
380
    }
381
382
    /**
383
     * When manifests are discovering files, tests files in modules using the following CI library type will be ignored.
384
     *
385
     * The purpose of this method is to avoid loading PHPUnit test files with incompatible definitions.
386
     *
387
     * @return string[] List of CI types to ignore as defined by `Module`.
388
     */
389
    protected function getIgnoredCIConfigs(): array
390
    {
391
        return [];
392
    }
393
394
395
    /**
396
     * @return bool
397
     */
398
    protected function getIncludeTests()
399
    {
400
        return false;
401
    }
402
403
    /**
404
     * @param bool $bool
405
     */
406
    protected function setBooted(bool $bool): void
407
    {
408
        $this->booted = $bool;
409
    }
410
411
    public function shutdown()
412
    {
413
    }
414
415
    public function nest()
416
    {
417
        // Clone this kernel, nesting config / injector manifest containers
418
        $kernel = clone $this;
419
        $kernel->setConfigLoader($this->configLoader->nest());
420
        $kernel->setInjectorLoader($this->injectorLoader->nest());
421
        $kernel->nestedFrom = $this;
422
        return $kernel;
423
    }
424
425
    public function activate()
426
    {
427
        $this->configLoader->activate();
428
        $this->injectorLoader->activate();
429
430
        // Self register
431
        $this->getInjectorLoader()
432
            ->getManifest()
433
            ->registerService($this, Kernel::class);
434
        return $this;
435
    }
436
437
    public function getNestedFrom()
438
    {
439
        return $this->nestedFrom;
440
    }
441
442
    public function getContainer()
443
    {
444
        return $this->getInjectorLoader()->getManifest();
445
    }
446
447
    public function setInjectorLoader(InjectorLoader $injectorLoader)
448
    {
449
        $this->injectorLoader = $injectorLoader;
450
        $injectorLoader
451
            ->getManifest()
452
            ->registerService($this, Kernel::class);
453
        return $this;
454
    }
455
456
    public function getInjectorLoader()
457
    {
458
        return $this->injectorLoader;
459
    }
460
461
    public function getClassLoader()
462
    {
463
        return $this->classLoader;
464
    }
465
466
    public function setClassLoader(ClassLoader $classLoader)
467
    {
468
        $this->classLoader = $classLoader;
469
        return $this;
470
    }
471
472
    public function getModuleLoader()
473
    {
474
        return $this->moduleLoader;
475
    }
476
477
    public function setModuleLoader(ModuleLoader $moduleLoader)
478
    {
479
        $this->moduleLoader = $moduleLoader;
480
        return $this;
481
    }
482
483
    public function setEnvironment($environment)
484
    {
485
        if (!in_array($environment, [self::DEV, self::TEST, self::LIVE, null])) {
486
            throw new InvalidArgumentException(
487
                "Director::set_environment_type passed '$environment'.  It should be passed dev, test, or live"
488
            );
489
        }
490
        $this->enviroment = $environment;
491
        return $this;
492
    }
493
494
    public function getConfigLoader()
495
    {
496
        return $this->configLoader;
497
    }
498
499
    public function setConfigLoader($configLoader)
500
    {
501
        $this->configLoader = $configLoader;
502
        return $this;
503
    }
504
505
    public function getThemeResourceLoader()
506
    {
507
        return $this->themeResourceLoader;
508
    }
509
510
    public function setThemeResourceLoader($themeResourceLoader)
511
    {
512
        $this->themeResourceLoader = $themeResourceLoader;
513
        return $this;
514
    }
515
}
516