1 : <?php
2 : /**
3 : * TApplication class file
4 : *
5 : * @author Qiang Xue <qiang.xue@gmail.com>
6 : * @link http://www.pradosoft.com/
7 : * @copyright Copyright © 2005 PradoSoft
8 : * @license http://www.pradosoft.com/license/
9 : * @version $Id: TApplication.php 2244 2007-09-26 13:15:56Z xue $
10 : * @package System
11 : */
12 :
13 : /**
14 : * Includes core interfaces essential for TApplication class
15 : */
16 : require_once(PRADO_DIR.'/interfaces.php');
17 :
18 : /**
19 : * Includes core classes essential for TApplication class
20 : */
21 : Prado::using('System.TApplicationComponent');
22 : Prado::using('System.TModule');
23 : Prado::using('System.TService');
24 : Prado::using('System.Exceptions.TErrorHandler');
25 : Prado::using('System.Caching.TCache');
26 : Prado::using('System.IO.TTextWriter');
27 : Prado::using('System.Collections.TList');
28 : Prado::using('System.Collections.TMap');
29 : Prado::using('System.Collections.TStack');
30 : Prado::using('System.Xml.TXmlDocument');
31 : Prado::using('System.Security.TAuthorizationRule');
32 : Prado::using('System.Security.TSecurityManager');
33 : Prado::using('System.Web.THttpUtility');
34 : Prado::using('System.Web.Javascripts.TJavaScript');
35 : Prado::using('System.Web.THttpRequest');
36 : Prado::using('System.Web.THttpResponse');
37 : Prado::using('System.Web.THttpSession');
38 : Prado::using('System.Web.Services.TPageService');
39 : Prado::using('System.Web.TAssetManager');
40 : Prado::using('System.I18N.TGlobalization');
41 :
42 : /**
43 : * TApplication class.
44 : *
45 : * TApplication coordinates modules and services, and serves as a configuration
46 : * context for all Prado components.
47 : *
48 : * TApplication uses a configuration file to specify the settings of
49 : * the application, the modules, the services, the parameters, and so on.
50 : *
51 : * TApplication adopts a modular structure. A TApplication instance is a composition
52 : * of multiple modules. A module is an instance of class implementing
53 : * {@link IModule} interface. Each module accomplishes certain functionalities
54 : * that are shared by all Prado components in an application.
55 : * There are default modules and user-defined modules. The latter offers extreme
56 : * flexibility of extending TApplication in a plug-and-play fashion.
57 : * Modules cooperate with each other to serve a user request by following
58 : * a sequence of lifecycles predefined in TApplication.
59 : *
60 : * TApplication has four modes that can be changed by setting {@link setMode Mode}
61 : * property (in the application configuration file).
62 : * - <b>Off</b> mode will prevent the application from serving user requests.
63 : * - <b>Debug</b> mode is mainly used during application development. It ensures
64 : * the cache is always up-to-date if caching is enabled. It also allows
65 : * exceptions are displayed with rich context information if they occur.
66 : * - <b>Normal</b> mode is mainly used during production stage. Exception information
67 : * will only be recorded in system error logs. The cache is ensured to be
68 : * up-to-date if it is enabled.
69 : * - <b>Performance</b> mode is similar to <b>Normal</b> mode except that it
70 : * does not ensure the cache is up-to-date.
71 : *
72 : * TApplication dispatches each user request to a particular service which
73 : * finishes the actual work for the request with the aid from the application
74 : * modules.
75 : *
76 : * TApplication maintains a lifecycle with the following stages:
77 : * - [construct] : construction of the application instance
78 : * - [initApplication] : load application configuration and instantiate modules and the requested service
79 : * - onBeginRequest : this event happens right after application initialization
80 : * - onAuthentication : this event happens when authentication is needed for the current request
81 : * - onAuthenticationComplete : this event happens right after the authentication is done for the current request
82 : * - onAuthorization : this event happens when authorization is needed for the current request
83 : * - onAuthorizationComplete : this event happens right after the authorization is done for the current request
84 : * - onLoadState : this event happens when application state needs to be loaded
85 : * - onLoadStateComplete : this event happens right after the application state is loaded
86 : * - onPreRunService : this event happens right before the requested service is to run
87 : * - runService : the requested service runs
88 : * - onSaveState : this event happens when application needs to save its state
89 : * - onSaveStateComplete : this event happens right after the application saves its state
90 : * - onPreFlushOutput : this event happens right before the application flushes output to client side.
91 : * - flushOutput : the application flushes output to client side.
92 : * - onEndRequest : this is the last stage a request is being completed
93 : * - [destruct] : destruction of the application instance
94 : * Modules and services can attach their methods to one or several of the above
95 : * events and do appropriate processing when the events are raised. By this way,
96 : * the application is able to coordinate the activities of modules and services
97 : * in the above order. To terminate an application before the whole lifecycle
98 : * completes, call {@link completeRequest}.
99 : *
100 : * Examples:
101 : * - Create and run a Prado application:
102 : * <code>
103 : * $application=new TApplication($configFile);
104 : * $application->run();
105 : * </code>
106 : *
107 : * @author Qiang Xue <qiang.xue@gmail.com>
108 : * @version $Id: TApplication.php 2244 2007-09-26 13:15:56Z xue $
109 : * @package System
110 : * @since 3.0
111 : */
112 : class TApplication extends TComponent
113 : {
114 : /**
115 : * possible application mode.
116 : * @deprecated deprecated since version 3.0.4 (use TApplicationMode constants instead)
117 : */
118 : const STATE_OFF='Off';
119 : const STATE_DEBUG='Debug';
120 : const STATE_NORMAL='Normal';
121 : const STATE_PERFORMANCE='Performance';
122 :
123 : /**
124 : * Page service ID
125 : */
126 : const PAGE_SERVICE_ID='page';
127 : /**
128 : * Application configuration file name
129 : */
130 : const CONFIG_FILE='application.xml';
131 : /**
132 : * File extension for external config files
133 : */
134 : const CONFIG_FILE_EXT='.xml';
135 : /**
136 : * Runtime directory name
137 : */
138 : const RUNTIME_PATH='runtime';
139 : /**
140 : * Config cache file
141 : */
142 : const CONFIGCACHE_FILE='config.cache';
143 : /**
144 : * Global data file
145 : */
146 : const GLOBAL_FILE='global.cache';
147 :
148 : /**
149 : * @var array list of events that define application lifecycles
150 : */
151 : private static $_steps=array(
152 : 'onBeginRequest',
153 : 'onLoadState',
154 : 'onLoadStateComplete',
155 : 'onAuthentication',
156 : 'onAuthenticationComplete',
157 : 'onAuthorization',
158 : 'onAuthorizationComplete',
159 : 'onPreRunService',
160 : 'runService',
161 : 'onSaveState',
162 : 'onSaveStateComplete',
163 : 'onPreFlushOutput',
164 : 'flushOutput'
165 : );
166 :
167 : /**
168 : * @var string application ID
169 : */
170 : private $_id;
171 : /**
172 : * @var string unique application ID
173 : */
174 : private $_uniqueID;
175 : /**
176 : * @var boolean whether the request is completed
177 : */
178 : private $_requestCompleted=false;
179 : /**
180 : * @var integer application state
181 : */
182 : private $_step;
183 : /**
184 : * @var array available services and their configurations indexed by service IDs
185 : */
186 : private $_services;
187 : /**
188 : * @var IService current service instance
189 : */
190 : private $_service;
191 : /**
192 : * @var array list of application modules
193 : */
194 : private $_modules=array();
195 : /**
196 : * @var TMap list of application parameters
197 : */
198 : private $_parameters;
199 : /**
200 : * @var string configuration file
201 : */
202 : private $_configFile;
203 : /**
204 : * @var string application base path
205 : */
206 : private $_basePath;
207 : /**
208 : * @var string directory storing application state
209 : */
210 : private $_runtimePath;
211 : /**
212 : * @var boolean if any global state is changed during the current request
213 : */
214 : private $_stateChanged=false;
215 : /**
216 : * @var array global variables (persistent across sessions, requests)
217 : */
218 : private $_globals=array();
219 : /**
220 : * @var string cache file
221 : */
222 : private $_cacheFile;
223 : /**
224 : * @var TErrorHandler error handler module
225 : */
226 : private $_errorHandler;
227 : /**
228 : * @var THttpRequest request module
229 : */
230 : private $_request;
231 : /**
232 : * @var THttpResponse response module
233 : */
234 : private $_response;
235 : /**
236 : * @var THttpSession session module, could be null
237 : */
238 : private $_session;
239 : /**
240 : * @var ICache cache module, could be null
241 : */
242 : private $_cache;
243 : /**
244 : * @var IStatePersister application state persister
245 : */
246 : private $_statePersister;
247 : /**
248 : * @var IUser user instance, could be null
249 : */
250 : private $_user;
251 : /**
252 : * @var TGlobalization module, could be null
253 : */
254 : private $_globalization;
255 : /**
256 : * @var TSecurityManager security manager module
257 : */
258 : private $_security;
259 : /**
260 : * @var TAssetManager asset manager module
261 : */
262 : private $_assetManager;
263 : /**
264 : * @var TAuthorizationRuleCollection collection of authorization rules
265 : */
266 : private $_authRules;
267 : /**
268 : * @var TApplicationMode application mode
269 : */
270 : private $_mode=TApplicationMode::Debug;
271 :
272 : /**
273 : * Constructor.
274 : * Sets application base path and initializes the application singleton.
275 : * Application base path refers to the root directory storing application
276 : * data and code not directly accessible by Web users.
277 : * By default, the base path is assumed to be the <b>protected</b>
278 : * directory under the directory containing the current running script.
279 : * @param string application base path or configuration file path.
280 : * If the parameter is a file, it is assumed to be the application
281 : * configuration file, and the directory containing the file is treated
282 : * as the application base path.
283 : * If it is a directory, it is assumed to be the application base path,
284 : * and within that directory, a file named <b>application.xml</b>
285 : * will be looked for. If found, the file is considered as the application
286 : * configuration file.
287 : * @param boolean whether to cache application configuration. Defaults to true.
288 : * @throws TConfigurationException if configuration file cannot be read or the runtime path is invalid.
289 : */
290 : public function __construct($basePath='protected',$cacheConfig=true)
291 : {
292 : // register application as a singleton
293 23 : Prado::setApplication($this);
294 :
295 23 : $this->resolvePaths($basePath);
296 :
297 : if($cacheConfig)
298 23 : $this->_cacheFile=$this->_runtimePath.DIRECTORY_SEPARATOR.self::CONFIGCACHE_FILE;
299 :
300 : // generates unique ID by hashing the runtime path
301 23 : $this->_uniqueID=md5($this->_runtimePath);
302 23 : $this->_parameters=new TMap;
303 23 : $this->_services=array(self::PAGE_SERVICE_ID=>array('TPageService',array(),null));
304 23 : Prado::setPathOfAlias('Application',$this->_basePath);
305 23 : }
306 :
307 : /**
308 : * Resolves application-relevant paths.
309 : * This method is invoked by the application constructor
310 : * to determine the application configuration file,
311 : * application root path and the runtime path.
312 : * @param string the application root path or the application configuration file
313 : * @see setBasePath
314 : * @see setRuntimePath
315 : * @see setConfigurationFile
316 : */
317 : protected function resolvePaths($basePath)
318 : {
319 : // determine configuration path and file
320 23 : if(empty($basePath) || ($basePath=realpath($basePath))===false)
321 23 : throw new TConfigurationException('application_basepath_invalid',$basePath);
322 23 : if(is_file($basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE))
323 23 : $configFile=$basePath.DIRECTORY_SEPARATOR.self::CONFIG_FILE;
324 23 : else if(is_file($basePath))
325 23 : {
326 0 : $configFile=$basePath;
327 0 : $basePath=dirname($configFile);
328 0 : }
329 : else
330 23 : $configFile=null;
331 :
332 : // determine runtime path
333 23 : $runtimePath=$basePath.DIRECTORY_SEPARATOR.self::RUNTIME_PATH;
334 23 : if(is_writable($runtimePath))
335 23 : {
336 23 : if($configFile!==null)
337 23 : {
338 0 : $runtimePath.=DIRECTORY_SEPARATOR.basename($configFile).'-'.Prado::getVersion();
339 0 : if(!is_dir($runtimePath))
340 0 : {
341 0 : if(@mkdir($runtimePath)===false)
342 0 : throw new TConfigurationException('application_runtimepath_failed',$runtimePath);
343 0 : @chmod($runtimePath, PRADO_CHMOD); //make it deletable
344 0 : }
345 0 : $this->setConfigurationFile($configFile);
346 0 : }
347 23 : $this->setBasePath($basePath);
348 23 : $this->setRuntimePath($runtimePath);
349 23 : }
350 : else
351 0 : throw new TConfigurationException('application_runtimepath_invalid',$runtimePath);
352 :
353 23 : }
354 :
355 : /**
356 : * Executes the lifecycles of the application.
357 : * This is the main entry function that leads to the running of the whole
358 : * Prado application.
359 : */
360 : public function run()
361 : {
362 : try
363 : {
364 0 : $this->initApplication();
365 0 : $n=count(self::$_steps);
366 0 : $this->_step=0;
367 0 : $this->_requestCompleted=false;
368 0 : while($this->_step<$n)
369 : {
370 0 : if($this->_mode===self::STATE_OFF)
371 0 : throw new THttpException(503,'application_unavailable');
372 0 : if($this->_requestCompleted)
373 0 : break;
374 0 : $method=self::$_steps[$this->_step];
375 0 : Prado::trace("Executing $method()",'System.TApplication');
376 0 : $this->$method();
377 0 : $this->_step++;
378 0 : }
379 : }
380 0 : catch(Exception $e)
381 : {
382 0 : $this->onError($e);
383 : }
384 0 : $this->onEndRequest();
385 0 : }
386 :
387 : /**
388 : * Completes current request processing.
389 : * This method can be used to exit the application lifecycles after finishing
390 : * the current cycle.
391 : */
392 : public function completeRequest()
393 : {
394 0 : $this->_requestCompleted=true;
395 0 : }
396 :
397 : /**
398 : * @return boolean whether the current request is processed.
399 : */
400 : public function getRequestCompleted()
401 : {
402 0 : return $this->_requestCompleted;
403 : }
404 :
405 : /**
406 : * Returns a global value.
407 : *
408 : * A global value is one that is persistent across users sessions and requests.
409 : * @param string the name of the value to be returned
410 : * @param mixed the default value. If $key is not found, $defaultValue will be returned
411 : * @return mixed the global value corresponding to $key
412 : */
413 : public function getGlobalState($key,$defaultValue=null)
414 : {
415 3 : return isset($this->_globals[$key])?$this->_globals[$key]:$defaultValue;
416 : }
417 :
418 : /**
419 : * Sets a global value.
420 : *
421 : * A global value is one that is persistent across users sessions and requests.
422 : * Make sure that the value is serializable and unserializable.
423 : * @param string the name of the value to be set
424 : * @param mixed the global value to be set
425 : * @param mixed the default value. If $key is not found, $defaultValue will be returned
426 : */
427 : public function setGlobalState($key,$value,$defaultValue=null)
428 : {
429 3 : $this->_stateChanged=true;
430 3 : if($value===$defaultValue)
431 3 : unset($this->_globals[$key]);
432 : else
433 3 : $this->_globals[$key]=$value;
434 3 : }
435 :
436 : /**
437 : * Clears a global value.
438 : *
439 : * The value cleared will no longer be available in this request and the following requests.
440 : * @param string the name of the value to be cleared
441 : */
442 : public function clearGlobalState($key)
443 : {
444 0 : $this->_stateChanged=true;
445 0 : unset($this->_globals[$key]);
446 0 : }
447 :
448 : /**
449 : * Loads global values from persistent storage.
450 : * This method is invoked when {@link onLoadState OnLoadState} event is raised.
451 : * After this method, values that are stored in previous requests become
452 : * available to the current request via {@link getGlobalState}.
453 : */
454 : protected function loadGlobals()
455 : {
456 0 : $this->_globals=$this->getApplicationStatePersister()->load();
457 0 : }
458 :
459 : /**
460 : * Saves global values into persistent storage.
461 : * This method is invoked when {@link onSaveState OnSaveState} event is raised.
462 : */
463 : protected function saveGlobals()
464 : {
465 0 : if($this->_stateChanged)
466 0 : {
467 0 : $this->_stateChanged=false;
468 0 : $this->getApplicationStatePersister()->save($this->_globals);
469 0 : }
470 0 : }
471 :
472 : /**
473 : * @return string application ID
474 : */
475 : public function getID()
476 : {
477 3 : return $this->_id;
478 : }
479 :
480 : /**
481 : * @param string application ID
482 : */
483 : public function setID($value)
484 : {
485 0 : $this->_id=$value;
486 0 : }
487 :
488 : /**
489 : * @return string an ID that uniquely identifies this Prado application from the others
490 : */
491 : public function getUniqueID()
492 : {
493 8 : return $this->_uniqueID;
494 : }
495 :
496 : /**
497 : * @return TApplicationMode application mode. Defaults to TApplicationMode::Debug.
498 : */
499 : public function getMode()
500 : {
501 0 : return $this->_mode;
502 : }
503 :
504 : /**
505 : * @param TApplicationMode application mode
506 : */
507 : public function setMode($value)
508 : {
509 0 : $this->_mode=TPropertyValue::ensureEnum($value,'TApplicationMode');
510 0 : }
511 :
512 : /**
513 : * @return string the directory containing the application configuration file (absolute path)
514 : */
515 : public function getBasePath()
516 : {
517 0 : return $this->_basePath;
518 : }
519 :
520 : /**
521 : * @param string the directory containing the application configuration file
522 : */
523 : public function setBasePath($value)
524 : {
525 23 : $this->_basePath=$value;
526 23 : }
527 :
528 : /**
529 : * @return string the application configuration file (absolute path)
530 : */
531 : public function getConfigurationFile()
532 : {
533 0 : return $this->_configFile;
534 : }
535 :
536 : /**
537 : * @param string the application configuration file (absolute path)
538 : */
539 : public function setConfigurationFile($value)
540 : {
541 0 : $this->_configFile=$value;
542 0 : }
543 :
544 : /**
545 : * @return string the directory storing cache data and application-level persistent data. (absolute path)
546 : */
547 : public function getRuntimePath()
548 : {
549 1 : return $this->_runtimePath;
550 : }
551 :
552 : /**
553 : * @param string the directory storing cache data and application-level persistent data. (absolute path)
554 : */
555 : public function setRuntimePath($value)
556 : {
557 23 : $this->_runtimePath=$value;
558 23 : }
559 :
560 : /**
561 : * @return IService the currently requested service
562 : */
563 : public function getService()
564 : {
565 0 : return $this->_service;
566 : }
567 :
568 : /**
569 : * @param IService the currently requested service
570 : */
571 : public function setService($value)
572 : {
573 0 : $this->_service=$value;
574 0 : }
575 :
576 : /**
577 : * Adds a module to application.
578 : * Note, this method does not do module initialization.
579 : * @param string ID of the module
580 : * @param IModule module object
581 : */
582 : public function setModule($id,IModule $module)
583 : {
584 12 : if(isset($this->_modules[$id]))
585 12 : throw new TConfigurationException('application_moduleid_duplicated',$id);
586 : else
587 12 : $this->_modules[$id]=$module;
588 12 : }
589 :
590 : /**
591 : * @return IModule the module with the specified ID, null if not found
592 : */
593 : public function getModule($id)
594 : {
595 6 : return isset($this->_modules[$id])?$this->_modules[$id]:null;
596 : }
597 :
598 : /**
599 : * @return array list of loaded application modules, indexed by module IDs
600 : */
601 : public function getModules()
602 : {
603 0 : return $this->_modules;
604 : }
605 :
606 : /**
607 : * Returns the list of application parameters.
608 : * Since the parameters are returned as a {@link TMap} object, you may use
609 : * the returned result to access, add or remove individual parameters.
610 : * @return TMap the list of application parameters
611 : */
612 : public function getParameters()
613 : {
614 0 : return $this->_parameters;
615 : }
616 :
617 : /**
618 : * @return THttpRequest the request module
619 : */
620 : public function getRequest()
621 : {
622 18 : if(!$this->_request)
623 18 : {
624 1 : $this->_request=new THttpRequest;
625 1 : $this->_request->init(null);
626 1 : }
627 18 : return $this->_request;
628 : }
629 :
630 : /**
631 : * @param THttpRequest the request module
632 : */
633 : public function setRequest(THttpRequest $request)
634 : {
635 43 : $this->_request=$request;
636 43 : }
637 :
638 : /**
639 : * @return THttpResponse the response module
640 : */
641 : public function getResponse()
642 : {
643 1 : if(!$this->_response)
644 1 : {
645 0 : $this->_response=new THttpResponse;
646 0 : $this->_response->init(null);
647 0 : }
648 1 : return $this->_response;
649 : }
650 :
651 : /**
652 : * @param THttpRequest the request module
653 : */
654 : public function setResponse(THttpResponse $response)
655 : {
656 8 : $this->_response=$response;
657 8 : }
658 :
659 : /**
660 : * @return THttpSession the session module, null if session module is not installed
661 : */
662 : public function getSession()
663 : {
664 0 : if(!$this->_session)
665 0 : {
666 0 : $this->_session=new THttpSession;
667 0 : $this->_session->init(null);
668 0 : }
669 0 : return $this->_session;
670 : }
671 :
672 : /**
673 : * @param THttpSession the session module
674 : */
675 : public function setSession(THttpSession $session)
676 : {
677 1 : $this->_session=$session;
678 1 : }
679 :
680 : /**
681 : * @return TErrorHandler the error handler module
682 : */
683 : public function getErrorHandler()
684 : {
685 0 : if(!$this->_errorHandler)
686 0 : {
687 0 : $this->_errorHandler=new TErrorHandler;
688 0 : $this->_errorHandler->init(null);
689 0 : }
690 0 : return $this->_errorHandler;
691 : }
692 :
693 : /**
694 : * @param TErrorHandler the error handler module
695 : */
696 : public function setErrorHandler(TErrorHandler $handler)
697 : {
698 0 : $this->_errorHandler=$handler;
699 0 : }
700 :
701 : /**
702 : * @return TSecurityManager the security manager module
703 : */
704 : public function getSecurityManager()
705 : {
706 2 : if(!$this->_security)
707 2 : {
708 1 : $this->_security=new TSecurityManager;
709 1 : $this->_security->init(null);
710 1 : }
711 2 : return $this->_security;
712 : }
713 :
714 : /**
715 : * @param TSecurityManager the security manager module
716 : */
717 : public function setSecurityManager(TSecurityManager $sm)
718 : {
719 9 : $this->_security=$sm;
720 9 : }
721 :
722 : /**
723 : * @return TAssetManager asset manager
724 : */
725 : public function getAssetManager()
726 : {
727 1 : if(!$this->_assetManager)
728 1 : {
729 0 : $this->_assetManager=new TAssetManager;
730 0 : $this->_assetManager->init(null);
731 0 : }
732 1 : return $this->_assetManager;
733 : }
734 :
735 : /**
736 : * @param TAssetManager asset manager
737 : */
738 : public function setAssetManager(TAssetManager $value)
739 : {
740 6 : $this->_assetManager=$value;
741 6 : }
742 :
743 : /**
744 : * @return IStatePersister application state persister
745 : */
746 : public function getApplicationStatePersister()
747 : {
748 0 : if(!$this->_statePersister)
749 0 : {
750 0 : $this->_statePersister=new TApplicationStatePersister;
751 0 : $this->_statePersister->init(null);
752 0 : }
753 0 : return $this->_statePersister;
754 : }
755 :
756 : /**
757 : * @param IStatePersister application state persister
758 : */
759 : public function setApplicationStatePersister(IStatePersister $persister)
760 : {
761 0 : $this->_statePersister=$persister;
762 0 : }
763 :
764 : /**
765 : * @return ICache the cache module, null if cache module is not installed
766 : */
767 : public function getCache()
768 : {
769 16 : return $this->_cache;
770 : }
771 :
772 : /**
773 : * @param ICache the cache module
774 : */
775 : public function setCache(ICache $cache)
776 : {
777 16 : $this->_cache=$cache;
778 16 : }
779 :
780 : /**
781 : * @return IUser the application user
782 : */
783 : public function getUser()
784 : {
785 0 : return $this->_user;
786 : }
787 :
788 : /**
789 : * @param IUser the application user
790 : */
791 : public function setUser(IUser $user)
792 : {
793 0 : $this->_user=$user;
794 0 : }
795 :
796 : /**
797 : * @param boolean whether to create globalization if it does not exist
798 : * @return TGlobalization globalization module
799 : */
800 : public function getGlobalization($createIfNotExists=true)
801 : {
802 0 : if($this->_globalization===null && $createIfNotExists)
803 0 : $this->_globalization=new TGlobalization;
804 0 : return $this->_globalization;
805 : }
806 :
807 : /**
808 : * @param TGlobalization globalization module
809 : */
810 : public function setGlobalization(TGlobalization $glob)
811 : {
812 0 : $this->_globalization=$glob;
813 0 : }
814 :
815 : /**
816 : * @return TAuthorizationRuleCollection list of authorization rules for the current request
817 : */
818 : public function getAuthorizationRules()
819 : {
820 0 : if($this->_authRules===null)
821 0 : $this->_authRules=new TAuthorizationRuleCollection;
822 0 : return $this->_authRules;
823 : }
824 :
825 : /**
826 : * Applies an application configuration.
827 : * @param TApplicationConfiguration the configuration
828 : * @param boolean whether the configuration is specified within a service.
829 : */
830 : public function applyConfiguration($config,$withinService=false)
831 : {
832 0 : if($config->getIsEmpty())
833 0 : return;
834 :
835 : // set path aliases and using namespaces
836 0 : foreach($config->getAliases() as $alias=>$path)
837 0 : Prado::setPathOfAlias($alias,$path);
838 0 : foreach($config->getUsings() as $using)
839 0 : Prado::using($using);
840 :
841 : // set application properties
842 0 : if(!$withinService)
843 0 : {
844 0 : foreach($config->getProperties() as $name=>$value)
845 0 : $this->setSubProperty($name,$value);
846 0 : }
847 :
848 : // load parameters
849 0 : foreach($config->getParameters() as $id=>$parameter)
850 : {
851 0 : if(is_array($parameter))
852 0 : {
853 0 : $component=Prado::createComponent($parameter[0]);
854 0 : foreach($parameter[1] as $name=>$value)
855 0 : $component->setSubProperty($name,$value);
856 0 : $this->_parameters->add($id,$component);
857 0 : }
858 : else
859 0 : $this->_parameters->add($id,$parameter);
860 0 : }
861 :
862 : // load and init modules specified in app config
863 0 : $modules=array();
864 0 : foreach($config->getModules() as $id=>$moduleConfig)
865 : {
866 0 : Prado::trace("Loading module $id ({$moduleConfig[0]})",'System.TApplication');
867 0 : list($moduleClass, $initProperties, $configElement)=$moduleConfig;
868 0 : $module=Prado::createComponent($moduleClass);
869 0 : if(!is_string($id))
870 0 : {
871 0 : $id='_module'.count($this->_modules);
872 0 : $initProperties['id']=$id;
873 0 : }
874 0 : $this->setModule($id,$module);
875 0 : foreach($initProperties as $name=>$value)
876 0 : $module->setSubProperty($name,$value);
877 0 : $modules[]=array($module,$configElement);
878 0 : }
879 0 : foreach($modules as $module)
880 0 : $module[0]->init($module[1]);
881 :
882 : // load service
883 0 : foreach($config->getServices() as $serviceID=>$serviceConfig)
884 0 : $this->_services[$serviceID]=$serviceConfig;
885 :
886 : // external configurations
887 0 : foreach($config->getExternalConfigurations() as $filePath=>$condition)
888 : {
889 0 : if($condition!==true)
890 0 : $condition=$this->evaluateExpression($condition);
891 : if($condition)
892 0 : {
893 0 : if(($path=Prado::getPathOfNamespace($filePath,self::CONFIG_FILE_EXT))===null || !is_file($path))
894 0 : throw new TConfigurationException('application_includefile_invalid',$filePath);
895 0 : $c=new TApplicationConfiguration;
896 0 : $c->loadFromFile($path);
897 0 : $this->applyConfiguration($c,$withinService);
898 0 : }
899 0 : }
900 0 : }
901 :
902 : /**
903 : * Loads configuration and initializes application.
904 : * Configuration file will be read and parsed (if a valid cached version exists,
905 : * it will be used instead). Then, modules are created and initialized;
906 : * Afterwards, the requested service is created and initialized.
907 : * @param string configuration file path (absolute or relative to current executing script)
908 : * @param string cache file path, empty if no present or needed
909 : * @throws TConfigurationException if module is redefined of invalid type, or service not defined or of invalid type
910 : */
911 : protected function initApplication()
912 : {
913 0 : Prado::trace('Initializing application','System.TApplication');
914 :
915 0 : if($this->_configFile!==null)
916 0 : {
917 0 : if($this->_cacheFile===null || @filemtime($this->_cacheFile)<filemtime($this->_configFile))
918 0 : {
919 0 : $config=new TApplicationConfiguration;
920 0 : $config->loadFromFile($this->_configFile);
921 0 : if($this->_cacheFile!==null)
922 0 : file_put_contents($this->_cacheFile,Prado::serialize($config),LOCK_EX);
923 0 : }
924 : else
925 0 : $config=Prado::unserialize(file_get_contents($this->_cacheFile));
926 :
927 0 : $this->applyConfiguration($config,false);
928 0 : }
929 :
930 0 : if(($serviceID=$this->getRequest()->resolveRequest(array_keys($this->_services)))===null)
931 0 : $serviceID=self::PAGE_SERVICE_ID;
932 :
933 0 : $this->startService($serviceID);
934 0 : }
935 :
936 : /**
937 : * Starts the specified service.
938 : * The service instance will be created. Its properties will be initialized
939 : * and the configurations will be applied, if any.
940 : * @param string service ID
941 : */
942 : public function startService($serviceID)
943 : {
944 0 : if(isset($this->_services[$serviceID]))
945 0 : {
946 0 : list($serviceClass,$initProperties,$configElement)=$this->_services[$serviceID];
947 0 : $service=Prado::createComponent($serviceClass);
948 0 : if(!($service instanceof IService))
949 0 : throw new THttpException(500,'application_service_invalid',$serviceClass);
950 0 : if(!$service->getEnabled())
951 0 : throw new THttpException(500,'application_service_unavailable',$serviceClass);
952 0 : $service->setID($serviceID);
953 0 : $this->setService($service);
954 :
955 0 : foreach($initProperties as $name=>$value)
956 0 : $service->setSubProperty($name,$value);
957 :
958 0 : if($configElement!==null)
959 0 : {
960 0 : $config=new TApplicationConfiguration;
961 0 : $config->loadFromXml($configElement,$this->getBasePath());
962 0 : $this->applyConfiguration($config,true);
963 0 : }
964 :
965 0 : $service->init($configElement);
966 0 : }
967 : else
968 0 : throw new THttpException(500,'application_service_unknown',$serviceID);
969 0 : }
970 :
971 : /**
972 : * Raises OnError event.
973 : * This method is invoked when an exception is raised during the lifecycles
974 : * of the application.
975 : * @param mixed event parameter
976 : */
977 : public function onError($param)
978 : {
979 0 : Prado::log($param->getMessage(),TLogger::ERROR,'System.TApplication');
980 0 : $this->raiseEvent('OnError',$this,$param);
981 0 : $this->getErrorHandler()->handleError($this,$param);
982 0 : }
983 :
984 : /**
985 : * Raises OnBeginRequest event.
986 : * At the time when this method is invoked, application modules are loaded
987 : * and initialized, user request is resolved and the corresponding service
988 : * is loaded and initialized. The application is about to start processing
989 : * the user request.
990 : */
991 : public function onBeginRequest()
992 : {
993 0 : $this->raiseEvent('OnBeginRequest',$this,null);
994 0 : }
995 :
996 : /**
997 : * Raises OnAuthentication event.
998 : * This method is invoked when the user request needs to be authenticated.
999 : */
1000 : public function onAuthentication()
1001 : {
1002 0 : $this->raiseEvent('OnAuthentication',$this,null);
1003 0 : }
1004 :
1005 : /**
1006 : * Raises OnAuthenticationComplete event.
1007 : * This method is invoked right after the user request is authenticated.
1008 : */
1009 : public function onAuthenticationComplete()
1010 : {
1011 0 : $this->raiseEvent('OnAuthenticationComplete',$this,null);
1012 0 : }
1013 :
1014 : /**
1015 : * Raises OnAuthorization event.
1016 : * This method is invoked when the user request needs to be authorized.
1017 : */
1018 : public function onAuthorization()
1019 : {
1020 0 : $this->raiseEvent('OnAuthorization',$this,null);
1021 0 : }
1022 :
1023 : /**
1024 : * Raises OnAuthorizationComplete event.
1025 : * This method is invoked right after the user request is authorized.
1026 : */
1027 : public function onAuthorizationComplete()
1028 : {
1029 0 : $this->raiseEvent('OnAuthorizationComplete',$this,null);
1030 0 : }
1031 :
1032 : /**
1033 : * Raises OnLoadState event.
1034 : * This method is invoked when the application needs to load state (probably stored in session).
1035 : */
1036 : public function onLoadState()
1037 : {
1038 0 : $this->loadGlobals();
1039 0 : $this->raiseEvent('OnLoadState',$this,null);
1040 0 : }
1041 :
1042 : /**
1043 : * Raises OnLoadStateComplete event.
1044 : * This method is invoked right after the application state has been loaded.
1045 : */
1046 : public function onLoadStateComplete()
1047 : {
1048 0 : $this->raiseEvent('OnLoadStateComplete',$this,null);
1049 0 : }
1050 :
1051 : /**
1052 : * Raises OnPreRunService event.
1053 : * This method is invoked right before the service is to be run.
1054 : */
1055 : public function onPreRunService()
1056 : {
1057 0 : $this->raiseEvent('OnPreRunService',$this,null);
1058 0 : }
1059 :
1060 : /**
1061 : * Runs the requested service.
1062 : */
1063 : public function runService()
1064 : {
1065 0 : if($this->_service)
1066 0 : $this->_service->run();
1067 0 : }
1068 :
1069 : /**
1070 : * Raises OnSaveState event.
1071 : * This method is invoked when the application needs to save state (probably stored in session).
1072 : */
1073 : public function onSaveState()
1074 : {
1075 0 : $this->raiseEvent('OnSaveState',$this,null);
1076 0 : $this->saveGlobals();
1077 0 : }
1078 :
1079 : /**
1080 : * Raises OnSaveStateComplete event.
1081 : * This method is invoked right after the application state has been saved.
1082 : */
1083 : public function onSaveStateComplete()
1084 : {
1085 0 : $this->raiseEvent('OnSaveStateComplete',$this,null);
1086 0 : }
1087 :
1088 : /**
1089 : * Raises OnPreFlushOutput event.
1090 : * This method is invoked right before the application flushes output to client.
1091 : */
1092 : public function onPreFlushOutput()
1093 : {
1094 0 : $this->raiseEvent('OnPreFlushOutput',$this,null);
1095 0 : }
1096 :
1097 : /**
1098 : * Flushes output to client side.
1099 : */
1100 : public function flushOutput()
1101 : {
1102 0 : $this->getResponse()->flush();
1103 0 : }
1104 :
1105 : /**
1106 : * Raises OnEndRequest event.
1107 : * This method is invoked when the application completes the processing of the request.
1108 : */
1109 : public function onEndRequest()
1110 : {
1111 0 : $this->saveGlobals(); // save global state
1112 0 : $this->raiseEvent('OnEndRequest',$this,null);
1113 0 : }
1114 : }
1115 :
1116 : /**
1117 : * TApplicationMode class.
1118 : * TApplicationMode defines the possible mode that an application can be set at by
1119 : * setting {@link TApplication::setMode Mode}.
1120 : * In particular, the following modes are defined
1121 : * - Off: the application is not running. Any request to the application will obtain an error.
1122 : * - Debug: the application is running in debug mode.
1123 : * - Normal: the application is running in normal production mode.
1124 : * - Performance: the application is running in performance mode.
1125 : * @author Qiang Xue <qiang.xue@gmail.com>
1126 : * @version $Id: TApplication.php 2244 2007-09-26 13:15:56Z xue $
1127 : * @package System
1128 : * @since 3.0.4
1129 : */
1130 : class TApplicationMode extends TEnumerable
1131 : {
1132 : const Off='Off';
1133 : const Debug='Debug';
1134 : const Normal='Normal';
1135 : const Performance='Performance';
1136 : }
1137 :
1138 :
1139 : /**
1140 : * TApplicationConfiguration class.
1141 : *
1142 : * This class is used internally by TApplication to parse and represent application configuration.
1143 : *
1144 : * @author Qiang Xue <qiang.xue@gmail.com>
1145 : * @version $Id: TApplication.php 2244 2007-09-26 13:15:56Z xue $
1146 : * @package System
1147 : * @since 3.0
1148 : */
1149 : class TApplicationConfiguration extends TComponent
1150 : {
1151 : /**
1152 : * @var array list of application initial property values, indexed by property names
1153 : */
1154 : private $_properties=array();
1155 : /**
1156 : * @var array list of namespaces to be used
1157 : */
1158 : private $_usings=array();
1159 : /**
1160 : * @var array list of path aliases, indexed by alias names
1161 : */
1162 : private $_aliases=array();
1163 : /**
1164 : * @var array list of module configurations
1165 : */
1166 : private $_modules=array();
1167 : /**
1168 : * @var array list of service configurations
1169 : */
1170 : private $_services=array();
1171 : /**
1172 : * @var array list of parameters
1173 : */
1174 : private $_parameters=array();
1175 : /**
1176 : * @var array list of included configurations
1177 : */
1178 : private $_includes=array();
1179 : /**
1180 : * @var boolean whether this configuration contains actual stuff
1181 : */
1182 : private $_empty=true;
1183 :
1184 : /**
1185 : * Parses the application configuration file.
1186 : * @param string configuration file name
1187 : * @throws TConfigurationException if there is any parsing error
1188 : */
1189 : public function loadFromFile($fname)
1190 : {
1191 0 : $dom=new TXmlDocument;
1192 0 : $dom->loadFromFile($fname);
1193 0 : $this->loadFromXml($dom,dirname($fname));
1194 0 : }
1195 :
1196 : /**
1197 : * @return boolean whether this configuration contains actual stuff
1198 : */
1199 : public function getIsEmpty()
1200 : {
1201 0 : return $this->_empty;
1202 : }
1203 :
1204 : /**
1205 : * Parses the application configuration given in terms of a TXmlElement.
1206 : * @param TXmlElement the XML element
1207 : * @param string the context path (for specifying relative paths)
1208 : */
1209 : public function loadFromXml($dom,$configPath)
1210 : {
1211 : // application properties
1212 0 : foreach($dom->getAttributes() as $name=>$value)
1213 : {
1214 0 : $this->_properties[$name]=$value;
1215 0 : $this->_empty=false;
1216 0 : }
1217 :
1218 0 : foreach($dom->getElements() as $element)
1219 : {
1220 0 : switch($element->getTagName())
1221 : {
1222 0 : case 'paths':
1223 0 : $this->loadPathsXml($element,$configPath);
1224 0 : break;
1225 0 : case 'modules':
1226 0 : $this->loadModulesXml($element,$configPath);
1227 0 : break;
1228 0 : case 'services':
1229 0 : $this->loadServicesXml($element,$configPath);
1230 0 : break;
1231 0 : case 'parameters':
1232 0 : $this->loadParametersXml($element,$configPath);
1233 0 : break;
1234 0 : case 'include':
1235 0 : $this->loadExternalXml($element,$configPath);
1236 0 : break;
1237 0 : default:
1238 : //throw new TConfigurationException('appconfig_tag_invalid',$element->getTagName());
1239 0 : break;
1240 0 : }
1241 0 : }
1242 0 : }
1243 :
1244 : /**
1245 : * Loads the paths XML node.
1246 : * @param TXmlElement the paths XML node
1247 : * @param string the context path (for specifying relative paths)
1248 : */
1249 : protected function loadPathsXml($pathsNode,$configPath)
1250 : {
1251 0 : foreach($pathsNode->getElements() as $element)
1252 : {
1253 0 : switch($element->getTagName())
1254 : {
1255 0 : case 'alias':
1256 : {
1257 0 : if(($id=$element->getAttribute('id'))!==null && ($path=$element->getAttribute('path'))!==null)
1258 0 : {
1259 0 : $path=str_replace('\\','/',$path);
1260 0 : if(preg_match('/^\\/|.:\\/|.:\\\\/',$path)) // if absolute path
1261 0 : $p=realpath($path);
1262 : else
1263 0 : $p=realpath($configPath.DIRECTORY_SEPARATOR.$path);
1264 0 : if($p===false || !is_dir($p))
1265 0 : throw new TConfigurationException('appconfig_aliaspath_invalid',$id,$path);
1266 0 : if(isset($this->_aliases[$id]))
1267 0 : throw new TConfigurationException('appconfig_alias_redefined',$id);
1268 0 : $this->_aliases[$id]=$p;
1269 0 : }
1270 : else
1271 0 : throw new TConfigurationException('appconfig_alias_invalid');
1272 0 : $this->_empty=false;
1273 0 : break;
1274 : }
1275 0 : case 'using':
1276 : {
1277 0 : if(($namespace=$element->getAttribute('namespace'))!==null)
1278 0 : $this->_usings[]=$namespace;
1279 : else
1280 0 : throw new TConfigurationException('appconfig_using_invalid');
1281 0 : $this->_empty=false;
1282 0 : break;
1283 : }
1284 0 : default:
1285 0 : throw new TConfigurationException('appconfig_paths_invalid',$tagName);
1286 0 : }
1287 0 : }
1288 0 : }
1289 :
1290 : /**
1291 : * Loads the modules XML node.
1292 : * @param TXmlElement the modules XML node
1293 : * @param string the context path (for specifying relative paths)
1294 : */
1295 : protected function loadModulesXml($modulesNode,$configPath)
1296 : {
1297 0 : foreach($modulesNode->getElements() as $element)
1298 : {
1299 0 : if($element->getTagName()==='module')
1300 0 : {
1301 0 : $properties=$element->getAttributes();
1302 0 : $id=$properties->itemAt('id');
1303 0 : $type=$properties->remove('class');
1304 0 : if($type===null)
1305 0 : throw new TConfigurationException('appconfig_moduletype_required',$id);
1306 0 : $element->setParent(null);
1307 0 : if($id===null)
1308 0 : $this->_modules[]=array($type,$properties->toArray(),$element);
1309 : else
1310 0 : $this->_modules[$id]=array($type,$properties->toArray(),$element);
1311 0 : $this->_empty=false;
1312 0 : }
1313 : else
1314 0 : throw new TConfigurationException('appconfig_modules_invalid',$element->getTagName());
1315 0 : }
1316 0 : }
1317 :
1318 : /**
1319 : * Loads the services XML node.
1320 : * @param TXmlElement the services XML node
1321 : * @param string the context path (for specifying relative paths)
1322 : */
1323 : protected function loadServicesXml($servicesNode,$configPath)
1324 : {
1325 0 : foreach($servicesNode->getElements() as $element)
1326 : {
1327 0 : if($element->getTagName()==='service')
1328 0 : {
1329 0 : $properties=$element->getAttributes();
1330 0 : if(($id=$properties->itemAt('id'))===null)
1331 0 : throw new TConfigurationException('appconfig_serviceid_required');
1332 0 : if(($type=$properties->remove('class'))===null)
1333 0 : throw new TConfigurationException('appconfig_servicetype_required',$id);
1334 0 : $element->setParent(null);
1335 0 : $this->_services[$id]=array($type,$properties->toArray(),$element);
1336 0 : $this->_empty=false;
1337 0 : }
1338 : else
1339 0 : throw new TConfigurationException('appconfig_services_invalid',$element->getTagName());
1340 0 : }
1341 0 : }
1342 :
1343 : /**
1344 : * Loads the parameters XML node.
1345 : * @param TXmlElement the parameters XML node
1346 : * @param string the context path (for specifying relative paths)
1347 : */
1348 : protected function loadParametersXml($parametersNode,$configPath)
1349 : {
1350 0 : foreach($parametersNode->getElements() as $element)
1351 : {
1352 0 : if($element->getTagName()==='parameter')
1353 0 : {
1354 0 : $properties=$element->getAttributes();
1355 0 : if(($id=$properties->remove('id'))===null)
1356 0 : throw new TConfigurationException('appconfig_parameterid_required');
1357 0 : if(($type=$properties->remove('class'))===null)
1358 0 : {
1359 0 : if(($value=$properties->remove('value'))===null)
1360 0 : $this->_parameters[$id]=$element;
1361 : else
1362 0 : $this->_parameters[$id]=$value;
1363 0 : }
1364 : else
1365 0 : $this->_parameters[$id]=array($type,$properties->toArray());
1366 0 : $this->_empty=false;
1367 0 : }
1368 : else
1369 0 : throw new TConfigurationException('appconfig_parameters_invalid',$element->getTagName());
1370 0 : }
1371 0 : }
1372 :
1373 : /**
1374 : * Loads the external XML configurations.
1375 : * @param TXmlElement the application DOM element
1376 : * @param string the context path (for specifying relative paths)
1377 : */
1378 : protected function loadExternalXml($includeNode,$configPath)
1379 : {
1380 0 : if(($when=$includeNode->getAttribute('when'))===null)
1381 0 : $when=true;
1382 0 : if(($filePath=$includeNode->getAttribute('file'))===null)
1383 0 : throw new TConfigurationException('appconfig_includefile_required');
1384 0 : if(isset($this->_includes[$filePath]))
1385 0 : $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')';
1386 : else
1387 0 : $this->_includes[$filePath]=$when;
1388 0 : $this->_empty=false;
1389 0 : }
1390 :
1391 : /**
1392 : * Returns list of page initial property values.
1393 : * Each array element represents a single property with the key
1394 : * being the property name and the value the initial property value.
1395 : * @return array list of page initial property values
1396 : */
1397 : public function getProperties()
1398 : {
1399 0 : return $this->_properties;
1400 : }
1401 :
1402 : /**
1403 : * Returns list of path alias definitions.
1404 : * The definitions are aggregated (top-down) from configuration files along the path
1405 : * to the specified page. Each array element represents a single alias definition,
1406 : * with the key being the alias name and the value the absolute path.
1407 : * @return array list of path alias definitions
1408 : */
1409 : public function getAliases()
1410 : {
1411 0 : return $this->_aliases;
1412 : }
1413 :
1414 : /**
1415 : * Returns list of namespaces to be used.
1416 : * The namespaces are aggregated (top-down) from configuration files along the path
1417 : * to the specified page. Each array element represents a single namespace usage,
1418 : * with the value being the namespace to be used.
1419 : * @return array list of namespaces to be used
1420 : */
1421 : public function getUsings()
1422 : {
1423 0 : return $this->_usings;
1424 : }
1425 :
1426 : /**
1427 : * Returns list of module configurations.
1428 : * The module configurations are aggregated (top-down) from configuration files
1429 : * along the path to the specified page. Each array element represents
1430 : * a single module configuration, with the key being the module ID and
1431 : * the value the module configuration. Each module configuration is
1432 : * stored in terms of an array with the following content
1433 : * ([0]=>module type, [1]=>module properties, [2]=>complete module configuration)
1434 : * The module properties are an array of property values indexed by property names.
1435 : * The complete module configuration is a TXmlElement object representing
1436 : * the raw module configuration which may contain contents enclosed within
1437 : * module tags.
1438 : * @return array list of module configurations to be used
1439 : */
1440 : public function getModules()
1441 : {
1442 0 : return $this->_modules;
1443 : }
1444 :
1445 : /**
1446 : * @return array list of service configurations
1447 : */
1448 : public function getServices()
1449 : {
1450 0 : return $this->_services;
1451 : }
1452 :
1453 : /**
1454 : * Returns list of parameter definitions.
1455 : * The parameter definitions are aggregated (top-down) from configuration files
1456 : * along the path to the specified page. Each array element represents
1457 : * a single parameter definition, with the key being the parameter ID and
1458 : * the value the parameter definition. A parameter definition can be either
1459 : * a string representing a string-typed parameter, or an array.
1460 : * The latter defines a component-typed parameter whose format is as follows,
1461 : * ([0]=>component type, [1]=>component properties)
1462 : * The component properties are an array of property values indexed by property names.
1463 : * @return array list of parameter definitions to be used
1464 : */
1465 : public function getParameters()
1466 : {
1467 0 : return $this->_parameters;
1468 : }
1469 :
1470 : /**
1471 : * @return array list of external configuration files. Each element is like $filePath=>$condition
1472 : */
1473 : public function getExternalConfigurations()
1474 : {
1475 0 : return $this->_includes;
1476 : }
1477 : }
1478 :
1479 : /**
1480 : * TApplicationStatePersister class.
1481 : * TApplicationStatePersister provides a file-based persistent storage
1482 : * for application state. Application state, when serialized, is stored
1483 : * in a file named 'global.cache' under the 'runtime' directory of the application.
1484 : * Cache will be exploited if it is enabled.
1485 : *
1486 : * @author Qiang Xue <qiang.xue@gmail.com>
1487 : * @version $Id: TApplication.php 2244 2007-09-26 13:15:56Z xue $
1488 : * @package System
1489 : * @since 3.0
1490 : */
1491 : class TApplicationStatePersister extends TModule implements IStatePersister
1492 : {
1493 : /**
1494 : * Name of the value stored in cache
1495 : */
1496 : const CACHE_NAME='prado:appstate';
1497 :
1498 : /**
1499 : * Initializes module.
1500 : * @param TXmlElement module configuration (may be null)
1501 : */
1502 : public function init($config)
1503 : {
1504 0 : $this->getApplication()->setApplicationStatePersister($this);
1505 0 : }
1506 :
1507 : /**
1508 : * @return string the file path storing the application state
1509 : */
1510 : protected function getStateFilePath()
1511 : {
1512 0 : return $this->getApplication()->getRuntimePath().'/global.cache';
1513 : }
1514 :
1515 : /**
1516 : * Loads application state from persistent storage.
1517 : * @return mixed application state
1518 : */
1519 : public function load()
1520 : {
1521 0 : if(($cache=$this->getApplication()->getCache())!==null && ($value=$cache->get(self::CACHE_NAME))!==false)
1522 0 : return unserialize($value);
1523 : else
1524 : {
1525 0 : if(($content=@file_get_contents($this->getStateFilePath()))!==false)
1526 0 : return unserialize($content);
1527 : else
1528 0 : return null;
1529 : }
1530 : }
1531 :
1532 : /**
1533 : * Saves application state in persistent storage.
1534 : * @param mixed application state
1535 : */
1536 : public function save($state)
1537 : {
1538 0 : $content=serialize($state);
1539 0 : $saveFile=true;
1540 0 : if(($cache=$this->getApplication()->getCache())!==null)
1541 0 : {
1542 0 : if($cache->get(self::CACHE_NAME)===$content)
1543 0 : $saveFile=false;
1544 : else
1545 0 : $cache->set(self::CACHE_NAME,$content);
1546 0 : }
1547 : if($saveFile)
1548 0 : {
1549 0 : $fileName=$this->getStateFilePath();
1550 0 : file_put_contents($fileName,$content,LOCK_EX);
1551 0 : }
1552 0 : }
1553 :
1554 : }
1555 : ?>
|