Passed
Pull Request — 4 (#10016)
by
unknown
07:28
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
    protected function bootManifests($flush)
181
    {
182
        // Setup autoloader
183
        $this->getClassLoader()->init($this->getIncludeTests(), $flush);
184
185
        // Find modules
186
        $this->getModuleLoader()->init($this->getIncludeTests(), $flush);
187
188
        // Flush config
189
        if ($flush) {
190
            $config = $this->getConfigLoader()->getManifest();
191
            if ($config instanceof CachedConfigCollection) {
192
                $config->setFlush(true);
193
            }
194
        }
195
        // tell modules to sort, now that config is available
196
        $this->getModuleLoader()->getManifest()->sort();
197
198
        // Find default templates
199
        $defaultSet = $this->getThemeResourceLoader()->getSet('$default');
200
        if ($defaultSet instanceof ThemeManifest) {
201
            $defaultSet->setProject(
202
                ModuleManifest::config()->get('project')
203
            );
204
            $defaultSet->init($this->getIncludeTests(), $flush);
205
        }
206
    }
207
208
    /**
209
     * Include all _config.php files
210
     */
211
    protected function bootConfigs()
212
    {
213
        global $project;
214
        $projectBefore = $project;
215
        $config = ModuleManifest::config();
216
        // After loading all other app manifests, include _config.php files
217
        $this->getModuleLoader()->getManifest()->activateConfig();
218
        if ($project && $project !== $projectBefore) {
219
            Deprecation::notice('5.0', '$project global is deprecated');
220
            $config->set('project', $project);
221
        }
222
    }
223
224
    /**
225
     * Turn on error handling
226
     * @throws Exception
227
     */
228
    protected function bootErrorHandling()
229
    {
230
        // Register error handler
231
        $errorHandler = Injector::inst()->get(ErrorHandler::class);
232
        $errorHandler->start();
233
234
        // Register error log file
235
        $errorLog = Environment::getEnv('SS_ERROR_LOG');
236
        if ($errorLog) {
237
            $logger = Injector::inst()->get(LoggerInterface::class);
238
            if ($logger instanceof Logger) {
239
                $logger->pushHandler(new StreamHandler($this->basePath . '/' . $errorLog, Logger::WARNING));
240
            } else {
241
                user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
242
            }
243
        }
244
    }
245
246
247
248
    /**
249
     * Get the environment type
250
     *
251
     * @return string
252
     *
253
     * @deprecated 5.0 use Director::get_environment_type() instead. Since 5.0 it should return only if kernel overrides. No checking SESSION or Environment.
254
     */
255
    public function getEnvironment()
256
    {
257
        // Check set
258
        if ($this->enviroment) {
259
            return $this->enviroment;
260
        }
261
262
        // Check saved session
263
        $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

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