Passed
Pull Request — 4 (#10016)
by
unknown
07:28
created

CoreKernel::setInjectorLoader()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core;
4
5
use SilverStripe\Control\HTTPResponse_Exception;
6
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
7
use SilverStripe\ORM\DB;
8
use Exception;
9
10
/**
11
 * Simple Kernel container
12
 */
13
class CoreKernel extends BaseKernel
14
{
15
16
    /**
17
     * Indicates whether the Kernel has been flushed on boot
18
     * Uninitialised before boot
19
     *
20
     * @var bool
21
     */
22
    private $flush;
23
24
    /**
25
     * @param false $flush
26
     * @throws HTTPResponse_Exception
27
     * @throws Exception
28
     */
29
    public function boot($flush = false)
30
    {
31
        $this->flush = $flush;
32
33
        $this->bootPHP();
34
        $this->bootManifests($flush);
35
        $this->bootErrorHandling();
36
        $this->bootDatabaseEnvVars();
37
        $this->bootConfigs();
38
        $this->bootDatabaseGlobals();
39
        $this->validateDatabase();
40
41
        $this->setBooted(true);
42
    }
43
44
    /**
45
     * Check that the database configuration is valid, throwing an HTTPResponse_Exception if it's not
46
     *
47
     * @throws HTTPResponse_Exception
48
     */
49
    protected function validateDatabase()
50
    {
51
        $databaseConfig = DB::getConfig();
52
        // Gracefully fail if no DB is configured
53
        if (empty($databaseConfig['database'])) {
54
            $msg = 'Silverstripe Framework requires a "database" key in DB::getConfig(). ' .
55
                'Did you forget to set SS_DATABASE_NAME or SS_DATABASE_CHOOSE_NAME in your environment?';
56
            $this->detectLegacyEnvironment();
57
            $this->redirectToInstaller($msg);
58
        }
59
    }
60
61
    /**
62
     * Load default database configuration from the $database and $databaseConfig globals
63
     */
64
    protected function bootDatabaseGlobals()
65
    {
66
        // Now that configs have been loaded, we can check global for database config
67
        global $databaseConfig;
68
        global $database;
69
70
        // Case 1: $databaseConfig global exists. Merge $database in as needed
71
        if (!empty($databaseConfig)) {
72
            if (!empty($database)) {
73
                $databaseConfig['database'] =  $this->getDatabasePrefix() . $database . $this->getDatabaseSuffix();
74
            }
75
76
            // Only set it if its valid, otherwise ignore $databaseConfig entirely
77
            if (!empty($databaseConfig['database'])) {
78
                DB::setConfig($databaseConfig);
79
80
                return;
81
            }
82
        }
83
84
        // Case 2: $database merged into existing config
85
        if (!empty($database)) {
86
            $existing = DB::getConfig();
87
            $existing['database'] = $this->getDatabasePrefix() . $database . $this->getDatabaseSuffix();
88
89
            DB::setConfig($existing);
90
        }
91
    }
92
93
    /**
94
     * Load default database configuration from environment variable
95
     */
96
    protected function bootDatabaseEnvVars()
97
    {
98
        // Set default database config
99
        $databaseConfig = $this->getDatabaseConfig();
100
        $databaseConfig['database'] = $this->getDatabaseName();
101
        DB::setConfig($databaseConfig);
102
    }
103
104
    /**
105
     * Load database config from environment
106
     *
107
     * @return array
108
     */
109
    protected function getDatabaseConfig()
110
    {
111
        /** @skipUpgrade */
112
        $databaseConfig = [
113
            "type" => Environment::getEnv('SS_DATABASE_CLASS') ?: 'MySQLDatabase',
114
            "server" => Environment::getEnv('SS_DATABASE_SERVER') ?: 'localhost',
115
            "username" => Environment::getEnv('SS_DATABASE_USERNAME') ?: null,
116
            "password" => Environment::getEnv('SS_DATABASE_PASSWORD') ?: null,
117
        ];
118
119
        // Set the port if called for
120
        $dbPort = Environment::getEnv('SS_DATABASE_PORT');
121
        if ($dbPort) {
122
            $databaseConfig['port'] = $dbPort;
123
        }
124
125
        // Set the timezone if called for
126
        $dbTZ = Environment::getEnv('SS_DATABASE_TIMEZONE');
127
        if ($dbTZ) {
128
            $databaseConfig['timezone'] = $dbTZ;
129
        }
130
131
        // For schema enabled drivers:
132
        $dbSchema = Environment::getEnv('SS_DATABASE_SCHEMA');
133
        if ($dbSchema) {
134
            $databaseConfig["schema"] = $dbSchema;
135
        }
136
137
        // For SQlite3 memory databases (mainly for testing purposes)
138
        $dbMemory = Environment::getEnv('SS_DATABASE_MEMORY');
139
        if ($dbMemory) {
140
            $databaseConfig["memory"] = $dbMemory;
141
        }
142
143
        // Allow database adapters to handle their own configuration
144
        DatabaseAdapterRegistry::autoconfigure($databaseConfig);
145
        return $databaseConfig;
146
    }
147
148
    /**
149
     * @return string
150
     */
151
    protected function getDatabasePrefix()
152
    {
153
        return Environment::getEnv('SS_DATABASE_PREFIX') ?: '';
154
    }
155
156
    /**
157
     * @return string
158
     */
159
    protected function getDatabaseSuffix()
160
    {
161
        return Environment::getEnv('SS_DATABASE_SUFFIX') ?: '';
162
    }
163
164
    /**
165
     * Get name of database
166
     *
167
     * @return string
168
     */
169
    protected function getDatabaseName()
170
    {
171
        // Check globals
172
        global $database;
173
174
        if (!empty($database)) {
175
            return $this->getDatabasePrefix() . $database . $this->getDatabaseSuffix();
176
        }
177
178
        global $databaseConfig;
179
180
        if (!empty($databaseConfig['database'])) {
181
            return $databaseConfig['database']; // Note: Already includes prefix
182
        }
183
184
        // Check environment
185
        $database = Environment::getEnv('SS_DATABASE_NAME');
186
187
        if ($database) {
188
            return $this->getDatabasePrefix() . $database . $this->getDatabaseSuffix();
189
        }
190
191
        // Auto-detect name
192
        $chooseName = Environment::getEnv('SS_DATABASE_CHOOSE_NAME');
193
194
        if ($chooseName) {
195
            // Find directory to build name from
196
            $loopCount = (int)$chooseName;
197
            $databaseDir = $this->basePath;
198
            for ($i = 0; $i < $loopCount-1; $i++) {
199
                $databaseDir = dirname($databaseDir);
200
            }
201
202
            // Build name
203
            $database = str_replace('.', '', basename($databaseDir));
204
            $prefix = $this->getDatabasePrefix();
205
206
            if ($prefix) {
207
                $prefix = 'SS_';
208
            } else {
209
                // If no prefix, hard-code prefix into database global
210
                $prefix = '';
211
                $database = 'SS_' . $database;
212
            }
213
214
            return $prefix . $database;
215
        }
216
217
        // no DB name (may be optional for some connectors)
218
        return null;
219
    }
220
221
    /**
222
     * Returns whether the Kernel has been flushed on boot
223
     *
224
     * @return bool|null null if the kernel hasn't been booted yet
225
     */
226
    public function isFlushed()
227
    {
228
        return $this->flush;
229
    }
230
}
231