1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
/* |
3
|
|
|
* This file is part of the SamsonPHP\Core package. |
4
|
|
|
* (c) 2013 Vitaly Iegorov <[email protected]> |
5
|
|
|
* |
6
|
|
|
* For the full copyright and license information, please view the LICENSE |
7
|
|
|
* file that was distributed with this source code. |
8
|
|
|
*/ |
9
|
|
|
namespace samson\core; |
10
|
|
|
|
11
|
|
|
use samsonframework\container\Builder; |
12
|
|
|
use samsonframework\container\metadata\ClassMetadata; |
13
|
|
|
use samsonframework\container\metadata\MethodMetadata; |
14
|
|
|
use samsonframework\core\SystemInterface; |
15
|
|
|
use samsonframework\di\ContainerInterface; |
16
|
|
|
use samsonframework\resource\ResourceMap; |
17
|
|
|
use samsonphp\config\Scheme; |
18
|
|
|
use samsonphp\core\exception\CannotLoadModule; |
19
|
|
|
use samsonphp\core\exception\ViewPathNotFound; |
20
|
|
|
use samsonphp\event\Event; |
21
|
|
|
use samsonframework\container\ContainerBuilderInterface; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* SamsonPHP Core. |
25
|
|
|
* |
26
|
|
|
* @author Vitaly Iegorov <[email protected]> |
27
|
|
|
*/ |
28
|
|
|
class Core implements SystemInterface |
29
|
|
|
{ |
30
|
|
|
/** @var ContainerInterface */ |
31
|
|
|
protected $container; |
32
|
|
|
|
33
|
|
|
/** @var ClassMetadata[] */ |
34
|
|
|
protected $metadataCollection = []; |
35
|
|
|
|
36
|
|
|
/** @var ContainerBuilderInterface */ |
37
|
|
|
protected $builder; |
38
|
|
|
|
39
|
|
|
/** @var string Current system environment */ |
40
|
|
|
protected $environment; |
41
|
|
|
|
42
|
|
|
/* Rendering models */ |
43
|
|
|
/** @deprecated Standard algorithm for view rendering */ |
44
|
|
|
const RENDER_STANDART = 1; |
45
|
|
|
/** @deprecated View rendering algorithm from array of view variables */ |
46
|
|
|
const RENDER_VARIABLE = 3; |
47
|
|
|
|
48
|
|
|
/** @deprecated @var ResourceMap Current web-application resource map */ |
49
|
|
|
public $map; |
50
|
|
|
|
51
|
|
|
/** @deprecated @var string Path to current web-application */ |
52
|
|
|
public $system_path = __SAMSON_CWD__; |
53
|
|
|
/** @deprecated @var string View path loading mode */ |
54
|
|
|
public $render_mode = self::RENDER_STANDART; |
55
|
|
|
/** @var Module Pointer to current active module */ |
56
|
|
|
protected $active = null; |
57
|
|
|
/** @var bool Flag for outputting layout template, used for asynchronous requests */ |
58
|
|
|
protected $async = false; |
59
|
|
|
/** @var string Path to main system template */ |
60
|
|
|
protected $template_path = __SAMSON_DEFAULT_TEMPLATE; |
61
|
|
|
|
62
|
|
|
/** @return ContainerInterface Get system container */ |
63
|
|
|
public function getContainer() |
64
|
|
|
{ |
65
|
|
|
return $this->container; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Core constructor. |
70
|
|
|
* |
71
|
|
|
* @param ContainerBuilderInterface $builder Container builder |
72
|
|
|
* @param ResourceMap|null $map system resources |
73
|
|
|
*/ |
74
|
|
|
public function __construct(ContainerBuilderInterface $builder, ResourceMap $map = null) |
75
|
|
|
{ |
76
|
|
|
$this->builder = $builder; |
77
|
|
|
|
78
|
|
|
if (!isset($map)) { |
79
|
|
|
// Get correct web-application path |
80
|
|
|
$this->system_path = __SAMSON_CWD__; |
|
|
|
|
81
|
|
|
|
82
|
|
|
// Get web-application resource map |
83
|
|
|
$this->map = ResourceMap::get($this->system_path, false, array('src/')); |
|
|
|
|
84
|
|
|
} else { // Use data from passed map |
85
|
|
|
$this->map = $map; |
|
|
|
|
86
|
|
|
$this->system_path = $map->entryPoint; |
|
|
|
|
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
// Temporary add template worker |
90
|
|
|
$this->subscribe('core.rendered', array($this, 'generateTemplate')); |
91
|
|
|
|
92
|
|
|
// TODO: Shoud be configurable not fixed integration |
93
|
|
|
$whoops = new \Whoops\Run; |
94
|
|
|
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler); |
|
|
|
|
95
|
|
|
$whoops->register(); |
96
|
|
|
|
97
|
|
|
// Fire core creation event |
98
|
|
|
Event::fire('core.created', array(&$this)); |
99
|
|
|
|
100
|
|
|
// Signal core configure event |
101
|
|
|
Event::signal('core.configure', array($this->system_path . __SAMSON_CONFIG_PATH)); |
|
|
|
|
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Generic wrap for Event system subscription. |
106
|
|
|
* @see \samson\core\\samsonphp\event\Event::subscribe() |
107
|
|
|
* |
108
|
|
|
* @param string $key Event identifier |
109
|
|
|
* @param callable $handler Event handler |
110
|
1 |
|
* @param array $params Event parameters |
111
|
|
|
* |
112
|
|
|
* @return $this Chaining |
113
|
|
|
*/ |
114
|
|
|
public function subscribe($key, $handler, $params = array()) |
115
|
|
|
{ |
116
|
|
|
Event::subscribe($key, $handler, $params); |
117
|
|
|
|
118
|
|
|
return $this; |
119
|
|
|
} |
120
|
|
|
|
121
|
1 |
|
/** |
122
|
|
|
* Change current system working environment or receive |
123
|
|
|
* current system enviroment if no arguments are passed. |
124
|
|
|
* |
125
|
|
|
* @param string $environment Environment identifier |
126
|
|
|
* |
127
|
|
|
* TODO: Function has two different logics - needs to be changed! |
128
|
|
|
* @return $this|string Chaining or current system environment |
129
|
|
|
*/ |
130
|
|
|
public function environment($environment = Scheme::BASE) |
131
|
|
|
{ |
132
|
|
|
if (func_num_args() !== 0) { |
133
|
|
|
$this->environment = $environment; |
134
|
|
|
|
135
|
|
|
// Signal core environment change |
136
|
|
|
Event::signal('core.environment.change', array($environment, &$this)); |
137
|
|
|
return $this; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
return $this->environment; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
/** |
144
|
|
|
* Generate special response header triggering caching mechanisms |
145
|
|
|
* @param int $cacheLife Amount of seconds for cache(default 3600 - 1 hour) |
146
|
|
|
* @param string $accessibility Cache-control accessibility value(default public) |
147
|
|
|
*/ |
148
|
|
|
public function cached($cacheLife = 3600, $accessibility = 'public') |
149
|
|
|
{ |
150
|
|
|
static $cached; |
151
|
|
|
// Protect sending cached headers once |
152
|
|
|
if (!isset($cached) or $cached !== true) { |
153
|
|
|
header('Expires: ' . gmdate('D, d M Y H:i:s T', time() + $cacheLife)); |
154
|
|
|
header('Cache-Control: ' . $accessibility . ', max-age=' . $cacheLife); |
155
|
|
|
header('Pragma: cache'); |
156
|
|
|
|
157
|
|
|
$cached = true; |
158
|
|
|
} |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Set asynchronous mode. |
163
|
|
|
* This mode will not output template and will just path everything that |
164
|
|
|
* was outputted to client. |
165
|
|
|
* |
166
|
|
|
* @param bool $async True to switch to asynchronous output mode |
167
|
|
|
* |
168
|
|
|
* @return $this Chaining |
169
|
|
|
*/ |
170
|
|
|
public function async($async) |
171
|
|
|
{ |
172
|
|
|
$this->async = $async; |
173
|
|
|
|
174
|
|
|
return $this; |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** @see iCore::path() */ |
178
|
|
|
public function path($path = null) |
179
|
|
|
{ |
180
|
|
|
// Если передан аргумент |
181
|
|
|
if (func_num_args()) { |
182
|
|
|
// Сформируем новый относительный путь к главному шаблону системы |
183
|
|
|
$this->template_path = $path . $this->template_path; |
184
|
|
|
|
185
|
|
|
// Сохраним относительный путь к Веб-приложению |
186
|
|
|
$this->system_path = $path; |
|
|
|
|
187
|
|
|
|
188
|
|
|
// Продолжил цепирование |
189
|
|
|
return $this; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
// Вернем текущее значение |
193
|
|
|
return $this->system_path; |
|
|
|
|
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** @see iModule::active() */ |
197
|
|
|
public function &active(iModule &$module = null) |
198
|
|
|
{ |
199
|
|
|
// Сохраним старый текущий модуль |
200
|
|
|
$old = &$this->active; |
201
|
|
|
|
202
|
|
|
// Если передано значение модуля для установки как текущий - проверим и установим его |
203
|
|
|
if (isset($module)) { |
204
|
|
|
$this->active = &$module; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
// Вернем значение текущего модуля |
208
|
|
|
return $old; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Retrieve module instance by identifier. |
213
|
|
|
* |
214
|
|
|
* @param string|null $module Module identifier |
215
|
|
|
* |
216
|
|
|
* @return null|Module Found or active module |
217
|
|
|
*/ |
218
|
|
|
public function &module($module = null) |
219
|
|
|
{ |
220
|
|
|
$return = null; |
221
|
|
|
|
222
|
|
|
// Ничего не передано - вернем текущуй модуль системы |
223
|
|
|
if (!isset($module) && isset($this->active)) { |
224
|
|
|
$return = &$this->active; |
225
|
|
|
} elseif (is_object($module)) { |
226
|
|
|
$return = &$module; |
227
|
|
|
} elseif (is_string($module)) { |
228
|
|
|
$return = $this->container->get($module); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
// Ничего не получилось вернем ошибку |
232
|
|
|
if ($return === null) { |
233
|
|
|
e('Не возможно получить модуль(##) системы', E_SAMSON_CORE_ERROR, array($module)); |
|
|
|
|
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
return $return; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Unload module from core. |
241
|
|
|
* |
242
|
|
|
* @param string $moduleID Module identifier |
243
|
|
|
*/ |
244
|
|
|
public function unload($moduleID) |
245
|
|
|
{ |
246
|
|
|
if (isset($this->module_stack[$moduleID])) { |
|
|
|
|
247
|
|
|
unset($this->module_stack[$moduleID]); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Insert generic html template tags and data |
253
|
|
|
* |
254
|
|
|
* @param string $templateHtml Generated HTML |
255
|
|
|
* |
256
|
|
|
* @deprecated Must be moved to a new HTML output object |
257
|
|
|
* @return mixed Changed HTML template |
258
|
|
|
*/ |
259
|
|
|
public function generateTemplate(&$templateHtml) |
260
|
|
|
{ |
261
|
|
|
// Добавим путь к ресурсам для браузера |
262
|
|
|
$headHtml = "\n" . '<base href="' . url()->base() . '">'; |
263
|
|
|
// Добавим отметку времени для JavaScript |
264
|
2 |
|
$headHtml .= "\n" . '<script type="text/javascript">var __SAMSONPHP_STARTED = new Date().getTime();</script>'; |
265
|
|
|
|
266
|
|
|
// Добавим поддержку HTML для старых IE |
267
|
|
|
$headHtml .= "\n" . '<!--[if lt IE 9]>'; |
268
|
|
|
$headHtml .= "\n" . '<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>'; |
269
|
|
|
$headHtml .= "\n" . '<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>'; |
270
|
|
|
$headHtml .= "\n" . '<![endif]-->'; |
271
|
2 |
|
|
272
|
|
|
// Выполним вставку главного тега <base> от которого зависят все ссылки документа |
273
|
|
|
// также подставим МЕТА-теги для текущего модуля и сгенерированный минифицированный CSS |
274
|
2 |
|
$templateHtml = str_ireplace('<head>', '<head>' . $headHtml, $templateHtml); |
275
|
|
|
|
276
|
|
|
// Вставим указатель JavaScript ресурсы в конец HTML документа |
277
|
|
|
$templateHtml = str_ireplace('</html>', '</html>' . __SAMSON_COPYRIGHT, $templateHtml); |
278
|
2 |
|
|
279
|
|
|
return $templateHtml; |
280
|
2 |
|
} |
281
|
|
|
|
282
|
2 |
|
/** |
283
|
2 |
|
* Start SamsonPHP framework. |
284
|
|
|
* |
285
|
|
|
* @param string $default Default module identifier |
286
|
2 |
|
* |
287
|
|
|
* @throws ViewPathNotFound |
288
|
2 |
|
*/ |
289
|
|
|
public function start($default) |
290
|
2 |
|
{ |
291
|
|
|
// TODO: Change ExternalModule::init() signature |
292
|
|
|
// Fire core started event |
293
|
|
|
Event::fire('core.started'); |
294
|
|
|
|
295
|
2 |
|
// TODO: Does not see why it should be here |
296
|
|
|
// Set main template path |
297
|
|
|
$this->template($this->template_path); |
298
|
|
|
|
299
|
|
|
// Security layer |
300
|
|
|
$securityResult = true; |
301
|
|
|
// Fire core security event |
302
|
|
|
Event::fire('core.security', array(&$this, &$securityResult)); |
303
|
|
|
|
304
|
|
|
/** @var mixed $result External route controller action result */ |
305
|
|
|
$result = false; |
306
|
|
|
|
307
|
|
|
// If we have passed security application layer |
308
|
|
|
if ($securityResult) { |
309
|
|
|
// Fire core routing event - go to routing application layer |
310
|
|
|
Event::signal('core.routing', array(&$this, &$result, $default)); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
// If no one has passed back routing callback |
314
|
|
|
if (!isset($result) || $result === false) { |
315
|
|
|
// Fire core e404 - routing failed event |
316
|
|
|
$result = Event::signal('core.e404', array(url()->module, url()->method)); |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
// Response |
320
|
2 |
|
$output = ''; |
321
|
|
|
|
322
|
|
|
// If this is not asynchronous response and controller has been executed |
323
|
2 |
|
if (!$this->async && ($result !== false)) { |
324
|
|
|
// Store module data |
325
|
|
|
$data = $this->active->toView(); |
326
|
2 |
|
|
327
|
|
|
// Render main template |
328
|
|
|
$output = $this->render($this->template_path, $data); |
329
|
2 |
|
|
330
|
|
|
// Fire after render event |
331
|
|
|
Event::fire('core.rendered', array(&$output)); |
332
|
2 |
|
} |
333
|
|
|
|
334
|
|
|
// Output results to client |
335
|
2 |
|
echo $output; |
336
|
|
|
|
337
|
|
|
// Fire ended event |
338
|
2 |
|
Event::fire('core.ended', array(&$output)); |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** @see iCore::template() */ |
342
|
|
|
public function template( $template = NULL, $absolutePath = false ) |
|
|
|
|
343
|
|
|
{ |
344
|
|
|
// Если передан аргумент |
345
|
|
|
if( func_num_args() ){ |
|
|
|
|
346
|
|
|
$this->template_path = ($absolutePath)?$template:$this->active->path().$template; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
// Аргументы не переданы - вернем текущий путь к шаблону системы |
350
|
|
|
return $this->template_path; |
351
|
|
|
} |
352
|
7 |
|
|
353
|
|
|
/** |
354
|
7 |
|
* Render file to a buffer. |
355
|
|
|
* |
356
|
7 |
|
* @param string $view Path to file |
357
|
|
|
* @param array $data Collection of variables to path to file |
358
|
|
|
* |
359
|
|
|
* @return string Rendered file contents |
360
|
|
|
* @throws ViewPathNotFound |
361
|
|
|
*/ |
362
|
|
|
public function render($view, $data = array()) |
363
|
|
|
{ |
364
|
|
|
// TODO: Make rendering as external system, to split up these 3 rendering options |
365
|
|
|
|
366
|
|
|
// Объявить ассоциативный массив переменных в данном контексте |
367
|
|
|
if (is_array($data)) { |
368
|
|
|
extract($data); |
369
|
|
|
} |
370
|
|
|
|
371
|
|
|
// Начать вывод в буффер |
372
|
|
|
ob_start(); |
373
|
|
|
|
374
|
|
|
// Path to another template view, by default we are using default template folder path, |
375
|
|
|
// for meeting first condition |
376
|
|
|
$templateView = $view; |
377
|
|
|
|
378
|
|
|
if (locale() != SamsonLocale::DEF) { |
379
|
|
|
// Modify standard view path with another template |
380
|
|
|
$templateView = str_replace(__SAMSON_VIEW_PATH, __SAMSON_VIEW_PATH . locale() . '/', $templateView); |
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
// Depending on core view rendering model |
384
|
|
|
switch ($this->render_mode) { |
|
|
|
|
385
|
|
|
// Standard algorithm for view rendering |
386
|
|
|
case self::RENDER_STANDART: |
|
|
|
|
387
|
|
|
// Trying to find another template path, by default it's an default template path |
388
|
|
|
if (file_exists($templateView)) { |
389
|
|
|
include($templateView); |
390
|
|
|
} elseif (file_exists($view)) { |
391
|
|
|
// If another template wasn't found - we will use default template path |
392
|
|
|
include($view); |
393
|
|
|
} else { // Error no template view was found |
394
|
|
|
throw(new ViewPathNotFound($view)); |
395
|
|
|
} |
396
|
|
|
break; |
397
|
|
|
|
398
|
|
|
// View rendering algorithm from array of view variables |
399
|
|
|
case self::RENDER_VARIABLE: |
|
|
|
|
400
|
|
|
// Collection of views |
401
|
|
|
$views = &$GLOBALS['__compressor_files']; |
402
|
|
|
// Trying to find another template path, by default it's an default template path |
403
|
2 |
|
if (isset($views[$templateView])) { |
404
|
|
|
eval(' ?>' . $views[$templateView] . '<?php '); |
405
|
|
|
} elseif (isset($views[$view])) { |
406
|
2 |
|
// If another template wasn't found - we will use default template path |
407
|
|
|
eval(' ?>' . $views[$view] . '<?php '); |
408
|
|
|
} else { // Error no template view was found |
409
|
2 |
|
throw(new ViewPathNotFound($view)); |
410
|
2 |
|
} |
411
|
2 |
|
break; |
412
|
|
|
} |
413
|
|
|
|
414
|
2 |
|
// Получим данные из буффера вывода |
415
|
|
|
$html = ob_get_contents(); |
416
|
|
|
|
417
|
|
|
// Очистим буффер |
418
|
|
|
ob_end_clean(); |
419
|
|
|
|
420
|
|
|
// Fire core render event |
421
|
|
|
Event::fire('core.render', array(&$html, &$data, &$this->active)); |
422
|
|
|
|
423
|
|
|
////elapsed('End rendering '.$__view); |
424
|
|
|
return $html; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
//[PHPCOMPRESSOR(remove,start)] |
428
|
|
|
|
429
|
|
|
/** |
430
|
|
|
* Load system from composer.json |
431
|
|
|
* @param string $dependencyFilePath Path to dependencies file |
432
|
|
|
* @return $this Chaining |
433
|
|
|
*/ |
434
|
|
|
public function composer($dependencyFilePath = null) |
435
|
|
|
{ |
436
|
|
|
$composerModules = array(); |
437
|
|
|
|
438
|
|
|
Event::fire( |
439
|
|
|
'core.composer.create', |
440
|
|
|
array( |
441
|
|
|
&$composerModules, |
442
|
|
|
isset($dependencyFilePath) ? $dependencyFilePath : $this->system_path, |
|
|
|
|
443
|
|
|
array( |
444
|
|
|
'vendorsList' => array('samsonphp/', 'samsonos/', 'samsoncms/', 'samsonjavascript/'), |
445
|
|
|
'ignoreKey' => 'samson_module_ignore', |
446
|
|
|
'includeKey' => 'samson_module_include' |
447
|
|
|
) |
448
|
|
|
) |
449
|
|
|
); |
450
|
|
|
|
451
|
|
|
$modulesToLoad = []; |
452
|
|
|
|
453
|
|
|
// Iterate requirements |
454
|
|
|
foreach ($composerModules as $requirement => $parameters) { |
455
|
|
|
$moduleName = $this->load(__SAMSON_CWD__ . __SAMSON_VENDOR_PATH . $requirement, |
456
|
|
|
array_merge( |
457
|
|
|
is_array($parameters) ? $parameters : array($parameters), |
458
|
|
|
array('module_id' => $requirement) |
459
|
|
|
)); |
460
|
|
|
|
461
|
|
|
$modulesToLoad[$moduleName] = $parameters; |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
$localModulesPath = '../src'; |
465
|
|
|
ResourceMap::get('cache'); |
466
|
|
|
// TODO: Nested modules relation |
467
|
|
|
for ($i = 0; $i < 2; $i++) { |
468
|
|
|
$resourceMap = ResourceMap::get($localModulesPath); |
469
|
|
|
|
470
|
|
|
foreach ($resourceMap->modules as $moduleFile) { |
471
|
|
|
$modulePath = str_replace(realpath($localModulesPath), '', $moduleFile[1]); |
472
|
|
|
$modulePath = explode('/', $modulePath); |
473
|
|
|
$modulePath = $localModulesPath . '/' . $modulePath[1]; |
474
|
|
|
$moduleName = $this->load($modulePath, $parameters); |
|
|
|
|
475
|
|
|
$modulesToLoad[$moduleName] = $parameters; |
476
|
|
|
} |
477
|
|
|
} |
478
|
|
|
|
479
|
|
|
//$this->active = new VirtualModule($this->system_path, $this->map, $this, 'local'); |
480
|
|
|
|
481
|
|
|
// Create local module and set it as active |
482
|
|
|
$this->createMetadata(VirtualModule::class, 'local', $this->system_path); |
|
|
|
|
483
|
|
|
|
484
|
|
|
// TODO: This should be changed to one single logic |
485
|
|
|
// Require all local module model files |
486
|
|
|
foreach ($this->map->models as $model) { |
|
|
|
|
487
|
|
|
// TODO: Why have to require once? |
488
|
|
|
require_once($model); |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
// Create all local modules |
492
|
|
|
foreach ($this->map->controllers as $controller) { |
|
|
|
|
493
|
|
|
// Require class into PHP |
494
|
|
|
require($controller); |
495
|
|
|
|
496
|
|
|
//new VirtualModule($this->system_path, $this->map, $this, basename($controller, '.php')); |
497
|
|
|
|
498
|
|
|
$this->createMetadata(VirtualModule::class, basename($controller, '.php'), $this->system_path); |
|
|
|
|
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
$this->createMetadata(get_class($this), get_class($this), $this->system_path); |
|
|
|
|
502
|
|
|
|
503
|
|
|
$metadata = new ClassMetadata(); |
504
|
|
|
$metadata->className = get_class($this); |
505
|
|
|
$metadata->name = get_class($this); |
506
|
|
|
$metadata->scopes[] = Builder::SCOPE_SERVICES; |
507
|
|
|
$metadata->methodsMetadata['__construct'] = new MethodMetadata($metadata); |
508
|
|
|
$metadata->methodsMetadata['__construct']->dependencies['map'] = ResourceMap::class; |
509
|
|
|
|
510
|
|
|
$this->metadataCollection[$metadata->name] = $metadata; |
511
|
|
|
|
512
|
|
|
$metadata = new ClassMetadata(); |
513
|
|
|
$metadata->className = ResourceMap::class; |
514
|
|
|
$metadata->name = ResourceMap::class; |
515
|
|
|
$metadata->scopes[] = Builder::SCOPE_SERVICES; |
516
|
|
|
|
517
|
|
|
$this->metadataCollection[$metadata->name] = $metadata; |
518
|
|
|
$containerPath = $this->path().'www/cache/Container.php'; |
519
|
|
|
|
520
|
|
|
file_put_contents($containerPath, $this->builder->build($this->metadataCollection)); |
521
|
|
|
|
522
|
|
|
require_once($containerPath); |
523
|
|
|
|
524
|
|
|
$this->container = new \Container(); |
|
|
|
|
525
|
|
|
$containerReflection = new \ReflectionClass(get_class($this->container)); |
526
|
|
|
$serviceProperty = $containerReflection->getProperty('servicesInstances'); |
527
|
|
|
$serviceProperty->setAccessible(true); |
528
|
|
|
$containerServices = $serviceProperty->getValue($this->container); |
529
|
|
|
$containerServices[get_class($this)] = $this; |
530
|
|
|
$serviceProperty->setValue(null, $containerServices); |
531
|
|
|
$serviceProperty->setAccessible(false); |
532
|
|
|
|
533
|
|
|
foreach ($modulesToLoad as $name => $parameters) { |
534
|
|
|
$instance = $this->container->get($name); |
535
|
|
|
$this->initModule($instance, $parameters); |
536
|
|
|
} |
537
|
|
|
|
538
|
|
|
$this->active = $this->container->getLocal(); |
539
|
|
|
|
540
|
|
|
return $this; |
541
|
|
|
} |
542
|
|
|
|
543
|
|
|
/** |
544
|
|
|
* Initialize module. |
545
|
|
|
* |
546
|
|
|
* @param ExternalModule $instance Module instance for initialization |
547
|
|
|
* @param array $composerParameters Collection of extra parameters from composer.json file |
548
|
|
|
*/ |
549
|
|
|
protected function initModule($instance, $composerParameters) |
550
|
|
|
{ |
551
|
|
|
$identifier = $instance->id(); |
552
|
|
|
|
553
|
|
|
// Set composer parameters |
554
|
|
|
$instance->composerParameters = $composerParameters; |
555
|
|
|
|
556
|
|
|
// TODO: Change event signature to single approach |
557
|
|
|
// Fire core module load event |
558
|
7 |
|
Event::fire('core.module_loaded', array($identifier, &$instance)); |
559
|
|
|
|
560
|
|
|
// Signal core module configure event |
561
|
7 |
|
Event::signal('core.module.configure', array(&$instance, $identifier)); |
562
|
|
|
|
563
|
|
|
// Call module preparation handler |
564
|
7 |
|
if (!$instance->prepare()) { |
565
|
|
|
// Handle module failed preparing |
566
|
|
|
} |
567
|
7 |
|
|
568
|
|
|
// Trying to find parent class for connecting to it to use View/Controller inheritance |
569
|
|
|
// $parentClass = get_parent_class($instance); |
570
|
7 |
|
// if (!in_array($parentClass, |
571
|
|
|
// array('samson\core\ExternalModule', 'samson\core\CompressableExternalModule')) |
572
|
|
|
// ) { |
573
|
7 |
|
// // Переберем загруженные в систему модули |
574
|
|
|
// foreach ($this->module_stack as &$m) { |
575
|
|
|
// // Если в систему был загружен модуль с родительским классом |
576
|
7 |
|
// if (get_class($m) === $parentClass) { |
577
|
7 |
|
// $instance->parent = &$m; |
578
|
|
|
// //elapsed('Parent connection for '.$moduleClass.'('.$connector->uid.') with '.$parent_class.'('.$m->uid.')'); |
579
|
|
|
// } |
580
|
|
|
// } |
581
|
|
|
// } |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
/** |
585
|
|
|
* Load module from path to core. |
586
|
|
|
* |
587
|
|
|
* @param string $path Path for module loading |
588
|
|
|
* @param array $parameters Collection of loading parameters |
589
|
|
|
* |
590
|
|
|
* @return string module name |
591
|
|
|
* @throws \samsonphp\core\exception\CannotLoadModule |
592
|
|
|
*/ |
593
|
|
|
public function load($path, $parameters = array()) |
594
|
|
|
{ |
595
|
|
|
$name = ''; |
596
|
|
|
// Check path |
597
|
|
|
if (file_exists($path)) { |
598
|
|
|
/** @var ResourceMap $resourceMap Gather all resources from path */ |
599
|
|
|
$resourceMap = ResourceMap::get($path); |
600
|
|
|
if (isset($resourceMap->module[0])) { |
601
|
|
|
|
602
|
|
|
/** @var string $controllerPath Path to module controller file */ |
603
|
|
|
$controllerPath = $resourceMap->module[1]; |
604
|
|
|
|
605
|
|
|
/** @var string $moduleClass Name of module controller class to load */ |
606
|
|
|
$moduleClass = $resourceMap->module[0]; |
607
|
|
|
|
608
|
|
|
// Require module controller class into PHP |
609
|
|
|
if (file_exists($controllerPath)) { |
610
|
|
|
require_once($controllerPath); |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
// TODO: this should be done via composer autoload file field |
614
|
|
|
// Iterate all function-style controllers and require them |
615
|
|
|
foreach ($resourceMap->controllers as $controller) { |
616
|
|
|
require_once($controller); |
617
|
|
|
} |
618
|
|
|
|
619
|
|
|
$reflection = new \ReflectionClass($moduleClass); |
620
|
|
|
$name = $reflection->getDefaultProperties(); |
621
|
|
|
$name = $name['id'] ?? str_replace('/', '', $moduleClass); |
622
|
|
|
|
623
|
|
|
$this->createMetadata($moduleClass, $name, $path); |
624
|
|
|
|
625
|
|
|
/*$this->initModule( |
626
|
|
|
new $moduleClass($path, $resourceMap, $this), |
627
|
|
|
$parameters |
628
|
|
|
);*/ |
629
|
|
|
} elseif (is_array($parameters) && isset($parameters['samsonphp_package_compressable']) && ($parameters['samsonphp_package_compressable'] == 1)) { |
630
|
|
|
$name = str_replace('/', '', $parameters['module_id']); |
631
|
|
|
$this->createMetadata(VirtualModule::class, str_replace('/', '', $parameters['module_id']), $path); |
632
|
|
|
|
633
|
|
|
/*$this->initModule( |
634
|
|
|
new VirtualModule($path, $resourceMap, $this, str_replace('/', '', $parameters['module_id'])), |
635
|
|
|
$parameters |
636
|
|
|
);*/ |
637
|
|
|
} elseif (count($resourceMap->classes)) { |
638
|
|
|
/** Update for future version: Search classes that implement LoadableInterface */ |
639
|
|
|
foreach ($resourceMap->classes as $classPath => $class) { |
640
|
|
|
// This class implements LoadableInterface LoadableInterface::class |
641
|
|
|
if (in_array('\samsonframework\core\LoadableInterface', $resourceMap->classData[$classPath]['implements'])) { |
|
|
|
|
642
|
|
|
|
643
|
|
|
$name = str_replace('/', '', $parameters['module_id']); |
644
|
|
|
|
645
|
|
|
$this->createMetadata(VirtualModule::class, str_replace('/', '', $parameters['module_id']), $path); |
646
|
|
|
|
647
|
|
|
/*$this->initModule( |
648
|
|
|
new VirtualModule( |
649
|
|
|
$path, |
650
|
|
|
$resourceMap, |
651
|
|
|
$this, |
652
|
|
|
str_replace('/', '', $resourceMap->classData[$classPath]['className']) |
653
|
|
|
), |
654
|
|
|
$parameters |
655
|
|
|
);*/ |
656
|
|
|
} |
657
|
|
|
} |
658
|
|
|
} |
659
|
|
|
|
|
|
|
|
660
|
|
|
} else { |
661
|
|
|
throw new CannotLoadModule($path); |
662
|
|
|
} |
663
|
|
|
|
664
|
|
|
return $name; |
665
|
|
|
} |
666
|
|
|
//[PHPCOMPRESSOR(remove,end)] |
667
|
|
|
|
668
|
|
|
/** Магический метод для десериализации объекта */ |
669
|
|
|
public function __wakeup() |
670
|
|
|
{ |
671
|
|
|
$this->active = &$this->module_stack['local']; |
672
|
|
|
} |
673
|
|
|
|
674
|
|
|
/** Магический метод для сериализации объекта */ |
675
|
|
|
public function __sleep() |
676
|
|
|
{ |
677
|
|
|
return array('module_stack', 'render_mode'); |
678
|
|
|
} |
679
|
|
|
|
680
|
|
|
protected function createMetadata($class, $name, $path) |
681
|
|
|
{ |
682
|
|
|
$metadata = new ClassMetadata(); |
683
|
|
|
$class = ltrim($class, '\\'); |
684
|
|
|
$metadata->className = $class; |
685
|
|
|
$metadata->name = str_replace('/', '', $name ?? $class); |
686
|
|
|
$metadata->scopes[] = Builder::SCOPE_SERVICES; |
687
|
|
|
$metadata->methodsMetadata['__construct'] = new MethodMetadata($metadata); |
688
|
|
|
$metadata->methodsMetadata['__construct']->dependencies['path'] = $path; |
689
|
|
|
$metadata->methodsMetadata['__construct']->dependencies['resources'] = ResourceMap::class; |
690
|
|
|
$metadata->methodsMetadata['__construct']->dependencies['system'] = get_class($this); |
691
|
|
|
|
692
|
|
|
$this->metadataCollection[$metadata->name] = $metadata; |
693
|
|
|
} |
694
|
|
|
} |
695
|
|
|
|
This property has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.