diff --git a/framework/base/Application.php b/framework/base/Application.php index dac3f10..5f4971d 100644 --- a/framework/base/Application.php +++ b/framework/base/Application.php @@ -80,6 +80,10 @@ class Application extends Module */ public $name = 'My Application'; /** + * @var string the version of this application. Defaults to '1.0'. + */ + public $version = '1.0'; + /** * @var string the charset currently used for the application. Defaults to 'UTF-8'. */ public $charset = 'UTF-8'; @@ -99,6 +103,11 @@ class Application extends Module * @var Controller the currently active controller instance */ public $controller; + /** + * @var mixed the layout that should be applied for views in this application. Defaults to 'main'. + * If this is false, layout will be disabled. + */ + public $layout = 'main'; // todo public $localeDataPath = '@yii/i18n/data'; diff --git a/framework/base/Controller.php b/framework/base/Controller.php index ab0fb95..2a45002 100644 --- a/framework/base/Controller.php +++ b/framework/base/Controller.php @@ -69,6 +69,10 @@ class Controller extends Component implements Initable * @var Action the action that is currently being executed */ public $action; + /** + * @var View the view currently being used + */ + private $_view; /** * @param string $id ID of this controller @@ -301,6 +305,12 @@ class Controller extends Component implements Initable { if ($this->beforeRender($view)) { $v = $this->createView(); + if (($theme = \Yii::$application->getTheme()) !== null) { + $v->basePath[] = $theme->getViewPath($this); + $v->rootPath[] = $theme->getViewPath(); + } + $v->basePath[] = $this->getViewPath(); + $v->rootPath[] = \Yii::$application->getViewPath(); $v->render($view, $params); $this->afterRender($view); } @@ -317,6 +327,32 @@ class Controller extends Component implements Initable } + public function resolveLayout() + { + $layout = $this->layout; + $module = $this->module; + while ($layout === null && $module !== null) { + $layout = $module->layout; + $module = $module->module; + $layout = $ + } + } + + public function getView() + { + if ($this->_view === null) { + $this->_view = $this->createView(); + $this->_view->owner = $this; + if (($theme = \Yii::$application->getTheme()) !== null) { + $this->_view->basePath[] = $theme->getViewPath($this); + $this->_view->rootPath[] = $theme->getViewPath(); + } + $this->_view->basePath[] = $this->getViewPath(); + $this->_view->rootPath[] = \Yii::$application->getViewPath(); + } + return $this->_view; + } + public function createView() { return new View; diff --git a/framework/base/ErrorHandler.php b/framework/base/ErrorHandler.php index 9400083..86f3e91 100644 --- a/framework/base/ErrorHandler.php +++ b/framework/base/ErrorHandler.php @@ -50,6 +50,11 @@ class ErrorHandler extends ApplicationComponent * @var \Exception the exception that is being handled currently */ public $exception; + /** + * @var boolean whether to log errors also using error_log(). Defaults to true. + * Note that errors captured by the error handler are always logged by [[\Yii::error()]]. + */ + public $logErrors = true; public function init() { @@ -95,6 +100,20 @@ class ErrorHandler extends ApplicationComponent // use the most primitive way to display exception thrown in the error view $this->renderAsText($e); } + + + try { + \Yii::$application->end(1); + } catch (Exception $e2) { + // use the most primitive way to log error occurred in end() + $msg = get_class($e2) . ': ' . $e2->getMessage() . ' (' . $e2->getFile() . ':' . $e2->getLine() . ")\n"; + $msg .= $e2->getTraceAsString() . "\n"; + $msg .= "Previous error:\n"; + $msg .= $e2->getTraceAsString() . "\n"; + $msg .= '$_SERVER=' . var_export($_SERVER, true); + error_log($msg); + exit(1); + } } protected function render($exception) @@ -269,6 +288,9 @@ class ErrorHandler extends ApplicationComponent $category .= '\\' . $exception->getSeverity(); } \Yii::error((string)$exception, $category); + if ($this->logErrors) { + error_log($exception); + } } public function clearOutput() diff --git a/framework/base/Module.php b/framework/base/Module.php index e76fd4a..4c0fe08 100644 --- a/framework/base/Module.php +++ b/framework/base/Module.php @@ -44,6 +44,12 @@ abstract class Module extends Component implements Initable */ public $module; /** + * @var mixed the layout that should be applied for views within this module. This refers to a view name + * relative to [[layoutPath]]. If this is not set, it means the layout value of the [[module|parent module]] + * will be taken. If this is false, layout will be disabled within this module. + */ + public $layout; + /** * @var array mapping from controller ID to controller configurations. * Each name-value pair specifies the configuration of a single controller. * A controller configuration can be either a string or an array. @@ -73,14 +79,18 @@ abstract class Module extends Component implements Initable public $defaultRoute = 'default'; /** * @var string the root directory of the module. - * @see getBasePath - * @see setBasePath */ protected $_basePath; /** + * @var string the root directory that contains view files. + */ + protected $_viewPath; + /** + * @var string the root directory that contains layout view files. + */ + protected $_layoutPath; + /** * @var string the directory containing controller classes in the module. - * @see getControllerPath - * @see setControllerPath */ protected $_controllerPath; /** @@ -221,6 +231,56 @@ abstract class Module extends Component implements Initable } /** + * @return string the root directory of view files. Defaults to 'moduleDir/views' where + * moduleDir is the directory containing the module class. + */ + public function getViewPath() + { + if ($this->_viewPath !== null) { + return $this->_viewPath; + } else { + return $this->_viewPath = $this->getBasePath() . DIRECTORY_SEPARATOR . 'views'; + } + } + + /** + * @param string $path the root directory of view files. + * @throws CException if the directory does not exist. + */ + public function setViewPath($path) + { + if (($this->_viewPath = realpath($path)) === false || !is_dir($this->_viewPath)) { + throw new CException(Yii::t('yii', 'The view path "{path}" is not a valid directory.', + array('{path}' => $path))); + } + } + + /** + * @return string the root directory of layout files. Defaults to 'moduleDir/views/layouts' where + * moduleDir is the directory containing the module class. + */ + public function getLayoutPath() + { + if ($this->_layoutPath !== null) { + return $this->_layoutPath; + } else { + return $this->_layoutPath = $this->getViewPath() . DIRECTORY_SEPARATOR . 'layouts'; + } + } + + /** + * @param string $path the root directory of layout files. + * @throws CException if the directory does not exist. + */ + public function setLayoutPath($path) + { + if (($this->_layoutPath = realpath($path)) === false || !is_dir($this->_layoutPath)) { + throw new CException(Yii::t('yii', 'The layout path "{path}" is not a valid directory.', + array('{path}' => $path))); + } + } + + /** * Imports the specified path aliases. * This method is provided so that you can import a set of path aliases when configuring a module. * The path aliases will be imported by calling [[\Yii::import()]]. diff --git a/framework/base/RenderEvent.php b/framework/base/RenderEvent.php index 114675b..60d2372 100644 --- a/framework/base/RenderEvent.php +++ b/framework/base/RenderEvent.php @@ -20,9 +20,9 @@ namespace yii\base; class RenderEvent extends Event { /** - * @var Action the action currently being executed + * @var string the view currently being rendered */ - public $action; + public $view; /** * @var boolean whether the action is in valid state and its life cycle should proceed. */ @@ -30,10 +30,10 @@ class RenderEvent extends Event /** * Constructor. - * @param Action $action the action associated with this action event. + * @param string $view the view currently being rendered */ - public function __construct(Action $action) + public function __construct($view) { - $this->action = $action; + $this->view = $view; } } diff --git a/framework/base/View.php b/framework/base/View.php index 46ef9d4..0e0f3fe 100644 --- a/framework/base/View.php +++ b/framework/base/View.php @@ -22,13 +22,22 @@ class View extends Component */ public $owner; /** - * @var string|array the base path where the view file should be looked for using the specified view name. - * This can be either a string representing a single base path, or an array representing multiple base paths. - * If the latter, the view file will be looked for in the given base paths in the order they are specified. - * Path aliases can be used. This property must be set before calling [[render()]]. + * @var string|array the directories where the view file should be looked for a *relative* view name is given. + * This can be either a string representing a single directory, or an array representing multiple directories. + * If the latter, the view file will be looked for in the given directories in the order they are specified. + * Path aliases can be used. This property must be set before calling [[render()]] with a relative view name. + * @see roothPath */ public $basePath; /** + * @var string|array the directories where the view file should be looked for an *absolute* view name is given. + * This can be either a string representing a single directory, or an array representing multiple directories. + * If the latter, the view file will be looked for in the given directories in the order they are specified. + * Path aliases can be used. This property must be set before calling [[render()]] with an absolute view name. + * @see basePath + */ + public $rootPath; + /** * @var string the language that the view should be rendered in. If not set, it will use * the value of [[Application::language]]. */ @@ -255,12 +264,25 @@ class View extends Component } if ($view[0] === '@') { $file = \Yii::getAlias($view); - } elseif (!empty($this->basePath)) { - $basePaths = is_array($this->basePath) ? $this->basePath : array($this->basePath); - foreach ($basePaths as $basePath) { - $file = \Yii::getAlias($basePath . DIRECTORY_SEPARATOR . $view); - if (is_file($file)) { - break; + if ($file === false) { + return false; + } + } else { + if ($view[0] === '/') { + $paths = $this->rootPath; + $view = substr($view, 1); + } else { + $paths = $this->basePath; + } + if (!empty($paths)) { + if (!is_array($paths)) { + $paths = array($paths); + } + foreach ($paths as $path) { + $file = \Yii::getAlias($path . '/' . $view); + if (is_file($file)) { + break; + } } } }