PageRenderTime 8ms CodeModel.GetById 26ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 1ms

/base/CApplication.php

https://bitbucket.org/stden/yiiru
PHP | 991 lines | 486 code | 71 blank | 434 comment | 58 complexity | 4c9a402722bfb9b6db543a8273649fbc MD5 | raw file
  1<?php
  2/**
  3 * Файл класса CApplication.
  4 *
  5 * @author Qiang Xue <qiang.xue@gmail.com>
  6 * @link http://www.yiiframework.com/
  7 * @copyright Copyright &copy; 2008-2011 Yii Software LLC
  8 * @license http://www.yiiframework.com/license/
  9 */
 10
 11/**
 12 * CApplication - это базовый класс для всех классов приложения.
 13 *
 14 * Приложение служит в качестве глобального контекста, в котором выполняется запрос пользователя.
 15 * Оно управляет набором компонентов приложения, предоставляющих
 16 * специальные функции для всего приложения.
 17 *
 18 * Список компонентов ядра приложения, предоставляемых классом CApplication:
 19 * <ul>
 20 * <li>{@link getErrorHandler errorHandler}: обрабатывает ошибки PHP и
 21 *   неперехваченные исключения. Данный компонент приложения загружается динамически при необходимости;</li>
 22 * <li>{@link getSecurityManager securityManager}: предоставляет функции безопасности
 23 *   такие, как хэширование, шифрование. Данный компонент приложения загружается динамически при необходимости;</li>
 24 * <li>{@link getStatePersister statePersister}: предоставляет функцию постоянного глобального состояния.
 25 *   Данный компонент приложения загружается динамически при необходимости;</li>
 26 * <li>{@link getCache cache}: предоставляет функции кэширования. Данный компонент по умолчанию отключен;</li>
 27 * <li>{@link getMessages messages}: предоставляет источник сообщений для перевода сообщений
 28 *   приложения. Данный компонент приложения загружается динамически при необходимости;</li>
 29 * <li>{@link getCoreMessages coreMessages}: предоставляет источник сообщений для перевода сообщений
 30 *   фреймворка Yii. Данный компонент приложения загружается динамически при необходимости.</li>
 31 * </ul>
 32 *
 33 * CApplication работает по следующему жизненному циклу при обработке пользовательского запроса:
 34 * <ol>
 35 * <li>загружает конфигурацию приложения;</li>
 36 * <li>устанавливает класс автозагрузчика и обработчика ошибок;</li>
 37 * <li>загружает статические компоненты приложения;</li>
 38 * <li>{@link onBeginRequest}: выполняет действия перед выполнением пользовательского запроса;</li>
 39 * <li>{@link processRequest}: выполняет пользовательский запрос;</li>
 40 * <li>{@link onEndRequest}: выполняет действия после выполнения пользовательского запроса;</li>
 41 * </ol>
 42 *
 43 * Начиная с пункта 3, при возникновении ошибки PHP или неперехваченного
 44 * исключения, приложение переключается на его обработчик ошибок и после
 45 * переходит к шагу 6.
 46 *
 47 * @property string $id уникальный идентификатор приложения
 48 * @property string $basePath корневая директория приложения. По умолчанию -
 49 * 'protected'
 50 * @property string $runtimePath директория, хранящая рабочие файлы. По
 51 * умолчанию - 'protected/runtime'
 52 * @property string $extensionPath директория, содержащая все расширения. По
 53 * умолчанию - директория 'extensions' в директории 'protected'
 54 * @property string $language язык, используемый пользователем и приложением.
 55 * По умолчанию задан свойством {@link sourceLanguage}
 56 * @property string $timeZone временная зона, используемая приложением
 57 * @property CLocale $locale экземпляр локали
 58 * @property string $localeDataPath директория, содержащая данные локали. По
 59 * умолчанию - 'framework/i18n/data'
 60 * @property CNumberFormatter $numberFormatter локалезависимый менеджер
 61 * форматирования чисел. Используется текущая {@link getLocale локаль приложения}
 62 * @property CDateFormatter $dateFormatter локалезависимый менеджер
 63 * форматирования дат. Используется текущая {@link getLocale локаль приложения}
 64 * @property CDbConnection $db компонент соединения с базой
 65 * @property CErrorHandler $errorHandler комопонент приложения, отвечающий за
 66 * обработку ошибок
 67 * @property CSecurityManager $securityManager компонент приложения, отвечающий
 68 * за безопасность
 69 * @property CStatePersister $statePersister компонент приложения,
 70 * представляющий постоянное состояние (state persister)
 71 * @property CCache $cache компонент приложения кэша. Null, если компонент не
 72 * включен
 73 * @property CPhpMessageSource $coreMessages компонент приложения, отвечающий
 74 * за перевод сообщений ядра
 75 * @property CMessageSource $messages компонент приложения, отвечающий за
 76 * перевод сообщений приложения
 77 * @property CHttpRequest $request компонент запроса
 78 * @property CUrlManager $urlManager менеджер URL маршрутов
 79 * @property CController $controller текущий активный контроллер. В данном
 80 * базовом классе возвращается значение null
 81 * @property string $baseUrl относительный URL-адрес приложения
 82 * @property string $homeUrl URL-адрес домашней страницы
 83 *
 84 * @author Qiang Xue <qiang.xue@gmail.com>
 85 * @version $Id: CApplication.php 3515 2011-12-28 12:29:24Z mdomba $
 86 * @package system.base
 87 * @since 1.0
 88 */
 89abstract class CApplication extends CModule
 90{
 91	/**
 92	 * @var string имя приложения. По умолчанию - 'My Application'.
 93	 */
 94	public $name='My Application';
 95	/**
 96	 * @var string кодировка, используемая приложением. По умолчанию - 'UTF-8'.
 97	 */
 98	public $charset='UTF-8';
 99	/**
100	 * @var string язык приложения. В основном это язык сообщений и представлений.
101	 * По умолчанию - 'en_us' (US English).
102	 */
103	public $sourceLanguage='en_us';
104
105	private $_id;
106	private $_basePath;
107	private $_runtimePath;
108	private $_extensionPath;
109	private $_globalState;
110	private $_stateChanged;
111	private $_ended=false;
112	private $_language;
113	private $_homeUrl;
114
115	/**
116	 * Выполняет запрос.
117	 * Это то место, где выполняется основная работа по запросу.
118	 * Классы-наследники должны переопределить данный метод.
119	 */
120	abstract public function processRequest();
121
122	/**
123	 * Конструктор.
124	 * @param mixed $config конфигурация приложения.
125	 * Если передана строка, она считается путем к файлу, содержащему конфигурацию;
126	 * если передан массив, он считается реальной информацией конфигурации.
127	 * Убедитесь, что свойство {@link getBasePath basePath} определено в конфигурации и
128	 * указывает на директорию, содержащую всю логику приложения, шаблоны и данные.
129	 * Если это свойство не указано, по умолчанию будет использована директория 'protected'.
130	 */
131	public function __construct($config=null)
132	{
133		Yii::setApplication($this);
134
135		// set basePath at early as possible to avoid trouble
136		if(is_string($config))
137			$config=require($config);
138		if(isset($config['basePath']))
139		{
140			$this->setBasePath($config['basePath']);
141			unset($config['basePath']);
142		}
143		else
144			$this->setBasePath('protected');
145		Yii::setPathOfAlias('application',$this->getBasePath());
146		Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME']));
147		Yii::setPathOfAlias('ext',$this->getBasePath().DIRECTORY_SEPARATOR.'extensions');
148
149		$this->preinit();
150
151		$this->initSystemHandlers();
152		$this->registerCoreComponents();
153
154		$this->configure($config);
155		$this->attachBehaviors($this->behaviors);
156		$this->preloadComponents();
157
158		$this->init();
159	}
160
161
162	/**
163	 * Запускает приложение.
164	 * Метод загружает статические компоненты приложения. Классы-наследники обычно переопределяют
165	 * данны метод для выполнения более специфичных задач приложения.
166	 * Не забудьте вызвать метод родителя для загрузки статических компонентов приложения.
167	 */
168	public function run()
169	{
170		if($this->hasEventHandler('onBeginRequest'))
171			$this->onBeginRequest(new CEvent($this));
172		$this->processRequest();
173		if($this->hasEventHandler('onEndRequest'))
174			$this->onEndRequest(new CEvent($this));
175	}
176
177	/**
178	 * Завершает приложение.
179	 * Метод заменяет PHP функцию exit() вызовом метода {@link onEndRequest} перед выходом.
180	 * @param integer $status статус выхода (значение 0 означает нормальный выход, другое значение означает выход с ошибкой)
181	 * @param boolean $exit завершить ли текущий запрос. Данный параметр доступен с версии 1.1.5.
182	 * По умолчанию - true, т.е., PHP функция exit() будет вызываться в конце данного метода
183	 */
184	public function end($status=0, $exit=true)
185	{
186		if($this->hasEventHandler('onEndRequest'))
187			$this->onEndRequest(new CEvent($this));
188		if($exit)
189			exit($status);
190	}
191
192	/**
193	 * Выполняется непосредственно ПЕРЕД обработкой запроса приложением.
194	 * @param CEvent $event параметр события
195	 */
196	public function onBeginRequest($event)
197	{
198		$this->raiseEvent('onBeginRequest',$event);
199	}
200
201	/**
202	 * Выполняется сразу ПОСЛЕ обработки запроса приложением.
203	 * @param CEvent $event параметр события
204	 */
205	public function onEndRequest($event)
206	{
207		if(!$this->_ended)
208		{
209			$this->_ended=true;
210			$this->raiseEvent('onEndRequest',$event);
211		}
212	}
213
214	/**
215	 * Возвращает уникальный идентификатор приложения
216	 * @return string уникальный идентификатор приложения
217	 */
218	public function getId()
219	{
220		if($this->_id!==null)
221			return $this->_id;
222		else
223			return $this->_id=sprintf('%x',crc32($this->getBasePath().$this->name));
224	}
225
226	/**
227	 * Устанавливает уникальный идентификатор приложения
228	 * @param string $id уникальный идентификатор приложения
229	 */
230	public function setId($id)
231	{
232		$this->_id=$id;
233	}
234
235	/**
236	 * Возвращает корневую директорию приложения
237	 * @return string корневая директория приложения. По умолчанию - 'protected'
238	 */
239	public function getBasePath()
240	{
241		return $this->_basePath;
242	}
243
244	/**
245	 * Устанавливает корневую директорию приложения.
246	 * Метод может быть вызван только в начале конструктора
247	 * @param string $path корневая директория приложения
248	 * @throws CException вызывается, если директория не существует
249	 */
250	public function setBasePath($path)
251	{
252		if(($this->_basePath=realpath($path))===false || !is_dir($this->_basePath))
253			throw new CException(Yii::t('yii','Application base path "{path}" is not a valid directory.',
254				array('{path}'=>$path)));
255	}
256
257	/**
258	 * Возвращает директорию, хранящую рабочие файлы
259	 * @return string директория, хранящая рабочие файлы. По умолчанию - 'protected/runtime'
260	 */
261	public function getRuntimePath()
262	{
263		if($this->_runtimePath!==null)
264			return $this->_runtimePath;
265		else
266		{
267			$this->setRuntimePath($this->getBasePath().DIRECTORY_SEPARATOR.'runtime');
268			return $this->_runtimePath;
269		}
270	}
271
272	/**
273	 * Устанавливает директорию, хранящую рабочие файлы
274	 * @param string $path директория, хранящая рабочие файлы
275	 * @throws CException вызывается, если директория не существует или недоступна для записи
276	 */
277	public function setRuntimePath($path)
278	{
279		if(($runtimePath=realpath($path))===false || !is_dir($runtimePath) || !is_writable($runtimePath))
280			throw new CException(Yii::t('yii','Application runtime path "{path}" is not valid. Please make sure it is a directory writable by the Web server process.',
281				array('{path}'=>$path)));
282		$this->_runtimePath=$runtimePath;
283	}
284
285	/**
286	 * Возвращает корневую директорию, хранящую все сторонние расширения
287	 * @return string директория, содержащая все расширения. По умолчанию - директория 'extensions' в директории 'protected'
288	 */
289	public function getExtensionPath()
290	{
291		return Yii::getPathOfAlias('ext');
292	}
293
294	/**
295	 * Устанавливает корневую директорию, хранящую все сторонние расширения
296	 * @param string $path директория, содержащая все сторонние расширения
297	 */
298	public function setExtensionPath($path)
299	{
300		if(($extensionPath=realpath($path))===false || !is_dir($extensionPath))
301			throw new CException(Yii::t('yii','Extension path "{path}" does not exist.',
302				array('{path}'=>$path)));
303		Yii::setPathOfAlias('ext',$extensionPath);
304	}
305
306	/**
307	 * Возвращает язык, используемый пользователем и приложением
308	 * @return string язык, используемый пользователем и приложением.
309	 * По умолчанию задан свойством {@link sourceLanguage}
310	 */
311	public function getLanguage()
312	{
313		return $this->_language===null ? $this->sourceLanguage : $this->_language;
314	}
315
316	/**
317	 * Определяет язык, используемый приложением.
318	 *
319	 * Это язык, отображаемый приложением конечным пользователям.
320	 * Если null, будет использован язык, заданный свойством {@link sourceLanguage}.
321	 *
322	 * Если ваше приложение должно поддерживать несколько языков, вы должны всегда
323	 * устанавливать данный язык в null для улучшения производительности приложения
324	 * @param string $language язык пользователя (например, 'en_US', 'zh_CN').
325	 * Если null, будет использован язык, заданный свойством {@link sourceLanguage}
326	 */
327	public function setLanguage($language)
328	{
329		$this->_language=$language;
330	}
331
332	/**
333	 * Возвращает временную зону, используемую приложением.
334	 * Это простая обертка PHP-функции date_default_timezone_get()
335	 * @return string временная зона, используемая приложением
336	 * @see http://php.net/manual/en/function.date-default-timezone-get.php
337	 */
338	public function getTimeZone()
339	{
340		return date_default_timezone_get();
341	}
342
343	/**
344	 * Устанавливает временную зону, используемую приложением.
345	 * Это простая обертка PHP-функции date_default_timezone_set()
346	 * @param string $value временная зона, используемая приложением
347	 * @see http://php.net/manual/en/function.date-default-timezone-set.php
348	 */
349	public function setTimeZone($value)
350	{
351		date_default_timezone_set($value);
352	}
353
354	/**
355	 * Возвращает локализованную версию определенного файла.
356	 *
357	 * Поиск идет по коду определенного языка. В частности,
358	 * файл с таким же именем будет искаться в поддиректории с именем,
359	 * равным иеднтификатору локали. Например, если переданы файл "path/to/view.php"
360	 * и локаль "zh_cn", то путёт поиска локализованнного файла будет
361	 * "path/to/zh_cn/view.php". Если файл не найден, будет возвращен оригинальный файл.
362	 *
363	 * Для согласованности рекомендуется передавать идентификатор локали
364	 * в нижнем регистре и в формате идентификаторЯзыка_идентификаторРегиона (например, "en_us")
365	 *
366	 * @param string $srcFile оригинальный файл
367	 * @param string $srcLanguage язык оригинального файла. Если null, используется язык, заданный свойством {@link sourceLanguage}
368	 * @param string $language желаемый язык, локализованная версия файла которого требуется. Если null, используется {@link getLanguage язык приложения}
369	 * @return string соответствующий локализованный файл. Если локализованныя версия не найдена или исходный язык равен желаемомоу, возвращается оригинальный файл
370	 */
371	public function findLocalizedFile($srcFile,$srcLanguage=null,$language=null)
372	{
373		if($srcLanguage===null)
374			$srcLanguage=$this->sourceLanguage;
375		if($language===null)
376			$language=$this->getLanguage();
377		if($language===$srcLanguage)
378			return $srcFile;
379		$desiredFile=dirname($srcFile).DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.basename($srcFile);
380		return is_file($desiredFile) ? $desiredFile : $srcFile;
381	}
382
383	/**
384	 * Возвращает экземпляр локали
385	 * @param string $localeID идентификатор локали (например, en_US). Если null, используется идентификатор {@link getLanguage языка приложения}
386	 * @return CLocale экземпляр локали
387	 */
388	public function getLocale($localeID=null)
389	{
390		return CLocale::getInstance($localeID===null?$this->getLanguage():$localeID);
391	}
392
393	/**
394	 * Возвращает директорию, содержащую данные локали
395	 * @return string директория, содержащая данные локали. По умолчанию - 'framework/i18n/data'
396	 * @since 1.1.0
397	 */
398	public function getLocaleDataPath()
399	{
400		return CLocale::$dataPath===null ? Yii::getPathOfAlias('system.i18n.data') : CLocale::$dataPath;
401	}
402
403	/**
404	 * Устанавливает директорию, содержащую данные локали
405	 * @param string $value директория, содержащая данные локали
406	 * @since 1.1.0
407	 */
408	public function setLocaleDataPath($value)
409	{
410		CLocale::$dataPath=$value;
411	}
412
413	/**
414	 * Возвращает локалезависимый менеджер форматирования чисел
415	 * @return CNumberFormatter локалезависимый менеджер форматирования чисел.
416	 * Используется текущая {@link getLocale локаль приложения}
417	 */
418	public function getNumberFormatter()
419	{
420		return $this->getLocale()->getNumberFormatter();
421	}
422
423	/**
424	 * Возвращает локалезависимый менеджер форматирования дат
425	 * @return CDateFormatter локалезависимый менеджер форматирования дат.
426	 * Используется текущая {@link getLocale локаль приложения}
427	 */
428	public function getDateFormatter()
429	{
430		return $this->getLocale()->getDateFormatter();
431	}
432
433	/**
434	 * Возвращает компонент соединения с базой
435	 * @return CDbConnection компонент соединения с базой
436	 */
437	public function getDb()
438	{
439		return $this->getComponent('db');
440	}
441
442	/**
443	 * Возвращает комопонент приложения, отвечающий за обработку ошибок
444	 * @return CErrorHandler комопонент приложения, отвечающий за обработку ошибок
445	 */
446	public function getErrorHandler()
447	{
448		return $this->getComponent('errorHandler');
449	}
450
451	/**
452	 * Возвращает компонент приложения, отвечающий за безопасность
453	 * @return CSecurityManager компонент приложения, отвечающий за безопасность
454	 */
455	public function getSecurityManager()
456	{
457		return $this->getComponent('securityManager');
458	}
459
460	/**
461	 * Возвращает компонент приложения, представляющий постоянное состояние
462	 * (state persister)
463	 * @return CStatePersister компонент приложения, представляющий постоянное
464	 * состояние (state persister)
465	 */
466	public function getStatePersister()
467	{
468		return $this->getComponent('statePersister');
469	}
470
471	/**
472	 * Возвращает  компонент приложения кэша
473	 * @return CCache компонент приложения кэша. Null, если компонент не включен
474	 */
475	public function getCache()
476	{
477		return $this->getComponent('cache');
478	}
479
480	/**
481	 * Возвращает компонент приложения, отвечающий за перевод сообщений ядра
482	 * @return CPhpMessageSource компонент приложения, отвечающий за перевод сообщений ядра
483	 */
484	public function getCoreMessages()
485	{
486		return $this->getComponent('coreMessages');
487	}
488
489	/**
490	 * Возвращает компонент приложения, отвечающий за перевод сообщений приложения
491	 * @return CMessageSource компонент приложения, отвечающий за перевод сообщений приложения
492	 */
493	public function getMessages()
494	{
495		return $this->getComponent('messages');
496	}
497
498	/**
499	 * Возвращает компонент запроса
500	 * @return CHttpRequest компонент запроса
501	 */
502	public function getRequest()
503	{
504		return $this->getComponent('request');
505	}
506
507	/**
508	 * Возвращает менеджер URL маршрутов
509	 * @return CUrlManager менеджер URL маршрутов
510	 */
511	public function getUrlManager()
512	{
513		return $this->getComponent('urlManager');
514	}
515
516	/**
517	 * @return CController текущий активный контроллер. В данном базовом классе
518	 * возвращается значение null
519	 * @since 1.1.8
520	 */
521	public function getController()
522	{
523		return null;
524	}
525
526	/**
527	 * Создает относительный URL-адрес приложения на основе информации о
528	 * переданных контроллере и действии
529	 * @param string $route URL-маршрут. Должен быть в формате
530	 * 'ControllerID/ActionID'
531	 * @param array $params дополнительные GET-параметры (имя => значение). И
532	 * имя и значение пройдут URL-кодирование
533	 * @param string $ampersand символ, разделяющий пары имя-значение в
534	 * URL-адресе
535	 * @return string созданный URL-адрес
536	 */
537	public function createUrl($route,$params=array(),$ampersand='&')
538	{
539		return $this->getUrlManager()->createUrl($route,$params,$ampersand);
540	}
541
542	/**
543	 * Создает абсолютный URL-адрес приложения на основе информации о
544	 * переданных контроллере и действии
545	 * @param string $route URL-маршрут. Должен быть в формате
546	 * 'ControllerID/ActionID'
547	 * @param array $params дополнительные GET-параметры (имя => значение). И
548	 * имя и значение пройдут URL-кодирование
549	 * @param string $schema используемый протокол (например, http, https).
550	 * Если пусто, то используется протокол текущего запроса
551	 * @param string $ampersand символ, разделяющий пары имя-значение в
552	 * URL-адресе
553	 * @return string созданный URL-адрес
554	 */
555	public function createAbsoluteUrl($route,$params=array(),$schema='',$ampersand='&')
556	{
557		$url=$this->createUrl($route,$params,$ampersand);
558		if(strpos($url,'http')===0)
559			return $url;
560		else
561			return $this->getRequest()->getHostInfo($schema).$url;
562	}
563
564	/**
565	 * Возвращает относительный URL-адрес приложения. Является оберткой для
566	 * метода {@link CHttpRequest::getBaseUrl()}
567	 * @param boolean $absolute возвращать ли абсолютный URL-адрес. По
568	 * умолчанию - false, т.е., возвращается относительный URL-адрес
569	 * @return string относительный URL-адрес приложения
570	 * @see CHttpRequest::getBaseUrl()
571	 */
572	public function getBaseUrl($absolute=false)
573	{
574		return $this->getRequest()->getBaseUrl($absolute);
575	}
576
577	/**
578	 * @return string URL-адрес домашней страницы
579	 */
580	public function getHomeUrl()
581	{
582		if($this->_homeUrl===null)
583		{
584			if($this->getUrlManager()->showScriptName)
585				return $this->getRequest()->getScriptUrl();
586			else
587				return $this->getRequest()->getBaseUrl().'/';
588		}
589		else
590			return $this->_homeUrl;
591	}
592
593	/**
594	 * @param string $value URL-адрес домашней страницы
595	 */
596	public function setHomeUrl($value)
597	{
598		$this->_homeUrl=$value;
599	}
600
601	/**
602	 * Возвращает глобальное значение.
603	 *
604	 * Глобальное значение - это постоянное для пользовательских сессий и запросов значение.
605	 * @param string $key имя возвращаемого значения
606	 * @param mixed $defaultValue значение по умолчанию. Возвращается, если именованное глобальное значение не было найдено.
607	 * @return mixed именованное глобальное значение
608	 * @see setGlobalState
609	 */
610	public function getGlobalState($key,$defaultValue=null)
611	{
612		if($this->_globalState===null)
613			$this->loadGlobalState();
614		if(isset($this->_globalState[$key]))
615			return $this->_globalState[$key];
616		else
617			return $defaultValue;
618	}
619
620	/**
621	 * Устанавливает глобальное значение.
622	 *
623	 * Глобальное значение - это постоянное для пользовательских сессий и запросов значение.
624	 * Убедитесь, что значение сериализуемо и десереализуемо.
625	 * @param string $key имя сохраняемого значения
626	 * @param mixed $value сохраняемое значение. Должно быть сериализуемо
627	 * @param mixed $defaultValue значение по умолчанию. Если именованое глобальное значение такое же как и данное, оно будет удалено из текущего хранилища
628	 * @see getGlobalState
629	 */
630	public function setGlobalState($key,$value,$defaultValue=null)
631	{
632		if($this->_globalState===null)
633			$this->loadGlobalState();
634
635		$changed=$this->_stateChanged;
636		if($value===$defaultValue)
637		{
638			if(isset($this->_globalState[$key]))
639			{
640			unset($this->_globalState[$key]);
641				$this->_stateChanged=true;
642			}
643		}
644		else if(!isset($this->_globalState[$key]) || $this->_globalState[$key]!==$value)
645		{
646			$this->_globalState[$key]=$value;
647			$this->_stateChanged=true;
648		}
649
650		if($this->_stateChanged!==$changed)
651			$this->attachEventHandler('onEndRequest',array($this,'saveGlobalState'));
652	}
653
654	/**
655	 * Очищает глобальное значение.
656	 *
657	 * Очищенное значение больше не будет доступно ни в данном запросе ни в последующих.
658	 * @param string $key имя очищаемого значения
659	 */
660	public function clearGlobalState($key)
661	{
662		$this->setGlobalState($key,true,true);
663	}
664
665	/**
666	 * Загружает данные глобального значения из постоянного хранилища.
667	 * @see getStatePersister
668	 * @throws CException вызывается, если менеджер постоянного состояния недоступен
669	 */
670	public function loadGlobalState()
671	{
672		$persister=$this->getStatePersister();
673		if(($this->_globalState=$persister->load())===null)
674			$this->_globalState=array();
675		$this->_stateChanged=false;
676		$this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
677	}
678
679	/**
680	 * Сохраняет данные глобального состояния в постоянное хранилище.
681	 * @see getStatePersister
682	 * @throws CException вызывается, если менеджер постоянного состояния недоступен
683	 */
684	public function saveGlobalState()
685	{
686		if($this->_stateChanged)
687		{
688			$this->_stateChanged=false;
689			$this->detachEventHandler('onEndRequest',array($this,'saveGlobalState'));
690			$this->getStatePersister()->save($this->_globalState);
691		}
692	}
693
694	/**
695	 * Обрабатывает неперехваченные исключения PHP.
696	 *
697	 * Метод реализован как обработчик исключений PHP. Он требует, чтобы
698	 * константа YII_ENABLE_EXCEPTION_HANDLER была установлена в значение true.
699	 *
700	 * Сначала метод вызывает событие {@link onException}.
701	 * Если исключение не обработано каким-либо другим обработчиком, для его
702	 * обработки будет вызван {@link getErrorHandler errorHandler}.
703	 *
704	 * При вызове данного метода приложение завершается.
705	 *
706	 * @param Exception $exception неперехваченное исключение
707	 */
708	public function handleException($exception)
709	{
710		// disable error capturing to avoid recursive errors
711		restore_error_handler();
712		restore_exception_handler();
713
714		$category='exception.'.get_class($exception);
715		if($exception instanceof CHttpException)
716			$category.='.'.$exception->statusCode;
717		// php <5.2 doesn't support string conversion auto-magically
718		$message=$exception->__toString();
719		if(isset($_SERVER['REQUEST_URI']))
720			$message.="\nREQUEST_URI=".$_SERVER['REQUEST_URI'];
721		if(isset($_SERVER['HTTP_REFERER']))
722			$message.="\nHTTP_REFERER=".$_SERVER['HTTP_REFERER'];
723		$message.="\n---";
724		Yii::log($message,CLogger::LEVEL_ERROR,$category);
725
726		try
727		{
728			$event=new CExceptionEvent($this,$exception);
729			$this->onException($event);
730			if(!$event->handled)
731			{
732				// try an error handler
733				if(($handler=$this->getErrorHandler())!==null)
734					$handler->handle($event);
735				else
736					$this->displayException($exception);
737			}
738		}
739		catch(Exception $e)
740		{
741			$this->displayException($e);
742		}
743
744		try
745		{
746		$this->end(1);
747	}
748		catch(Exception $e)
749		{
750			// use the most primitive way to log error
751			$msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
752			$msg .= $e->getTraceAsString()."\n";
753			$msg .= "Previous exception:\n";
754			$msg .= get_class($exception).': '.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().")\n";
755			$msg .= $exception->getTraceAsString()."\n";
756			$msg .= '$_SERVER='.var_export($_SERVER,true);
757			error_log($msg);
758			exit(1);
759		}
760	}
761
762	/**
763	 * Обрабатывает ошибки выполнения PHP такие, как предупреждения (warnings), замечания (notices).
764	 *
765	 * Метод реализован как обработчик ошибок PHP. Он требует, чтобы
766	 * константа YII_ENABLE_ERROR_HANDLER была установлена в значение true.
767	 *
768	 * Сначала метод вызывает событие {@link onError}.
769	 * Если ошибка не обработана каким-либо другим обработчиком, для ее
770	 * обработки будет вызван {@link getErrorHandler errorHandler}.
771	 *
772	 * При вызове данного метода приложение завершается.
773	 *
774	 * @param integer $code уровень ошибки
775	 * @param string $message сообщение ошибки
776	 * @param string $file файл, в котором произошла ошибка
777	 * @param string $line строка кода, в которой произошла ошибка
778	 */
779	public function handleError($code,$message,$file,$line)
780	{
781		if($code & error_reporting())
782		{
783			// disable error capturing to avoid recursive errors
784			restore_error_handler();
785			restore_exception_handler();
786
787			$log="$message ($file:$line)\nStack trace:\n";
788			$trace=debug_backtrace();
789			// skip the first 3 stacks as they do not tell the error position
790			if(count($trace)>3)
791				$trace=array_slice($trace,3);
792			foreach($trace as $i=>$t)
793			{
794				if(!isset($t['file']))
795					$t['file']='unknown';
796				if(!isset($t['line']))
797					$t['line']=0;
798				if(!isset($t['function']))
799					$t['function']='unknown';
800				$log.="#$i {$t['file']}({$t['line']}): ";
801				if(isset($t['object']) && is_object($t['object']))
802					$log.=get_class($t['object']).'->';
803				$log.="{$t['function']}()\n";
804			}
805			if(isset($_SERVER['REQUEST_URI']))
806				$log.='REQUEST_URI='.$_SERVER['REQUEST_URI'];
807			Yii::log($log,CLogger::LEVEL_ERROR,'php');
808
809			try
810			{
811				Yii::import('CErrorEvent',true);
812				$event=new CErrorEvent($this,$code,$message,$file,$line);
813				$this->onError($event);
814				if(!$event->handled)
815				{
816					// try an error handler
817					if(($handler=$this->getErrorHandler())!==null)
818						$handler->handle($event);
819					else
820						$this->displayError($code,$message,$file,$line);
821				}
822			}
823			catch(Exception $e)
824			{
825				$this->displayException($e);
826			}
827
828			try
829			{
830			$this->end(1);
831		}
832			catch(Exception $e)
833			{
834				// use the most primitive way to log error
835				$msg = get_class($e).': '.$e->getMessage().' ('.$e->getFile().':'.$e->getLine().")\n";
836				$msg .= $e->getTraceAsString()."\n";
837				$msg .= "Previous error:\n";
838				$msg .= $log."\n";
839				$msg .= '$_SERVER='.var_export($_SERVER,true);
840				error_log($msg);
841				exit(1);
842			}
843		}
844	}
845
846	/**
847	 * Выполняется при возникновении неперехваченного исключения PHP.
848	 *
849	 * Обработчик события может установить свойство {@link CErrorEvent::handled handled}
850	 * параметра события в значение true для индикации того, что дальнейшая обработка ошибок не
851	 * требуется. В ином случае, компонент приложения {@link getErrorHandler errorHandler}
852	 * будет продолжать обрабатывать ошибки.
853	 *
854	 * @param CExceptionEvent $event параметр события
855	 */
856	public function onException($event)
857	{
858		$this->raiseEvent('onException',$event);
859	}
860
861	/**
862	 * Выполняется при возникновении ошибки исполнения скрипта PHP.
863	 *
864	 * Обработчик события может установить свойство {@link CErrorEvent::handled handled}
865	 * параметра события в значение true для индикации того, что дальнейшая обработка ошибок не
866	 * требуется. В ином случае, компонент приложения {@link getErrorHandler errorHandler}
867	 * будет продолжать обрабатывать ошибки.
868	 *
869	 * @param CErrorEvent $event параметр события
870	 */
871	public function onError($event)
872	{
873		$this->raiseEvent('onError',$event);
874	}
875
876	/**
877	 * Отображает перехваченную ошибку PHP.
878	 * Метод отображает ошибку в коде HTML, если
879	 * для нее нет обработчика.
880	 * @param integer $code код ошибки
881	 * @param string $message сообщение об ошибке
882	 * @param string $file файл, в котором произошла ошибка
883	 * @param string $line строка кода, в которой произошла ошибка
884	 */
885	public function displayError($code,$message,$file,$line)
886	{
887		if(YII_DEBUG)
888		{
889			echo "<h1>PHP Error [$code]</h1>\n";
890			echo "<p>$message ($file:$line)</p>\n";
891			echo '<pre>';
892
893			$trace=debug_backtrace();
894			// skip the first 3 stacks as they do not tell the error position
895			if(count($trace)>3)
896				$trace=array_slice($trace,3);
897			foreach($trace as $i=>$t)
898			{
899				if(!isset($t['file']))
900					$t['file']='unknown';
901				if(!isset($t['line']))
902					$t['line']=0;
903				if(!isset($t['function']))
904					$t['function']='unknown';
905				echo "#$i {$t['file']}({$t['line']}): ";
906				if(isset($t['object']) && is_object($t['object']))
907					echo get_class($t['object']).'->';
908				echo "{$t['function']}()\n";
909			}
910
911			echo '</pre>';
912		}
913		else
914		{
915			echo "<h1>PHP Error [$code]</h1>\n";
916			echo "<p>$message</p>\n";
917		}
918	}
919
920	/**
921	 * Отображает неперехваченные исключения PHP.
922	 * Метод отображает исключения в HTML, когда нет активного обработчика ошибок.
923	 * @param Exception $exception неперехваченное исключение
924	 */
925	public function displayException($exception)
926	{
927		if(YII_DEBUG)
928		{
929			echo '<h1>'.get_class($exception)."</h1>\n";
930			echo '<p>'.$exception->getMessage().' ('.$exception->getFile().':'.$exception->getLine().')</p>';
931			echo '<pre>'.$exception->getTraceAsString().'</pre>';
932		}
933		else
934		{
935			echo '<h1>'.get_class($exception)."</h1>\n";
936			echo '<p>'.$exception->getMessage().'</p>';
937		}
938	}
939
940	/**
941	 * Инициализирует обработчики исключений и ошибок.
942	 */
943	protected function initSystemHandlers()
944	{
945		if(YII_ENABLE_EXCEPTION_HANDLER)
946			set_exception_handler(array($this,'handleException'));
947		if(YII_ENABLE_ERROR_HANDLER)
948			set_error_handler(array($this,'handleError'),error_reporting());
949	}
950
951	/**
952	 * Регистрирует компоненты ядра приложения.
953	 * @see setComponents
954	 */
955	protected function registerCoreComponents()
956	{
957		$components=array(
958			'coreMessages'=>array(
959				'class'=>'CPhpMessageSource',
960				'language'=>'en_us',
961				'basePath'=>YII_PATH.DIRECTORY_SEPARATOR.'messages',
962			),
963			'db'=>array(
964				'class'=>'CDbConnection',
965			),
966			'messages'=>array(
967				'class'=>'CPhpMessageSource',
968			),
969			'errorHandler'=>array(
970				'class'=>'CErrorHandler',
971			),
972			'securityManager'=>array(
973				'class'=>'CSecurityManager',
974			),
975			'statePersister'=>array(
976				'class'=>'CStatePersister',
977			),
978			'urlManager'=>array(
979				'class'=>'CUrlManager',
980			),
981			'request'=>array(
982				'class'=>'CHttpRequest',
983			),
984			'format'=>array(
985				'class'=>'CFormatter',
986			),
987		);
988
989		$this->setComponents($components);
990	}
991}