forked from silverstripe/silverstripe-framework
/
Application.php
302 lines (254 loc) · 7.6 KB
/
Application.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
<?php
/**
* @package framework
* @subpackage core
*/
namespace SilverStripe\Framework\Core;
use DB;
use Debug;
use Director;
use SilverStripe\Framework\FrameworkModule;
use SilverStripe\Framework\Injector\Injector;
use SilverStripe\Framework\Injector\ApplicationServiceConfigurationLocator;
use SilverStripe\Framework\Manifest\ClassLoader;
use SilverStripe\Framework\Manifest\Manifest;
/**
* The default implementation of the application interface. The application
* is the main entry point for a SilverStripe application. It serves to
* initialise the environment, hand of control to the {@link Director} class,
* and provide dependencies.
*
* Each application is made up of a number of modules - the framework is itself
* a module. Each application subclass needs to define a `getBasePath` method,
* and also a `registerModules` method to register modules that are a part of
* the application:
*
* <code>
* class ExampleApplication extends Application {
*
* public function getBasePath() {
* return dirname(__DIR__);
* }
*
* protected function registerModules() {
* $this->registerModule('name', 'path/to/module');
* parent::registerModules();
* }
*
* }
* </code>
*
* It has the following responsibilities:
* <ul>
* <li>Provide a list of modules making up the application</li>
* <li>Get the paths for various parts of the application</li>
* <li>Initialise and provide access to the manifest and loaders</li>
* <li>Provide access to the application injector and config objects.</li>
* <li>Generate responses to incoming requests</li>
* </ul>
*
* @package framework
* @subpackage core
* @see ComposerApplication
* @see WebrootApplication
*/
abstract class Application implements ApplicationInterface {
private static $curr;
protected $modules;
protected $manifest;
protected $config;
protected $injector;
protected $classLoader;
protected $tempPath;
/**
* Returns the currently active application instance.
*
* @return Application
*/
public static function curr() {
return self::$curr;
}
public static function respond() {
$app = new static();
$app->start();
$app->handle()->output();
$app->stop();
}
public function __construct() {
$this->modules = new ModuleSet($this);
$this->registerModules();
}
public function start() {
// Register this application as the current one
self::$curr = $this;
// Bootstrap the environment
Bootstrap::bootstrap($this);
// Create the manifest, and register loaders
$this->initManifest();
$this->initClassLoader();
// Create the config and then use it to create the injector, which will
// be used for later dependencies
$this->createInjector();
$this->initConfig();
$this->initInjector();
// Register the created objects with the injector
$injector = $this->getInjector();
$injector->registerNamedService('Config', $this->getConfig());
$injector->registerNamedService('Application', $this);
$injector->registerNamedService('Manifest', $this->getManifest());
$injector->registerNamedService('ClassLoader', $this->getClassLoader());
$injector->registerNamedService('PhpManifest', $this->getManifest()->getPhpManifest());
$injector->registerNamedService('ConfigManifest', $this->getManifest()->getConfigManifest());
$injector->registerNamedService('TemplateManifest', $this->getManifest()->getTemplateManifest());
// @todo This code should be moved elsewhere
global $databaseConfig;
DB::connect($databaseConfig);
if(Director::isLive()) {
error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
}
Debug::loadErrorHandlers();
}
public function stop() {
if(self::$curr !== $this) {
throw new \Exception('The application is not currently running');
}
self::$curr = null;
}
public function handle() {
return $this->injector->get('Director')->direct();
}
public function get($name) {
return $this->getInjector()->get($name);
}
/**
* @return ModuleSet
*/
public function getModules() {
return $this->modules;
}
/**
* @return ModuleInterface|null
*/
public function getModule($name) {
return $this->modules->get($name);
}
public function getManifest() {
return $this->manifest;
}
/**
* @param Manifest $manifest
*/
public function setManifest(Manifest $manifest) {
$this->manifest = $manifest;
}
public function getConfig() {
return $this->config;
}
/**
* @param Config $config
*/
public function setConfig(Config $config) {
$this->config = $config;
}
/**
* @return \SilverStripe\Framework\Injector\Injector
*/
public function getInjector() {
return $this->injector;
}
public function getClassLoader() {
return $this->classLoader;
}
public function getPublicPath() {
return $this->getBasePath() . '/public';
}
public function getAssetsPath() {
return $this->getPublicPath() . '/' . ASSETS_DIR;
}
/**
* Returns the path to the app-specific temp directory, creating one if
* one doesn't exist.
*
* @return string
*/
public function getTempPath() {
if(!$this->tempPath) {
$base = $this->getBasePath();
if(is_dir("$base/silverstripe-cache")) {
return $this->tempPath = "$base/silverstripe-cache";
}
$tmp = sys_get_temp_dir();
$name = 'silverstripe-cache' . preg_replace('/[^a-zA-Z0-9-]/', '-', $base);
$path = "$tmp/$name";
if(!is_dir($path)) {
mkdir($path);
if(!is_dir($path)) {
throw new \Exception(
'Could not gain access to a temp folder. Please create ' .
'a directory called "silverstripe-cache" in your ' .
'application base directory.'
);
}
}
$this->tempPath = $path;
}
return $this->tempPath;
}
/**
* Registers the module instances for this application.
*/
protected function registerModules() {
$this->registerModule(new FrameworkModule());
}
/**
* Registers a module. This can either be passed a {@link ModuleInterface}
* instance, or the module name and path. The path can either be absolute
* or relative to the base path.
*
* @param ModuleInterface|string $module
* @param string $path
* @param string $type
* @see ModuleSet
*/
protected function registerModule() {
if(func_num_args() == 1) {
call_user_func_array(array($this->modules, 'add'), func_get_args());
} else {
call_user_func_array(array($this->modules, 'addFromDetails'), func_get_args());
}
}
/**
* Creates and initialises the application manifest.
*/
protected function initManifest() {
$this->manifest = new Manifest($this);
$this->manifest->init(isset($_GET['flush']));
}
/**
* Creates and initialises the application config instance.
*/
protected function initConfig() {
$this->config = new Config($this->manifest->getConfigManifest());
$this->config->init();
}
/**
* Createss the injector but does not initialise it. This must be done in
* two stages as initialisation requires the config to be available.
*/
protected function createInjector() {
$this->injector = new Injector();
}
/**
* Initialises the previously created injector.
*/
protected function initInjector() {
$this->getInjector()->setConfigLocator(new ApplicationServiceConfigurationLocator($this));
}
/**
* Creates and initialises the class loader instance.
*/
protected function initClassLoader() {
$this->classLoader = new ClassLoader($this->manifest->getPhpManifest());
$this->classLoader->register();
}
}