Total Complexity | 164 |
Total Lines | 1278 |
Duplicated Lines | 0 % |
Changes | 5 | ||
Bugs | 0 | Features | 1 |
Complex classes like TApplication often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use TApplication, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
101 | class TApplication extends \Prado\TComponent implements ISingleton |
||
102 | { |
||
103 | /** |
||
104 | * Page service ID |
||
105 | */ |
||
106 | public const PAGE_SERVICE_ID = 'page'; |
||
107 | /** |
||
108 | * Application configuration file name |
||
109 | */ |
||
110 | public const CONFIG_FILE_XML = 'application.xml'; |
||
111 | /** |
||
112 | * File extension for external config files |
||
113 | */ |
||
114 | public const CONFIG_FILE_EXT_XML = '.xml'; |
||
115 | /** |
||
116 | * Configuration file type, application.xml and config.xml |
||
117 | */ |
||
118 | public const CONFIG_TYPE_XML = 'xml'; |
||
119 | /** |
||
120 | * Application configuration file name |
||
121 | */ |
||
122 | public const CONFIG_FILE_PHP = 'application.php'; |
||
123 | /** |
||
124 | * File extension for external config files |
||
125 | */ |
||
126 | public const CONFIG_FILE_EXT_PHP = '.php'; |
||
127 | /** |
||
128 | * Configuration file type, application.php and config.php |
||
129 | */ |
||
130 | public const CONFIG_TYPE_PHP = 'php'; |
||
131 | /** |
||
132 | * Runtime directory name |
||
133 | */ |
||
134 | public const RUNTIME_PATH = 'runtime'; |
||
135 | /** |
||
136 | * Config cache file |
||
137 | */ |
||
138 | public const CONFIGCACHE_FILE = 'config.cache'; |
||
139 | /** |
||
140 | * Global data file |
||
141 | */ |
||
142 | public const GLOBAL_FILE = 'global.cache'; |
||
143 | |||
144 | /** |
||
145 | * @var array list of events that define application lifecycles |
||
146 | */ |
||
147 | private static $_steps = [ |
||
148 | 'onBeginRequest', |
||
149 | 'onLoadState', |
||
150 | 'onLoadStateComplete', |
||
151 | 'onAuthentication', |
||
152 | 'onAuthenticationComplete', |
||
153 | 'onAuthorization', |
||
154 | 'onAuthorizationComplete', |
||
155 | 'onPreRunService', |
||
156 | 'runService', |
||
157 | 'onSaveState', |
||
158 | 'onSaveStateComplete', |
||
159 | 'onPreFlushOutput', |
||
160 | 'flushOutput', |
||
161 | ]; |
||
162 | |||
163 | /** |
||
164 | * @var string application ID |
||
165 | */ |
||
166 | private $_id; |
||
167 | /** |
||
168 | * @var string unique application ID |
||
169 | */ |
||
170 | private $_uniqueID; |
||
171 | /** |
||
172 | * @var bool whether the request is completed |
||
173 | */ |
||
174 | private $_requestCompleted = false; |
||
175 | /** |
||
176 | * @var int application state |
||
177 | */ |
||
178 | private $_step; |
||
179 | /** |
||
180 | * @var array available services and their configurations indexed by service IDs |
||
181 | */ |
||
182 | private $_services; |
||
183 | /** |
||
184 | * @var IService current service instance |
||
185 | */ |
||
186 | private $_service; |
||
187 | /** |
||
188 | * @var array list of loaded application modules |
||
189 | */ |
||
190 | private $_modules = []; |
||
191 | /** |
||
192 | * @var array list of application modules yet to be loaded |
||
193 | */ |
||
194 | private $_lazyModules = []; |
||
195 | /** |
||
196 | * @var \Prado\Collections\TMap list of application parameters |
||
197 | */ |
||
198 | private $_parameters; |
||
199 | /** |
||
200 | * @var string configuration file |
||
201 | */ |
||
202 | private $_configFile; |
||
203 | /** |
||
204 | * @var string configuration file extension |
||
205 | */ |
||
206 | private $_configFileExt; |
||
207 | /** |
||
208 | * @var string configuration type |
||
209 | */ |
||
210 | private $_configType; |
||
211 | /** |
||
212 | * @var string application base path |
||
213 | */ |
||
214 | private $_basePath; |
||
215 | /** |
||
216 | * @var string directory storing application state |
||
217 | */ |
||
218 | private $_runtimePath; |
||
219 | /** |
||
220 | * @var bool if any global state is changed during the current request |
||
221 | */ |
||
222 | private $_stateChanged = false; |
||
223 | /** |
||
224 | * @var array global variables (persistent across sessions, requests) |
||
225 | */ |
||
226 | private $_globals = []; |
||
227 | /** |
||
228 | * @var string cache file |
||
229 | */ |
||
230 | private $_cacheFile; |
||
231 | /** |
||
232 | * @var TErrorHandler error handler module |
||
233 | */ |
||
234 | private $_errorHandler; |
||
235 | /** |
||
236 | * @var THttpRequest request module |
||
237 | */ |
||
238 | private $_request; |
||
239 | /** |
||
240 | * @var THttpResponse response module |
||
241 | */ |
||
242 | private $_response; |
||
243 | /** |
||
244 | * @var THttpSession session module, could be null |
||
245 | */ |
||
246 | private $_session; |
||
247 | /** |
||
248 | * @var \Prado\Caching\ICache cache module, could be null |
||
249 | */ |
||
250 | private $_cache; |
||
251 | /** |
||
252 | * @var IStatePersister application state persister |
||
253 | */ |
||
254 | private $_statePersister; |
||
255 | /** |
||
256 | * @var \Prado\Security\IUser user instance, could be null |
||
257 | */ |
||
258 | private $_user; |
||
259 | /** |
||
260 | * @var TGlobalization module, could be null |
||
261 | */ |
||
262 | private $_globalization; |
||
263 | /** |
||
264 | * @var TSecurityManager security manager module |
||
265 | */ |
||
266 | private $_security; |
||
267 | /** |
||
268 | * @var TAssetManager asset manager module |
||
269 | */ |
||
270 | private $_assetManager; |
||
271 | /** |
||
272 | * @var \Prado\Web\UI\TTemplateManager template manager module |
||
273 | */ |
||
274 | private $_templateManager; |
||
275 | /** |
||
276 | * @var \Prado\Web\UI\TThemeManager theme manager module |
||
277 | */ |
||
278 | private $_themeManager; |
||
279 | /** |
||
280 | * @var \Prado\Security\TAuthorizationRuleCollection collection of authorization rules |
||
281 | */ |
||
282 | private $_authRules; |
||
283 | /** |
||
284 | * @var string|TApplicationMode application mode |
||
285 | */ |
||
286 | private $_mode = TApplicationMode::Debug; |
||
287 | |||
288 | /** |
||
289 | * @var string Customizable page service ID |
||
290 | */ |
||
291 | private $_pageServiceID = self::PAGE_SERVICE_ID; |
||
292 | |||
293 | /** |
||
294 | * Constructor. |
||
295 | * Sets application base path and initializes the application singleton. |
||
296 | * Application base path refers to the root directory storing application |
||
297 | * data and code not directly accessible by Web users. |
||
298 | * By default, the base path is assumed to be the <b>protected</b> |
||
299 | * directory under the directory containing the current running script. |
||
300 | * @param string $basePath application base path or configuration file path. |
||
301 | * If the parameter is a file, it is assumed to be the application |
||
302 | * configuration file, and the directory containing the file is treated |
||
303 | * as the application base path. |
||
304 | * If it is a directory, it is assumed to be the application base path, |
||
305 | * and within that directory, a file named <b>application.xml</b> |
||
306 | * will be looked for. If found, the file is considered as the application |
||
307 | * configuration file. |
||
308 | * @param bool $cacheConfig whether to cache application configuration. Defaults to true. |
||
309 | * @param string $configType configuration type. Defaults to CONFIG_TYPE_XML. |
||
310 | * @throws TConfigurationException if configuration file cannot be read or the runtime path is invalid. |
||
311 | */ |
||
312 | public function __construct($basePath = 'protected', $cacheConfig = true, $configType = self::CONFIG_TYPE_XML) |
||
313 | { |
||
314 | // register application as a singleton |
||
315 | Prado::setApplication($this); |
||
316 | $this->setConfigurationType($configType); |
||
317 | $this->resolvePaths($basePath); |
||
318 | |||
319 | if ($cacheConfig) { |
||
320 | $this->_cacheFile = $this->_runtimePath . DIRECTORY_SEPARATOR . self::CONFIGCACHE_FILE; |
||
321 | } |
||
322 | |||
323 | // generates unique ID by hashing the runtime path |
||
324 | $this->_uniqueID = md5($this->_runtimePath); |
||
325 | $this->_parameters = new \Prado\Collections\TMap(); |
||
326 | $this->_services = [$this->getPageServiceID() => ['TPageService', [], null]]; |
||
327 | |||
328 | Prado::setPathOfAlias('Application', $this->_basePath); |
||
329 | parent::__construct(); |
||
330 | } |
||
331 | |||
332 | /** |
||
333 | * Returns the current Prado application. This enables application behaviors to |
||
334 | * be used for undefined static function calls via {@see \Prado\TComponent::__callStatic}. |
||
335 | * @param bool $create This is ignored and returns Prado::getApplication(). |
||
336 | * @return ?object The singleton instance of the class. |
||
337 | * @since 4.3.0 |
||
338 | */ |
||
339 | public static function singleton(bool $create = true): ?object |
||
340 | { |
||
341 | return Prado::getApplication(); |
||
342 | } |
||
343 | |||
344 | /** |
||
345 | * Resolves application-relevant paths. |
||
346 | * This method is invoked by the application constructor |
||
347 | * to determine the application configuration file, |
||
348 | * application root path and the runtime path. |
||
349 | * @param string $basePath the application root path or the application configuration file |
||
350 | * @see setBasePath |
||
351 | * @see setRuntimePath |
||
352 | * @see setConfigurationFile |
||
353 | */ |
||
354 | protected function resolvePaths($basePath) |
||
355 | { |
||
356 | // determine configuration path and file |
||
357 | if (empty($errValue = $basePath) || ($basePath = realpath($basePath)) === false) { |
||
358 | throw new TConfigurationException('application_basepath_invalid', $errValue); |
||
359 | } |
||
360 | if (is_dir($basePath) && is_file($basePath . DIRECTORY_SEPARATOR . $this->getConfigurationFileName())) { |
||
361 | $configFile = $basePath . DIRECTORY_SEPARATOR . $this->getConfigurationFileName(); |
||
362 | } elseif (is_file($basePath)) { |
||
363 | $configFile = $basePath; |
||
364 | $basePath = dirname($configFile); |
||
365 | } else { |
||
366 | $configFile = null; |
||
367 | } |
||
368 | |||
369 | // determine runtime path |
||
370 | $runtimePath = $basePath . DIRECTORY_SEPARATOR . self::RUNTIME_PATH; |
||
371 | if (is_writable($runtimePath)) { |
||
372 | if ($configFile !== null) { |
||
373 | $runtimePath .= DIRECTORY_SEPARATOR . basename($configFile) . '-' . Prado::getVersion(); |
||
374 | if (!is_dir($runtimePath)) { |
||
375 | if (@mkdir($runtimePath) === false) { |
||
376 | throw new TConfigurationException('application_runtimepath_failed', $runtimePath); |
||
377 | } |
||
378 | @chmod($runtimePath, Prado::getDefaultDirPermissions()); //make it deletable |
||
|
|||
379 | } |
||
380 | $this->setConfigurationFile($configFile); |
||
381 | } |
||
382 | $this->setBasePath($basePath); |
||
383 | $this->setRuntimePath($runtimePath); |
||
384 | } else { |
||
385 | throw new TConfigurationException('application_runtimepath_invalid', $runtimePath); |
||
386 | } |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Executes the lifecycles of the application. |
||
391 | * This is the main entry function that leads to the running of the whole |
||
392 | * Prado application. |
||
393 | */ |
||
394 | public function run() |
||
395 | { |
||
396 | try { |
||
397 | $this->initApplication(); |
||
398 | $n = count(self::$_steps); |
||
399 | $this->_step = 0; |
||
400 | $this->_requestCompleted = false; |
||
401 | while ($this->_step < $n) { |
||
402 | if ($this->_mode === TApplicationMode::Off) { |
||
403 | throw new THttpException(503, 'application_unavailable'); |
||
404 | } |
||
405 | if ($this->_requestCompleted) { |
||
406 | break; |
||
407 | } |
||
408 | $method = self::$_steps[$this->_step]; |
||
409 | Prado::trace("Executing $method()", TApplication::class); |
||
410 | $this->$method(); |
||
411 | $this->_step++; |
||
412 | } |
||
413 | } catch (TExitException $e) { |
||
414 | $this->onEndRequest(); |
||
415 | exit($e->getExitCode()); |
||
416 | } catch (\Exception $e) { |
||
417 | $this->onError($e); |
||
418 | } |
||
419 | $this->onEndRequest(); |
||
420 | } |
||
421 | |||
422 | /** |
||
423 | * Completes current request processing. |
||
424 | * This method can be used to exit the application lifecycles after finishing |
||
425 | * the current cycle. |
||
426 | */ |
||
427 | public function completeRequest() |
||
428 | { |
||
429 | $this->_requestCompleted = true; |
||
430 | } |
||
431 | |||
432 | /** |
||
433 | * @return bool whether the current request is processed. |
||
434 | */ |
||
435 | public function getRequestCompleted() |
||
436 | { |
||
437 | return $this->_requestCompleted; |
||
438 | } |
||
439 | |||
440 | /** |
||
441 | * Returns a global value. |
||
442 | * |
||
443 | * A global value is one that is persistent across users sessions and requests. |
||
444 | * @param string $key the name of the value to be returned |
||
445 | * @param mixed $defaultValue the default value. If $key is not found, $defaultValue will be returned |
||
446 | * @return mixed the global value corresponding to $key |
||
447 | */ |
||
448 | public function getGlobalState($key, $defaultValue = null) |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * Sets a global value. |
||
455 | * |
||
456 | * A global value is one that is persistent across users sessions and requests. |
||
457 | * Make sure that the value is serializable and unserializable. |
||
458 | * @param string $key the name of the value to be set |
||
459 | * @param mixed $value the global value to be set |
||
460 | * @param null|mixed $defaultValue the default value. If $key is not found, $defaultValue will be returned |
||
461 | * @param bool $forceSave wheter to force an immediate GlobalState save. defaults to false |
||
462 | */ |
||
463 | public function setGlobalState($key, $value, $defaultValue = null, $forceSave = false) |
||
464 | { |
||
465 | $this->_stateChanged = true; |
||
466 | if ($value === $defaultValue) { |
||
467 | unset($this->_globals[$key]); |
||
468 | } else { |
||
469 | $this->_globals[$key] = $value; |
||
470 | } |
||
471 | if ($forceSave) { |
||
472 | $this->saveGlobals(); |
||
473 | } |
||
474 | } |
||
475 | |||
476 | /** |
||
477 | * Clears a global value. |
||
478 | * |
||
479 | * The value cleared will no longer be available in this request and the following requests. |
||
480 | * @param string $key the name of the value to be cleared |
||
481 | */ |
||
482 | public function clearGlobalState($key) |
||
483 | { |
||
484 | $this->_stateChanged = true; |
||
485 | unset($this->_globals[$key]); |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Loads global values from persistent storage. |
||
490 | * This method is invoked when {@see onLoadState OnLoadState} event is raised. |
||
491 | * After this method, values that are stored in previous requests become |
||
492 | * available to the current request via {@see getGlobalState}. |
||
493 | */ |
||
494 | protected function loadGlobals() |
||
495 | { |
||
496 | $this->_globals = $this->getApplicationStatePersister()->load(); |
||
497 | } |
||
498 | |||
499 | /** |
||
500 | * Saves global values into persistent storage. |
||
501 | * This method is invoked when {@see onSaveState OnSaveState} event is raised. |
||
502 | */ |
||
503 | protected function saveGlobals() |
||
504 | { |
||
505 | if ($this->_stateChanged) { |
||
506 | $this->_stateChanged = false; |
||
507 | $this->getApplicationStatePersister()->save($this->_globals); |
||
508 | } |
||
509 | } |
||
510 | |||
511 | /** |
||
512 | * @return string application ID |
||
513 | */ |
||
514 | public function getID() |
||
515 | { |
||
516 | return $this->_id; |
||
517 | } |
||
518 | |||
519 | /** |
||
520 | * @param string $value application ID |
||
521 | */ |
||
522 | public function setID($value) |
||
523 | { |
||
524 | $this->_id = $value; |
||
525 | } |
||
526 | |||
527 | /** |
||
528 | * @return string page service ID |
||
529 | */ |
||
530 | public function getPageServiceID() |
||
531 | { |
||
532 | return $this->_pageServiceID; |
||
533 | } |
||
534 | |||
535 | /** |
||
536 | * @param string $value page service ID |
||
537 | */ |
||
538 | public function setPageServiceID($value) |
||
539 | { |
||
540 | $this->_pageServiceID = $value; |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * @return string an ID that uniquely identifies this Prado application from the others |
||
545 | */ |
||
546 | public function getUniqueID() |
||
547 | { |
||
548 | return $this->_uniqueID; |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * @return string|TApplicationMode application mode. Defaults to TApplicationMode::Debug. |
||
553 | */ |
||
554 | public function getMode() |
||
555 | { |
||
556 | return $this->_mode; |
||
557 | } |
||
558 | |||
559 | /** |
||
560 | * @param TApplicationMode $value application mode |
||
561 | */ |
||
562 | public function setMode($value) |
||
563 | { |
||
564 | $this->_mode = TPropertyValue::ensureEnum($value, TApplicationMode::class); |
||
565 | } |
||
566 | |||
567 | /** |
||
568 | * @return string the directory containing the application configuration file (absolute path) |
||
569 | */ |
||
570 | public function getBasePath() |
||
571 | { |
||
572 | return $this->_basePath; |
||
573 | } |
||
574 | |||
575 | /** |
||
576 | * @param string $value the directory containing the application configuration file |
||
577 | */ |
||
578 | public function setBasePath($value) |
||
579 | { |
||
580 | $this->_basePath = $value; |
||
581 | } |
||
582 | |||
583 | /** |
||
584 | * @return string the application configuration file (absolute path) |
||
585 | */ |
||
586 | public function getConfigurationFile() |
||
587 | { |
||
588 | return $this->_configFile; |
||
589 | } |
||
590 | |||
591 | /** |
||
592 | * @param string $value the application configuration file (absolute path) |
||
593 | */ |
||
594 | public function setConfigurationFile($value) |
||
595 | { |
||
596 | $this->_configFile = $value; |
||
597 | } |
||
598 | |||
599 | /** |
||
600 | * @return string the application configuration file (absolute path) |
||
601 | */ |
||
602 | public function getConfigurationType() |
||
605 | } |
||
606 | |||
607 | /** |
||
608 | * @param string $value the application configuration type. 'xml' and 'php' are valid values |
||
609 | */ |
||
610 | public function setConfigurationType($value) |
||
611 | { |
||
612 | $this->_configType = $value; |
||
613 | } |
||
614 | |||
615 | /** |
||
616 | * @return string the application configuration type. default is 'xml' |
||
617 | */ |
||
618 | public function getConfigurationFileExt() |
||
619 | { |
||
620 | if ($this->_configFileExt === null) { |
||
621 | switch ($this->_configType) { |
||
622 | case TApplication::CONFIG_TYPE_PHP: |
||
623 | $this->_configFileExt = TApplication::CONFIG_FILE_EXT_PHP; |
||
624 | break; |
||
625 | default: |
||
626 | $this->_configFileExt = TApplication::CONFIG_FILE_EXT_XML; |
||
627 | } |
||
628 | } |
||
629 | return $this->_configFileExt; |
||
630 | } |
||
631 | |||
632 | /** |
||
633 | * @return string the default configuration file name |
||
634 | */ |
||
635 | public function getConfigurationFileName() |
||
636 | { |
||
637 | static $fileName; |
||
638 | if ($fileName == null) { |
||
639 | switch ($this->_configType) { |
||
640 | case TApplication::CONFIG_TYPE_PHP: |
||
641 | $fileName = TApplication::CONFIG_FILE_PHP; |
||
642 | break; |
||
643 | default: |
||
644 | $fileName = TApplication::CONFIG_FILE_XML; |
||
645 | } |
||
646 | } |
||
647 | return $fileName; |
||
648 | } |
||
649 | |||
650 | /** |
||
651 | * @return string the directory storing cache data and application-level persistent data. (absolute path) |
||
652 | */ |
||
653 | public function getRuntimePath() |
||
654 | { |
||
655 | return $this->_runtimePath; |
||
656 | } |
||
657 | |||
658 | /** |
||
659 | * @param string $value the directory storing cache data and application-level persistent data. (absolute path) |
||
660 | */ |
||
661 | public function setRuntimePath($value) |
||
662 | { |
||
663 | $this->_runtimePath = $value; |
||
664 | if ($this->_cacheFile) { |
||
665 | $this->_cacheFile = $this->_runtimePath . DIRECTORY_SEPARATOR . self::CONFIGCACHE_FILE; |
||
666 | } |
||
667 | // generates unique ID by hashing the runtime path |
||
668 | $this->_uniqueID = md5($this->_runtimePath); |
||
669 | } |
||
670 | |||
671 | /** |
||
672 | * @return TService the currently requested service |
||
673 | */ |
||
674 | public function getService() |
||
675 | { |
||
676 | return $this->_service; |
||
677 | } |
||
678 | |||
679 | /** |
||
680 | * @param IService $value the currently requested service |
||
681 | */ |
||
682 | public function setService($value) |
||
683 | { |
||
684 | $this->_service = $value; |
||
685 | } |
||
686 | |||
687 | /** |
||
688 | * Adds a module to application. |
||
689 | * Note, this method does not do module initialization. |
||
690 | * @param string $id ID of the module |
||
691 | * @param null|IModule $module module object or null if the module has not been loaded yet |
||
692 | */ |
||
693 | public function setModule($id, ?IModule $module = null) |
||
694 | { |
||
695 | if (isset($this->_modules[$id])) { |
||
696 | throw new TConfigurationException('application_moduleid_duplicated', $id); |
||
697 | } else { |
||
698 | $this->_modules[$id] = $module; |
||
699 | } |
||
700 | } |
||
701 | |||
702 | /** |
||
703 | * @param mixed $id |
||
704 | * @return null|TModule the module with the specified ID, null if not found |
||
705 | */ |
||
706 | public function getModule($id) |
||
707 | { |
||
708 | if (!array_key_exists($id, $this->_modules)) { |
||
709 | return null; |
||
710 | } |
||
711 | |||
712 | // force loading of a lazy module |
||
713 | if ($this->_modules[$id] === null) { |
||
714 | $module = $this->internalLoadModule($id, true); |
||
715 | $module[0]->init($module[1]); |
||
716 | } |
||
717 | |||
718 | return $this->_modules[$id]; |
||
719 | } |
||
720 | |||
721 | /** |
||
722 | * Returns a list of application modules indexed by module IDs. |
||
723 | * Modules that have not been loaded yet are returned as null objects. |
||
724 | * @return array<TModule> list of loaded application modules, indexed by module IDs |
||
725 | */ |
||
726 | public function getModules() |
||
727 | { |
||
728 | return $this->_modules; |
||
729 | } |
||
730 | |||
731 | /** |
||
732 | * Returns a list of application modules of a specific class. |
||
733 | * Lazy Loading Modules are not loaded, and are null but have an ID Key. |
||
734 | * When null modules are found, load them with {@see getModule}. eg. |
||
735 | * ```php |
||
736 | * foreach (Prado::getApplication()->getModulesByType(\Prado\Caching\ICache::class) as $id => $module) { |
||
737 | * $module = (!$module) ? $app->getModule($id) : $module; |
||
738 | * ... |
||
739 | * } |
||
740 | * ``` |
||
741 | * @param string $type class name of the modules to look for. |
||
742 | * @param bool $strict should the module be the class or can the module be a subclass |
||
743 | * @return array keys are the ids of the module and values are module of a specific class |
||
744 | * @since 4.2.0 |
||
745 | */ |
||
746 | public function getModulesByType($type, $strict = false) |
||
747 | { |
||
748 | $m = []; |
||
749 | foreach ($this->_modules as $id => $module) { |
||
750 | if ($module === null && isset($this->_lazyModules[$id])) { |
||
751 | [$moduleClass, $initProperties, $configElement] = $this->_lazyModules[$id]; |
||
752 | if ($strict ? ($moduleClass === $type) : ($moduleClass instanceof $type)) { |
||
753 | $m[$id] = null; |
||
754 | } |
||
755 | } elseif ($module !== null && ($strict ? ($module::class === $type) : $module->isa($type))) { |
||
756 | $m[$id] = $module; |
||
757 | } |
||
758 | } |
||
759 | return $m; |
||
760 | } |
||
761 | |||
762 | /** |
||
763 | * Returns the list of application parameters. |
||
764 | * Since the parameters are returned as a {@see \Prado\Collections\TMap} object, you may use |
||
765 | * the returned result to access, add or remove individual parameters. |
||
766 | * @return \Prado\Collections\TMap the list of application parameters |
||
767 | */ |
||
768 | public function getParameters() |
||
769 | { |
||
770 | return $this->_parameters; |
||
771 | } |
||
772 | |||
773 | /** |
||
774 | * @return THttpRequest the request module |
||
775 | */ |
||
776 | public function getRequest() |
||
777 | { |
||
778 | if (!$this->_request) { |
||
779 | $this->_request = new \Prado\Web\THttpRequest(); |
||
780 | $this->_request->init(null); |
||
781 | } |
||
782 | return $this->_request; |
||
783 | } |
||
784 | |||
785 | /** |
||
786 | * @param THttpRequest $request the request module |
||
787 | */ |
||
788 | public function setRequest(THttpRequest $request) |
||
789 | { |
||
790 | $this->_request = $request; |
||
791 | } |
||
792 | |||
793 | /** |
||
794 | * @return THttpResponse the response module |
||
795 | */ |
||
796 | public function getResponse() |
||
797 | { |
||
798 | if (!$this->_response) { |
||
799 | $this->_response = new THttpResponse(); |
||
800 | $this->_response->init(null); |
||
801 | } |
||
802 | return $this->_response; |
||
803 | } |
||
804 | |||
805 | /** |
||
806 | * @param THttpResponse $response the request module |
||
807 | */ |
||
808 | public function setResponse(THttpResponse $response) |
||
809 | { |
||
810 | $this->_response = $response; |
||
811 | } |
||
812 | |||
813 | /** |
||
814 | * @return THttpSession the session module, null if session module is not installed |
||
815 | */ |
||
816 | public function getSession() |
||
817 | { |
||
818 | if (!$this->_session) { |
||
819 | $this->_session = new THttpSession(); |
||
820 | $this->_session->init(null); |
||
821 | } |
||
822 | return $this->_session; |
||
823 | } |
||
824 | |||
825 | /** |
||
826 | * @param THttpSession $session the session module |
||
827 | */ |
||
828 | public function setSession(THttpSession $session) |
||
829 | { |
||
830 | $this->_session = $session; |
||
831 | } |
||
832 | |||
833 | /** |
||
834 | * @return TErrorHandler the error handler module |
||
835 | */ |
||
836 | public function getErrorHandler() |
||
837 | { |
||
838 | if (!$this->_errorHandler) { |
||
839 | $this->_errorHandler = new TErrorHandler(); |
||
840 | $this->_errorHandler->init(null); |
||
841 | } |
||
842 | return $this->_errorHandler; |
||
843 | } |
||
844 | |||
845 | /** |
||
846 | * @param TErrorHandler $handler the error handler module |
||
847 | */ |
||
848 | public function setErrorHandler(TErrorHandler $handler) |
||
849 | { |
||
850 | $this->_errorHandler = $handler; |
||
851 | } |
||
852 | |||
853 | /** |
||
854 | * @return TSecurityManager the security manager module |
||
855 | */ |
||
856 | public function getSecurityManager() |
||
857 | { |
||
858 | if (!$this->_security) { |
||
859 | $this->_security = new TSecurityManager(); |
||
860 | $this->_security->init(null); |
||
861 | } |
||
862 | return $this->_security; |
||
863 | } |
||
864 | |||
865 | /** |
||
866 | * @param TSecurityManager $sm the security manager module |
||
867 | */ |
||
868 | public function setSecurityManager(TSecurityManager $sm) |
||
869 | { |
||
870 | $this->_security = $sm; |
||
871 | } |
||
872 | |||
873 | /** |
||
874 | * @return TAssetManager asset manager |
||
875 | */ |
||
876 | public function getAssetManager() |
||
877 | { |
||
878 | if (!$this->_assetManager) { |
||
879 | $this->_assetManager = new TAssetManager(); |
||
880 | $this->_assetManager->init(null); |
||
881 | } |
||
882 | return $this->_assetManager; |
||
883 | } |
||
884 | |||
885 | /** |
||
886 | * @param TAssetManager $value asset manager |
||
887 | */ |
||
888 | public function setAssetManager(TAssetManager $value) |
||
889 | { |
||
890 | $this->_assetManager = $value; |
||
891 | } |
||
892 | |||
893 | /** |
||
894 | * @return TTemplateManager template manager |
||
895 | */ |
||
896 | public function getTemplateManager() |
||
897 | { |
||
898 | if (!$this->_templateManager) { |
||
899 | $this->_templateManager = new TTemplateManager(); |
||
900 | $this->_templateManager->init(null); |
||
901 | } |
||
902 | return $this->_templateManager; |
||
903 | } |
||
904 | |||
905 | /** |
||
906 | * @param TTemplateManager $value template manager |
||
907 | */ |
||
908 | public function setTemplateManager(TTemplateManager $value) |
||
909 | { |
||
910 | $this->_templateManager = $value; |
||
911 | } |
||
912 | |||
913 | /** |
||
914 | * @return TThemeManager theme manager |
||
915 | */ |
||
916 | public function getThemeManager() |
||
917 | { |
||
918 | if (!$this->_themeManager) { |
||
919 | $this->_themeManager = new TThemeManager(); |
||
920 | $this->_themeManager->init(null); |
||
921 | } |
||
922 | return $this->_themeManager; |
||
923 | } |
||
924 | |||
925 | /** |
||
926 | * @param TThemeManager $value theme manager |
||
927 | */ |
||
928 | public function setThemeManager(TThemeManager $value) |
||
929 | { |
||
930 | $this->_themeManager = $value; |
||
931 | } |
||
932 | |||
933 | /** |
||
934 | * @return IStatePersister application state persister |
||
935 | */ |
||
936 | public function getApplicationStatePersister() |
||
937 | { |
||
938 | if (!$this->_statePersister) { |
||
939 | $this->_statePersister = new TApplicationStatePersister(); |
||
940 | $this->_statePersister->init(null); |
||
941 | } |
||
942 | return $this->_statePersister; |
||
943 | } |
||
944 | |||
945 | /** |
||
946 | * @param IStatePersister $persister application state persister |
||
947 | */ |
||
948 | public function setApplicationStatePersister(IStatePersister $persister) |
||
951 | } |
||
952 | |||
953 | /** |
||
954 | * @return null|\Prado\Caching\ICache the cache module, null if cache module is not installed |
||
955 | */ |
||
956 | public function getCache() |
||
957 | { |
||
958 | return $this->_cache; |
||
959 | } |
||
960 | |||
961 | /** |
||
962 | * @param \Prado\Caching\ICache $cache the cache module |
||
963 | */ |
||
964 | public function setCache(\Prado\Caching\ICache $cache) |
||
965 | { |
||
966 | $this->_cache = $cache; |
||
967 | } |
||
968 | |||
969 | /** |
||
970 | * @return \Prado\Security\IUser the application user |
||
971 | */ |
||
972 | public function getUser() |
||
973 | { |
||
974 | return $this->_user; |
||
975 | } |
||
976 | |||
977 | /** |
||
978 | * This sets the application user and raises the onSetUser event. |
||
979 | * @param \Prado\Security\IUser $user the application user |
||
980 | */ |
||
981 | public function setUser(\Prado\Security\IUser $user) |
||
982 | { |
||
983 | $this->_user = $user; |
||
984 | $this->onSetUser($user); |
||
985 | } |
||
986 | |||
987 | /** |
||
988 | * Raises onSetUser event. |
||
989 | * Allows modules/components to run handlers when the Application User is set. |
||
990 | * e.g. A user module could set the $_SERVER['HTTP_ACCEPT_LANGUAGE'] and |
||
991 | * $_SERVER['HTTP_ACCEPT_CHARSET'] in a cli environment to the user's last |
||
992 | * web Language and Charset so Emails (and other templates) get language |
||
993 | * customized. |
||
994 | * @param \Prado\Security\IUser $user |
||
995 | * @since 4.2.2 |
||
996 | */ |
||
997 | public function onSetUser(\Prado\Security\IUser $user) |
||
998 | { |
||
999 | $this->raiseEvent('onSetUser', $this, $user); |
||
1000 | } |
||
1001 | |||
1002 | /** |
||
1003 | * @param bool $createIfNotExists whether to create globalization if it does not exist |
||
1004 | * @return null|TGlobalization globalization module |
||
1005 | */ |
||
1006 | public function getGlobalization($createIfNotExists = true) |
||
1007 | { |
||
1008 | if ($this->_globalization === null && $createIfNotExists) { |
||
1009 | $this->_globalization = new TGlobalization(); |
||
1010 | $this->_globalization->init(null); |
||
1011 | } |
||
1012 | return $this->_globalization; |
||
1013 | } |
||
1014 | |||
1015 | /** |
||
1016 | * @param \Prado\I18N\TGlobalization $glob globalization module |
||
1017 | */ |
||
1018 | public function setGlobalization(\Prado\I18N\TGlobalization $glob) |
||
1019 | { |
||
1020 | $this->_globalization = $glob; |
||
1021 | } |
||
1022 | |||
1023 | /** |
||
1024 | * @return \Prado\Security\TAuthorizationRuleCollection list of authorization rules for the current request |
||
1025 | */ |
||
1026 | public function getAuthorizationRules() |
||
1027 | { |
||
1028 | if ($this->_authRules === null) { |
||
1029 | $this->_authRules = new \Prado\Security\TAuthorizationRuleCollection(); |
||
1030 | } |
||
1031 | return $this->_authRules; |
||
1032 | } |
||
1033 | |||
1034 | protected function getApplicationConfigurationClass() |
||
1035 | { |
||
1036 | return TApplicationConfiguration::class; |
||
1037 | } |
||
1038 | |||
1039 | protected function internalLoadModule($id, $force = false) |
||
1040 | { |
||
1041 | [$moduleClass, $initProperties, $configElement] = $this->_lazyModules[$id]; |
||
1042 | if (isset($initProperties['lazy']) && $initProperties['lazy'] && !$force) { |
||
1043 | Prado::trace("Postponed loading of lazy module $id ({$moduleClass})", TApplication::class); |
||
1044 | $this->setModule($id, null); |
||
1045 | return null; |
||
1046 | } |
||
1047 | |||
1048 | Prado::trace("Loading module $id ({$moduleClass})", TApplication::class); |
||
1049 | $module = Prado::createComponent($moduleClass); |
||
1050 | foreach ($initProperties as $name => $value) { |
||
1051 | if ($name === 'lazy') { |
||
1052 | continue; |
||
1053 | } |
||
1054 | $module->setSubProperty($name, $value); |
||
1055 | } |
||
1056 | $this->setModule($id, $module); |
||
1057 | // keep the key to avoid reuse of the old module id |
||
1058 | $this->_lazyModules[$id] = null; |
||
1059 | $module->dyPreInit($configElement); |
||
1060 | |||
1061 | return [$module, $configElement]; |
||
1062 | } |
||
1063 | /** |
||
1064 | * Applies an application configuration. |
||
1065 | * @param TApplicationConfiguration $config the configuration |
||
1066 | * @param bool $withinService whether the configuration is specified within a service. |
||
1067 | */ |
||
1068 | public function applyConfiguration($config, $withinService = false) |
||
1069 | { |
||
1070 | if ($config->getIsEmpty()) { |
||
1071 | return; |
||
1072 | } |
||
1073 | |||
1074 | // set path aliases and using namespaces |
||
1075 | foreach ($config->getAliases() as $alias => $path) { |
||
1076 | Prado::setPathOfAlias($alias, $path); |
||
1077 | } |
||
1078 | foreach ($config->getUsings() as $using) { |
||
1079 | Prado::using($using); |
||
1080 | } |
||
1081 | |||
1082 | // set application properties |
||
1083 | if (!$withinService) { |
||
1084 | foreach ($config->getProperties() as $name => $value) { |
||
1085 | $this->setSubProperty($name, $value); |
||
1086 | } |
||
1087 | } |
||
1088 | |||
1089 | if (empty($this->_services)) { |
||
1090 | $this->_services = [$this->getPageServiceID() => [\Prado\Web\Services\TPageService::class, [], null]]; |
||
1091 | } |
||
1092 | |||
1093 | // load parameters |
||
1094 | foreach ($config->getParameters() as $id => $parameter) { |
||
1095 | if (is_array($parameter)) { |
||
1096 | $component = Prado::createComponent($parameter[0]); |
||
1097 | foreach ($parameter[1] as $name => $value) { |
||
1098 | $component->setSubProperty($name, $value); |
||
1099 | } |
||
1100 | $component->dyInit($parameter[2]); |
||
1101 | $this->_parameters->add($id, $component); |
||
1102 | } else { |
||
1103 | $this->_parameters->add($id, $parameter); |
||
1104 | } |
||
1105 | } |
||
1106 | |||
1107 | // load and init modules specified in app config |
||
1108 | $modules = []; |
||
1109 | foreach ($config->getModules() as $id => $moduleConfig) { |
||
1110 | if (!is_string($id)) { |
||
1111 | $id = '_module' . count($this->_lazyModules); |
||
1112 | } |
||
1113 | $this->_lazyModules[$id] = $moduleConfig; |
||
1114 | if ($module = $this->internalLoadModule($id)) { |
||
1115 | $modules[] = $module; |
||
1116 | } |
||
1117 | } |
||
1118 | foreach ($modules as $module) { |
||
1119 | $module[0]->init($module[1]); |
||
1120 | } |
||
1121 | |||
1122 | // load service |
||
1123 | foreach ($config->getServices() as $serviceID => $serviceConfig) { |
||
1124 | $this->_services[$serviceID] = $serviceConfig; |
||
1125 | } |
||
1126 | |||
1127 | // external configurations |
||
1128 | foreach ($config->getExternalConfigurations() as $filePath => $condition) { |
||
1129 | if ($condition !== true) { |
||
1130 | $condition = $this->evaluateExpression($condition); |
||
1131 | } |
||
1132 | if ($condition) { |
||
1133 | if (($path = Prado::getPathOfNamespace($filePath, $this->getConfigurationFileExt())) === null || !is_file($path)) { |
||
1134 | throw new TConfigurationException('application_includefile_invalid', $filePath); |
||
1135 | } |
||
1136 | $cn = $this->getApplicationConfigurationClass(); |
||
1137 | $c = new $cn(); |
||
1138 | $c->loadFromFile($path); |
||
1139 | $this->applyConfiguration($c, $withinService); |
||
1140 | } |
||
1141 | } |
||
1142 | } |
||
1143 | |||
1144 | /** |
||
1145 | * Loads configuration and initializes application. |
||
1146 | * Configuration file will be read and parsed (if a valid cached version exists, |
||
1147 | * it will be used instead). Then, modules are created and initialized; |
||
1148 | * Afterwards, the requested service is created and initialized. |
||
1149 | * Lastly, the onInitComplete event is raised. |
||
1150 | * @throws TConfigurationException if module is redefined of invalid type, or service not defined or of invalid type |
||
1151 | */ |
||
1152 | protected function initApplication() |
||
1153 | { |
||
1154 | Prado::trace('Initializing application', TApplication::class); |
||
1155 | |||
1156 | if ($this->_configFile !== null) { |
||
1157 | if ($this->_cacheFile === null || @filemtime($this->_cacheFile) < filemtime($this->_configFile)) { |
||
1158 | $config = new TApplicationConfiguration(); |
||
1159 | $config->loadFromFile($this->_configFile); |
||
1160 | if ($this->_cacheFile !== null) { |
||
1161 | file_put_contents($this->_cacheFile, serialize($config), LOCK_EX); |
||
1162 | } |
||
1163 | } else { |
||
1164 | $config = unserialize(file_get_contents($this->_cacheFile)); |
||
1165 | } |
||
1166 | |||
1167 | $this->applyConfiguration($config, false); |
||
1168 | } |
||
1169 | |||
1170 | if (($serviceID = $this->getRequest()->resolveRequest(array_keys($this->_services))) === null) { |
||
1171 | $serviceID = $this->getPageServiceID(); |
||
1172 | } |
||
1173 | |||
1174 | $this->startService($serviceID); |
||
1175 | |||
1176 | $this->onInitComplete(); |
||
1177 | } |
||
1178 | |||
1179 | /** |
||
1180 | * Starts the specified service. |
||
1181 | * The service instance will be created. Its properties will be initialized |
||
1182 | * and the configurations will be applied, if any. |
||
1183 | * @param string $serviceID service ID |
||
1184 | */ |
||
1185 | public function startService($serviceID) |
||
1186 | { |
||
1187 | if (isset($this->_services[$serviceID])) { |
||
1188 | [$serviceClass, $initProperties, $configElement] = $this->_services[$serviceID]; |
||
1189 | $service = Prado::createComponent($serviceClass); |
||
1190 | if (!($service instanceof TService)) { |
||
1191 | throw new THttpException(500, 'application_service_invalid', $serviceClass); |
||
1192 | } |
||
1193 | if (!$service->getEnabled()) { |
||
1194 | throw new THttpException(500, 'application_service_unavailable', $serviceClass); |
||
1195 | } |
||
1196 | $service->setID($serviceID); |
||
1197 | $this->setService($service); |
||
1198 | |||
1199 | foreach ($initProperties as $name => $value) { |
||
1200 | $service->setSubProperty($name, $value); |
||
1201 | } |
||
1202 | |||
1203 | if ($configElement !== null) { |
||
1204 | $config = new TApplicationConfiguration(); |
||
1205 | if ($this->getConfigurationType() == self::CONFIG_TYPE_PHP) { |
||
1206 | $config->loadFromPhp($configElement, $this->getBasePath()); |
||
1207 | } else { |
||
1208 | $config->loadFromXml($configElement, $this->getBasePath()); |
||
1209 | } |
||
1210 | $this->applyConfiguration($config, true); |
||
1211 | } |
||
1212 | |||
1213 | $service->init($configElement); |
||
1214 | } else { |
||
1215 | throw new THttpException(500, 'application_service_unknown', $serviceID); |
||
1216 | } |
||
1217 | } |
||
1218 | |||
1219 | /** |
||
1220 | * Raises OnError event. |
||
1221 | * This method is invoked when an exception is raised during the lifecycles |
||
1222 | * of the application. |
||
1223 | * @param mixed $param event parameter |
||
1224 | */ |
||
1225 | public function onError($param) |
||
1226 | { |
||
1227 | Prado::log($param->getMessage(), TLogger::ERROR, TApplication::class); |
||
1228 | $this->raiseEvent('OnError', $this, $param); |
||
1229 | $this->getErrorHandler()->handleError($this, $param); |
||
1230 | } |
||
1231 | |||
1232 | /** |
||
1233 | * Raises onInitComplete event. |
||
1234 | * At the time when this method is invoked, application modules are loaded, |
||
1235 | * user request is resolved and the corresponding service is loaded and |
||
1236 | * initialized. The application is about to start processing the user |
||
1237 | * request. This call is important for CLI/Shell applications that do not have |
||
1238 | * a web service lifecycle stack. This is the first and last event for finalization |
||
1239 | * of any loaded modules in CLI/Shell mode. |
||
1240 | * @since 4.2.0 |
||
1241 | */ |
||
1242 | public function onInitComplete() |
||
1243 | { |
||
1244 | $this->raiseEvent('onInitComplete', $this, null); |
||
1245 | } |
||
1246 | |||
1247 | /** |
||
1248 | * Raises OnBeginRequest event. |
||
1249 | * At the time when this method is invoked, application modules are loaded |
||
1250 | * and initialized, user request is resolved and the corresponding service |
||
1251 | * is loaded and initialized. The application is about to start processing |
||
1252 | * the user request. |
||
1253 | */ |
||
1254 | public function onBeginRequest() |
||
1255 | { |
||
1256 | $this->raiseEvent('OnBeginRequest', $this, null); |
||
1257 | } |
||
1258 | |||
1259 | /** |
||
1260 | * Raises OnAuthentication event. |
||
1261 | * This method is invoked when the user request needs to be authenticated. |
||
1262 | */ |
||
1263 | public function onAuthentication() |
||
1264 | { |
||
1265 | $this->raiseEvent('OnAuthentication', $this, null); |
||
1266 | } |
||
1267 | |||
1268 | /** |
||
1269 | * Raises OnAuthenticationComplete event. |
||
1270 | * This method is invoked right after the user request is authenticated. |
||
1271 | */ |
||
1272 | public function onAuthenticationComplete() |
||
1273 | { |
||
1274 | $this->raiseEvent('OnAuthenticationComplete', $this, null); |
||
1275 | } |
||
1276 | |||
1277 | /** |
||
1278 | * Raises OnAuthorization event. |
||
1279 | * This method is invoked when the user request needs to be authorized. |
||
1280 | */ |
||
1281 | public function onAuthorization() |
||
1282 | { |
||
1283 | $this->raiseEvent('OnAuthorization', $this, null); |
||
1284 | } |
||
1285 | |||
1286 | /** |
||
1287 | * Raises OnAuthorizationComplete event. |
||
1288 | * This method is invoked right after the user request is authorized. |
||
1289 | */ |
||
1290 | public function onAuthorizationComplete() |
||
1291 | { |
||
1292 | $this->raiseEvent('OnAuthorizationComplete', $this, null); |
||
1293 | } |
||
1294 | |||
1295 | /** |
||
1296 | * Raises OnLoadState event. |
||
1297 | * This method is invoked when the application needs to load state (probably stored in session). |
||
1298 | */ |
||
1299 | public function onLoadState() |
||
1300 | { |
||
1301 | $this->loadGlobals(); |
||
1302 | $this->raiseEvent('OnLoadState', $this, null); |
||
1303 | } |
||
1304 | |||
1305 | /** |
||
1306 | * Raises OnLoadStateComplete event. |
||
1307 | * This method is invoked right after the application state has been loaded. |
||
1308 | */ |
||
1309 | public function onLoadStateComplete() |
||
1310 | { |
||
1311 | $this->raiseEvent('OnLoadStateComplete', $this, null); |
||
1312 | } |
||
1313 | |||
1314 | /** |
||
1315 | * Raises OnPreRunService event. |
||
1316 | * This method is invoked right before the service is to be run. |
||
1317 | */ |
||
1318 | public function onPreRunService() |
||
1319 | { |
||
1320 | $this->raiseEvent('OnPreRunService', $this, null); |
||
1321 | } |
||
1322 | |||
1323 | /** |
||
1324 | * Runs the requested service. |
||
1325 | */ |
||
1326 | public function runService() |
||
1327 | { |
||
1328 | if ($this->_service) { |
||
1329 | $this->_service->run(); |
||
1330 | } |
||
1331 | } |
||
1332 | |||
1333 | /** |
||
1334 | * Raises OnSaveState event. |
||
1335 | * This method is invoked when the application needs to save state (probably stored in session). |
||
1336 | */ |
||
1337 | public function onSaveState() |
||
1338 | { |
||
1339 | $this->raiseEvent('OnSaveState', $this, null); |
||
1340 | $this->saveGlobals(); |
||
1341 | } |
||
1342 | |||
1343 | /** |
||
1344 | * Raises OnSaveStateComplete event. |
||
1345 | * This method is invoked right after the application state has been saved. |
||
1346 | */ |
||
1347 | public function onSaveStateComplete() |
||
1348 | { |
||
1349 | $this->raiseEvent('OnSaveStateComplete', $this, null); |
||
1350 | } |
||
1351 | |||
1352 | /** |
||
1353 | * Raises OnPreFlushOutput event. |
||
1354 | * This method is invoked right before the application flushes output to client. |
||
1355 | */ |
||
1356 | public function onPreFlushOutput() |
||
1357 | { |
||
1358 | $this->raiseEvent('OnPreFlushOutput', $this, null); |
||
1359 | } |
||
1360 | |||
1361 | /** |
||
1362 | * Flushes output to client side. |
||
1363 | * @param bool $continueBuffering whether to continue buffering after flush if buffering was active |
||
1364 | */ |
||
1365 | public function flushOutput($continueBuffering = true) |
||
1368 | } |
||
1369 | |||
1370 | /** |
||
1371 | * Raises OnEndRequest event. |
||
1372 | * This method is invoked when the application completes the processing of the request. |
||
1373 | */ |
||
1374 | public function onEndRequest() |
||
1375 | { |
||
1376 | $this->flushOutput(false); // flush all remaining content in the buffer |
||
1377 | $this->raiseEvent('OnEndRequest', $this, null); |
||
1378 | $this->saveGlobals(); // save global state |
||
1379 | } |
||
1380 | } |
||
1381 |
If you suppress an error, we recommend checking for the error condition explicitly: