Commit 1d48d01e by Qiang Xue

refactored View.

parent 9a4f4f85
......@@ -4,9 +4,9 @@
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
use yii\base\Exception;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\logging\Logger;
/**
......@@ -159,9 +159,7 @@ class YiiBase
return self::$_imported[$alias] = $className;
}
if (($path = static::getAlias(dirname($alias))) === false) {
throw new Exception('Invalid path alias: ' . $alias);
}
$path = static::getAlias(dirname($alias));
if ($isClass) {
if ($forceInclude) {
......@@ -191,25 +189,31 @@ class YiiBase
*
* Note, this method does not ensure the existence of the resulting path.
* @param string $alias alias
* @param boolean $throwException whether to throw an exception if the given alias is invalid.
* If this is false and an invalid alias is given, false will be returned by this method.
* @return string|boolean path corresponding to the alias, false if the root alias is not previously registered.
* @see setAlias
*/
public static function getAlias($alias)
public static function getAlias($alias, $throwException = true)
{
if (!is_string($alias)) {
return false;
} elseif (isset(self::$aliases[$alias])) {
if (is_string($alias)) {
if (isset(self::$aliases[$alias])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($pos = strpos($alias, '/')) !== false) {
} elseif (($pos = strpos($alias, '/')) !== false || ($pos = strpos($alias, '\\')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
}
}
}
if ($throwException) {
throw new InvalidParamException("Invalid path alias: $alias");
} else {
return false;
}
}
/**
* Registers a path alias.
......@@ -236,10 +240,8 @@ class YiiBase
unset(self::$aliases[$alias]);
} elseif ($path[0] !== '@') {
self::$aliases[$alias] = rtrim($path, '\\/');
} elseif (($p = static::getAlias($path)) !== false) {
self::$aliases[$alias] = $p;
} else {
throw new Exception('Invalid path: ' . $path);
self::$aliases[$alias] = static::getAlias($path);
}
}
......@@ -273,14 +275,14 @@ class YiiBase
// namespaced class, e.g. yii\base\Component
// convert namespace to path alias, e.g. yii\base\Component to @yii/base/Component
$alias = '@' . str_replace('\\', '/', ltrim($className, '\\'));
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
} elseif (($pos = strpos($className, '_')) !== false) {
// PEAR-styled class, e.g. PHPUnit_Framework_TestCase
// convert class name to path alias, e.g. PHPUnit_Framework_TestCase to @PHPUnit/Framework/TestCase
$alias = '@' . str_replace('_', '/', $className);
if (($path = static::getAlias($alias)) !== false) {
if (($path = static::getAlias($alias, false)) !== false) {
$classFile = $path . '.php';
}
}
......
......@@ -160,28 +160,28 @@ class Application extends Module
*/
public function handleFatalError()
{
if(YII_ENABLE_ERROR_HANDLER) {
if (YII_ENABLE_ERROR_HANDLER) {
$error = error_get_last();
if(ErrorException::isFatalErorr($error)) {
if (ErrorException::isFatalErorr($error)) {
unset($this->_memoryReserve);
$exception = new ErrorException($error['message'], $error['type'], $error['type'], $error['file'], $error['line']);
if(function_exists('xdebug_get_function_stack')) {
if (function_exists('xdebug_get_function_stack')) {
$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4, -1);
foreach($trace as &$frame) {
if(!isset($frame['function'])) {
foreach ($trace as &$frame) {
if (!isset($frame['function'])) {
$frame['function'] = 'unknown';
}
// XDebug < 2.1.1: http://bugs.xdebug.org/view.php?id=695
if(!isset($frame['type'])) {
if (!isset($frame['type'])) {
$frame['type'] = '::';
}
// XDebug has a different key name
$frame['args'] = array();
if(isset($frame['params']) && !isset($frame['args'])) {
if (isset($frame['params']) && !isset($frame['args'])) {
$frame['args'] = $frame['params'];
}
}
......@@ -214,8 +214,8 @@ class Application extends Module
$this->beforeRequest();
// Allocating twice more than required to display memory exhausted error
// in case of trying to allocate last 1 byte while all memory is taken.
$this->_memoryReserve = str_repeat('x', 1024*256);
register_shutdown_function(array($this,'end'),0,false);
$this->_memoryReserve = str_repeat('x', 1024 * 256);
register_shutdown_function(array($this, 'end'), 0, false);
$status = $this->processRequest();
$this->afterRequest();
return $status;
......@@ -346,15 +346,6 @@ class Application extends Module
}
/**
* Returns the application theme.
* @return Theme the theme that this application is currently using.
*/
public function getTheme()
{
return $this->getComponent('theme');
}
/**
* Returns the cache component.
* @return \yii\caching\Cache the cache application component. Null if the component is not enabled.
*/
......@@ -373,12 +364,12 @@ class Application extends Module
}
/**
* Returns the view renderer.
* @return ViewRenderer the view renderer used by this application.
* Returns the view object.
* @return View the view object that is used to render various view files.
*/
public function getViewRenderer()
public function getView()
{
return $this->getComponent('viewRenderer');
return $this->getComponent('view');
}
/**
......@@ -423,6 +414,9 @@ class Application extends Module
'urlManager' => array(
'class' => 'yii\web\UrlManager',
),
'view' => array(
'class' => 'yii\base\View',
),
));
}
......@@ -446,8 +440,8 @@ class Application extends Module
// in case error appeared in __toString method we can't throw any exception
$trace = debug_backtrace(false);
array_shift($trace);
foreach($trace as $frame) {
if($frame['function'] == '__toString') {
foreach ($trace as $frame) {
if ($frame['function'] == '__toString') {
$this->handleException($exception);
}
}
......@@ -481,7 +475,7 @@ class Application extends Module
$this->end(1);
} catch(\Exception $e) {
} catch (\Exception $e) {
// exception could be thrown in end() or ErrorHandler::handle()
$msg = (string)$e;
$msg .= "\nPrevious exception:\n";
......
......@@ -8,6 +8,7 @@
namespace yii\base;
use Yii;
use yii\util\FileHelper;
use yii\util\StringHelper;
/**
......@@ -295,34 +296,42 @@ class Controller extends Component
/**
* Renders a view and applies layout if available.
*
* @param $view
* @param array $params
* @return string
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* These parameters will not be available in the layout.
* @return string the rendering result.
* @throws InvalidParamException if the view file or the layout file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->render($view, $params);
}
public function renderContent($content)
{
return $this->createView()->renderContent($content);
$viewFile = $this->findViewFile($view);
$layoutFile = $this->findLayoutFile();
return Yii::$app->getView()->render($this, $viewFile, $params, $layoutFile);
}
/**
* Renders a view.
* This method differs from [[render()]] in that it does not apply any layout.
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderPartial($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
return $this->renderFile($this->findViewFile($view), $params);
}
/**
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function renderFile($file, $params = array())
{
return $this->createView()->renderFile($file, $params);
}
public function createView()
{
return new View($this);
return Yii::$app->getView()->render($this, $file, $params);
}
/**
......@@ -335,4 +344,105 @@ class Controller extends Component
{
return $this->module->getViewPath() . DIRECTORY_SEPARATOR . $this->id;
}
/**
* Finds the view file based on the given view name.
*
* A view name can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
* The actual view file will be looked for under the [[Module::viewPath|view path]] of the currently
* active module.
* - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]].
*
* If the view name does not contain a file extension, it will use the default one `.php`.
*
* @param string $view the view name or the path alias of the view file.
* @return string the view file path. Note that the file may not exist.
* @throws InvalidParamException if the view file is an invalid path alias
*/
protected function findViewFile($view)
{
if (strncmp($view, '@', 1) === 0) {
// e.g. "@app/views/common"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '/', 1) !== 0) {
// e.g. "index"
$file = $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
} elseif (strncmp($view, '//', 2) !== 0) {
// e.g. "/site/index"
$file = $this->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
}
if (FileHelper::getExtension($file) === '') {
$file .= '.php';
}
return $file;
}
/**
* Finds the applicable layout file.
*
* This method locates an applicable layout file via two steps.
*
* In the first step, it determines the layout name and the context module:
*
* - If [[layout]] is specified as a string, use it as the layout name and [[module]] as the context module;
* - If [[layout]] is null, search through all ancestor modules of this controller and find the first
* module whose [[Module::layout|layout]] is not null. The layout and the corresponding module
* are used as the layout name and the context module, respectively. If such a module is not found
* or the corresponding layout is not a string, it will return false, meaning no applicable layout.
*
* In the second step, it determines the actual layout file according to the previously found layout name
* and context module. The layout name can be
*
* - a path alias (e.g. "@app/views/layouts/main");
* - an absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
* looked for under the [[Application::layoutPath|layout path]] of the application;
* - a relative path (e.g. "main"): the actual layout layout file will be looked for under the
* [[Module::viewPath|view path]] of the context module.
*
* If the layout name does not contain a file extension, it will use the default one `.php`.
*
* @return string|boolean the layout file path, or false if layout is not needed.
* @throws InvalidParamException if an invalid path alias is used to specify the layout
*/
protected function findLayoutFile()
{
/** @var $module Module */
if (is_string($this->layout)) {
$module = $this->module;
$view = $this->layout;
} elseif ($this->layout === null) {
$module = $this->module;
while ($module !== null && $module->layout === null) {
$module = $module->module;
}
if ($module !== null && is_string($module->layout)) {
$view = $module->layout;
}
}
if (!isset($view)) {
return false;
}
if (strncmp($view, '@', 1) === 0) {
$file = Yii::getAlias($view);
} elseif (strncmp($view, '/', 1) === 0) {
$file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
} else {
$file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
}
if (FileHelper::getExtension($file) === '') {
$file .= '.php';
}
return $file;
}
}
......@@ -253,14 +253,9 @@ class ErrorHandler extends Component
*/
public function renderAsHtml($exception)
{
$view = new View($this);
if (!YII_DEBUG || $exception instanceof UserException) {
$viewName = $this->errorView;
} else {
$viewName = $this->exceptionView;
}
$view = new View;
$name = !YII_DEBUG || $exception instanceof HttpException ? $this->errorView : $this->exceptionView;
echo $view->render($name, array(
echo $view->render($this, $name, array(
'exception' => $exception,
));
}
......
......@@ -40,7 +40,8 @@ class Theme extends Component
/**
* @var array the mapping between view directories and their corresponding themed versions.
* If not set, it will be initialized as a mapping from [[Application::basePath]] to [[basePath]].
* This property is used by [[apply()]] when a view is trying to apply the theme.
* This property is used by [[applyTo()]] when a view is trying to apply the theme.
* Path aliases can be used when specifying directories.
*/
public $pathMap;
......@@ -63,7 +64,9 @@ class Theme extends Component
}
$paths = array();
foreach ($this->pathMap as $from => $to) {
$paths[FileHelper::normalizePath($from) . DIRECTORY_SEPARATOR] = FileHelper::normalizePath($to) . DIRECTORY_SEPARATOR;
$from = FileHelper::normalizePath(Yii::getAlias($from));
$to = FileHelper::normalizePath(Yii::getAlias($to));
$paths[$from . DIRECTORY_SEPARATOR] = $to . DIRECTORY_SEPARATOR;
}
$this->pathMap = $paths;
}
......@@ -93,7 +96,7 @@ class Theme extends Component
* @param string $path the file to be themed
* @return string the themed file, or the original file if the themed version is not available.
*/
public function apply($path)
public function applyTo($path)
{
$path = FileHelper::normalizePath($path);
foreach ($this->pathMap as $from => $to) {
......
......@@ -8,8 +8,8 @@
namespace yii\base;
use Yii;
use yii\util\FileHelper;
use yii\base\Application;
use yii\util\FileHelper;
/**
* View represents a view object in the MVC pattern.
......@@ -24,133 +24,112 @@ class View extends Component
/**
* @var object the object that owns this view. This can be a controller, a widget, or any other object.
*/
public $owner;
/**
* @var string the layout to be applied when [[render()]] or [[renderContent()]] is called.
* If not set, it will use the [[Module::layout]] of the currently active module.
*/
public $layout;
/**
* @var string the language that the view should be rendered in. If not set, it will use
* the value of [[Application::language]].
*/
public $language;
public $context;
/**
* @var string the language that the original view is in. If not set, it will use
* the value of [[Application::sourceLanguage]].
* @var mixed custom parameters that are shared among view templates.
*/
public $sourceLanguage;
/**
* @var boolean whether to localize the view when possible. Defaults to true.
* Note that when this is true, if a localized view cannot be found, the original view will be rendered.
* No error will be reported.
*/
public $enableI18N = true;
public $params;
/**
* @var boolean whether to theme the view when possible. Defaults to true.
* Note that theming will be disabled if [[Application::theme]] is not set.
* @var ViewRenderer|array the view renderer object or the configuration array for
* creating the view renderer. If not set, view files will be treated as normal PHP files.
*/
public $enableTheme = true;
public $renderer;
/**
* @var mixed custom parameters that are available in the view template
* @var Theme|array the theme object or the configuration array for creating the theme.
* If not set, it means theming is not enabled.
*/
public $params;
public $theme;
/**
* @var Widget[] the widgets that are currently not ended
*/
private $_widgetStack = array();
/**
* Constructor.
* @param object $owner the owner of this view. This usually is a controller or a widget.
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($owner, $config = array())
{
$this->owner = $owner;
parent::__construct($config);
}
/**
* Renders a view within a layout.
* This method is similar to [[renderPartial()]] except that if a layout is available,
* this method will embed the view result into the layout and then return it.
* @param string $view the view to be rendered. Please refer to [[findViewFile()]] on possible formats of the view name.
* @param array $params the parameters that should be made available in the view. The PHP function `extract()`
* will be called on this variable to extract the variables from this parameter.
* @return string the rendering result
* @throws InvalidConfigException if the view file or layout file cannot be found
* @see findViewFile()
* @see findLayoutFile()
* Initializes the view component.
*/
public function render($view, $params = array())
public function init()
{
$content = $this->renderPartial($view, $params);
return $this->renderContent($content);
parent::init();
if (is_array($this->renderer)) {
$this->renderer = Yii::createObject($this->renderer);
}
/**
* Renders a text content within a layout.
* The layout being used is resolved by [[findLayout()]].
* If no layout is available, the content will be returned back.
* @param string $content the content to be rendered
* @return string the rendering result
* @throws InvalidConfigException if the layout file cannot be found
* @see findLayoutFile()
*/
public function renderContent($content)
{
$layoutFile = $this->findLayoutFile();
if ($layoutFile !== false) {
return $this->renderFile($layoutFile, array('content' => $content));
} else {
return $content;
if (is_array($this->theme)) {
$this->theme = Yii::createObject($this->theme);
}
}
/**
* Renders a view.
* Renders a view file under a context with an optional layout.
*
* The method first finds the actual view file corresponding to the specified view.
* It then calls [[renderFile()]] to render the view file. The rendering result is returned
* as a string. If the view file does not exist, an exception will be thrown.
* This method is similar to [[renderFile()]] except that it will update [[context]]
* with the provided $context parameter. It will also apply layout to the rendering result
* of the view file if $layoutFile is given.
*
* @param string $view the view to be rendered. Please refer to [[findViewFile()]] on possible formats of the view name.
* @param array $params the parameters that should be made available in the view. The PHP function `extract()`
* will be called on this variable to extract the variables from this parameter.
* Theming and localization will be performed for the view file and the layout file, if possible.
*
* @param object $context the context object for rendering the file. This could be a controller, a widget,
* or any other object that serves as the rendering context of the view file. In the view file,
* it can be accessed through the [[context]] property.
* @param string $viewFile the view file. This can be a file path or a path alias.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param string|boolean $layoutFile the layout file. This can be a file path or a path alias.
* If it is false, it means no layout should be applied.
* @return string the rendering result
* @throws InvalidParamException if the view file cannot be found
* @see findViewFile()
* @throws InvalidParamException if the view file or the layout file does not exist.
*/
public function renderPartial($view, $params = array())
public function render($context, $viewFile, $params = array(), $layoutFile = false)
{
$file = $this->findViewFile($view);
if ($file !== false) {
return $this->renderFile($file, $params);
} else {
throw new InvalidParamException("Unable to find the view file for view '$view'.");
$oldContext = $this->context;
$this->context = $context;
$content = $this->renderFile($viewFile, $params);
if ($layoutFile !== false) {
$content = $this->renderFile($layoutFile, array('content' => $content));
}
$this->context = $oldContext;
return $content;
}
/**
* Renders a view file.
*
* If a [[ViewRenderer|view renderer]] is installed, this method will try to use the view renderer
* to render the view file. Otherwise, it will simply include the view file, capture its output
* and return it as a string.
* This method renders the specified view file under the existing [[context]].
*
* If [[theme]] is enabled (not null), it will try to render the themed version of the view file as long
* as it is available.
*
* The method will call [[FileHelper::localize()]] to localize the view file.
*
* @param string $file the view file.
* If [[renderer]] is enabled (not null), the method will use it to render the view file.
* Otherwise, it will simply include the view file as a normal PHP file, capture its output and
* return it as a string.
*
* @param string $viewFile the view file. This can be a file path or a path alias.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @return string the rendering result
* @throws InvalidParamException if the view file does not exist
*/
public function renderFile($file, $params = array())
public function renderFile($viewFile, $params = array())
{
$renderer = Yii::$app->getViewRenderer();
if ($renderer !== null) {
return $renderer->render($this, $file, $params);
$viewFile = Yii::getAlias($viewFile);
if (is_file($viewFile)) {
if ($this->theme !== null) {
$viewFile = $this->theme->applyTo($viewFile);
}
$viewFile = FileHelper::localize($viewFile);
} else {
throw new InvalidParamException("The view file does not exist: $viewFile");
}
if ($this->renderer !== null) {
return $this->renderer->render($this, $viewFile, $params);
} else {
return $this->renderPhpFile($file, $params);
return $this->renderPhpFile($viewFile, $params);
}
}
......@@ -161,6 +140,8 @@ class View extends Component
* It extracts the given parameters and makes them available in the view file.
* The method captures the output of the included view file and returns it as a string.
*
* This method should mainly be called by view renderer or [[renderFile()]].
*
* @param string $_file_ the view file.
* @param array $_params_ the parameters (name-value pairs) that will be extracted and made available in the view file.
* @return string the rendering result
......@@ -184,7 +165,7 @@ class View extends Component
public function createWidget($class, $properties = array())
{
$properties['class'] = $class;
return Yii::createObject($properties, $this->owner);
return Yii::createObject($properties, $this->context);
}
/**
......@@ -233,7 +214,7 @@ class View extends Component
* If you want to capture the rendering result of a widget, you may use
* [[createWidget()]] and [[Widget::run()]].
* @return Widget the widget instance
* @throws Exception if [[beginWidget()]] and [[endWidget()]] calls are not properly nested
* @throws InvalidCallException if [[beginWidget()]] and [[endWidget()]] calls are not properly nested
*/
public function endWidget()
{
......@@ -242,251 +223,99 @@ class View extends Component
$widget->run();
return $widget;
} else {
throw new Exception("Unmatched beginWidget() and endWidget() calls.");
}
}
//
// /**
// * Begins recording a clip.
// * This method is a shortcut to beginning [[yii\widgets\Clip]]
// * @param string $id the clip ID.
// * @param array $properties initial property values for [[yii\widgets\Clip]]
// */
// public function beginClip($id, $properties = array())
// {
// $properties['id'] = $id;
// $this->beginWidget('yii\widgets\Clip', $properties);
// }
//
// /**
// * Ends recording a clip.
// */
// public function endClip()
// {
// $this->endWidget();
// }
//
// /**
// * Begins fragment caching.
// * This method will display cached content if it is available.
// * If not, it will start caching and would expect an [[endCache()]]
// * call to end the cache and save the content into cache.
// * A typical usage of fragment caching is as follows,
// *
// * ~~~
// * if($this->beginCache($id)) {
// * // ...generate content here
// * $this->endCache();
// * }
// * ~~~
// *
// * @param string $id a unique ID identifying the fragment to be cached.
// * @param array $properties initial property values for [[yii\widgets\OutputCache]]
// * @return boolean whether we need to generate content for caching. False if cached version is available.
// * @see endCache
// */
// public function beginCache($id, $properties = array())
// {
// $properties['id'] = $id;
// $cache = $this->beginWidget('yii\widgets\OutputCache', $properties);
// if ($cache->getIsContentCached()) {
// $this->endCache();
// return false;
// } else {
// return true;
// }
// }
//
// /**
// * Ends fragment caching.
// * This is an alias to [[endWidget()]]
// * @see beginCache
// */
// public function endCache()
// {
// $this->endWidget();
// }
//
// /**
// * Begins the rendering of content that is to be decorated by the specified view.
// * @param mixed $view the name of the view that will be used to decorate the content. The actual view script
// * is resolved via {@link getViewFile}. If this parameter is null (default),
// * the default layout will be used as the decorative view.
// * Note that if the current controller does not belong to
// * any module, the default layout refers to the application's {@link CWebApplication::layout default layout};
// * If the controller belongs to a module, the default layout refers to the module's
// * {@link CWebModule::layout default layout}.
// * @param array $params the variables (name=>value) to be extracted and made available in the decorative view.
// * @see endContent
// * @see yii\widgets\ContentDecorator
// */
// public function beginContent($view, $params = array())
// {
// $this->beginWidget('yii\widgets\ContentDecorator', array(
// 'view' => $view,
// 'params' => $params,
// ));
// }
//
// /**
// * Ends the rendering of content.
// * @see beginContent
// */
// public function endContent()
// {
// $this->endWidget();
// }
/**
* Finds the view file based on the given view name.
*
* A view name can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
* The actual view file will be looked for under the [[Module::viewPath|view path]] of the currently
* active module.
* - relative path (e.g. "index"): the actual view file will be looked for under the [[owner]]'s view path.
* If [[owner]] is a widget or a controller, its view path is given by their `viewPath` property.
* If [[owner]] is an object of any other type, its view path is the `view` sub-directory of the directory
* containing the owner class file.
*
* If the view name does not contain a file extension, it will default to `.php`.
*
* If [[enableTheme]] is true and there is an active application them, the method will also
* attempt to use a themed version of the view file, when available.
*
* And if [[enableI18N]] is true, the method will attempt to use a translated version of the view file,
* when available.
*
* @param string $view the view name or path alias. If the view name does not specify
* the view file extension name, it will use `.php` as the extension name.
* @return string the view file path if it exists. False if the view file cannot be found.
* @throws InvalidConfigException if the view file does not exist
*/
public function findViewFile($view)
{
if (FileHelper::getExtension($view) === '') {
$view .= '.php';
}
if (strncmp($view, '@', 1) === 0) {
// e.g. "@app/views/common"
if (($file = Yii::getAlias($view)) === false) {
throw new InvalidConfigException("Invalid path alias: $view");
}
} elseif (strncmp($view, '/', 1) !== 0) {
// e.g. "index"
if ($this->owner instanceof Controller || $this->owner instanceof Widget) {
$file = $this->owner->getViewPath() . DIRECTORY_SEPARATOR . $view;
} elseif ($this->owner !== null) {
$class = new \ReflectionClass($this->owner);
$file = dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . $view;
} else {
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . $view;
throw new InvalidCallException("Unmatched beginWidget() and endWidget() calls.");
}
} elseif (strncmp($view, '//', 2) !== 0 && Yii::$app->controller !== null) {
// e.g. "/site/index"
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
}
if (is_file($file)) {
if ($this->enableTheme && ($theme = Yii::$app->getTheme()) !== null) {
$file = $theme->apply($file);
}
return $this->enableI18N ? FileHelper::localize($file, $this->language, $this->sourceLanguage) : $file;
} else {
throw new InvalidConfigException("View file for view '$view' does not exist: $file");
}
}
/**
* Finds the layout file that can be applied to the view.
*
* The applicable layout is resolved according to the following rules:
*
* - If [[layout]] is specified as a string, use it as the layout name and search for the layout file
* under the layout path of the currently active module;
* - If [[layout]] is null and [[owner]] is a controller:
* * If the controller's [[Controller::layout|layout]] is a string, use it as the layout name
* and search for the layout file under the layout path of the parent module of the controller;
* * If the controller's [[Controller::layout|layout]] is null, look through its ancestor modules
* and find the first one whose [[Module::layout|layout]] is not null. Use the layout specified
* by that module;
* - Returns false for all other cases.
*
* Like view names, a layout name can take several formats:
*
* - path alias (e.g. "@app/views/layouts/main");
* - absolute path (e.g. "/main"): the layout name starts with a slash. The actual layout file will be
* looked for under the [[Application::layoutPath|layout path]] of the application;
* - relative path (e.g. "main"): the actual layout layout file will be looked for under the
* [[Module::viewPath|view path]] of the context module determined by the above layout resolution process.
*
* If the layout name does not contain a file extension, it will default to `.php`.
*
* If [[enableTheme]] is true and there is an active application them, the method will also
* attempt to use a themed version of the layout file, when available.
*
* And if [[enableI18N]] is true, the method will attempt to use a translated version of the layout file,
* when available.
*
* @return string|boolean the layout file path, or false if layout is not needed.
* @throws InvalidConfigException if the layout file cannot be found
*/
public function findLayoutFile()
{
/** @var $module Module */
if (is_string($this->layout)) {
if (Yii::$app->controller) {
$module = Yii::$app->controller->module;
} else {
$module = Yii::$app;
}
$view = $this->layout;
} elseif ($this->owner instanceof Controller) {
if (is_string($this->owner->layout)) {
$module = $this->owner->module;
$view = $this->owner->layout;
} elseif ($this->owner->layout === null) {
$module = $this->owner->module;
while ($module !== null && $module->layout === null) {
$module = $module->module;
}
if ($module !== null && is_string($module->layout)) {
$view = $module->layout;
}
}
}
if (!isset($view)) {
return false;
}
if (FileHelper::getExtension($view) === '') {
$view .= '.php';
}
if (strncmp($view, '@', 1) === 0) {
if (($file = Yii::getAlias($view)) === false) {
throw new InvalidConfigException("Invalid path alias: $view");
}
} elseif (strncmp($view, '/', 1) === 0) {
$file = Yii::$app->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
} else {
$file = $module->getLayoutPath() . DIRECTORY_SEPARATOR . $view;
}
if (is_file($file)) {
if ($this->enableTheme && ($theme = Yii::$app->getTheme()) !== null) {
$file = $theme->apply($file);
}
return $this->enableI18N ? FileHelper::localize($file, $this->language, $this->sourceLanguage) : $file;
} else {
throw new InvalidConfigException("Layout file for layout '$view' does not exist: $file");
}
}
//
// /**
// * Begins recording a clip.
// * This method is a shortcut to beginning [[yii\widgets\Clip]]
// * @param string $id the clip ID.
// * @param array $properties initial property values for [[yii\widgets\Clip]]
// */
// public function beginClip($id, $properties = array())
// {
// $properties['id'] = $id;
// $this->beginWidget('yii\widgets\Clip', $properties);
// }
//
// /**
// * Ends recording a clip.
// */
// public function endClip()
// {
// $this->endWidget();
// }
//
// /**
// * Begins fragment caching.
// * This method will display cached content if it is available.
// * If not, it will start caching and would expect an [[endCache()]]
// * call to end the cache and save the content into cache.
// * A typical usage of fragment caching is as follows,
// *
// * ~~~
// * if($this->beginCache($id)) {
// * // ...generate content here
// * $this->endCache();
// * }
// * ~~~
// *
// * @param string $id a unique ID identifying the fragment to be cached.
// * @param array $properties initial property values for [[yii\widgets\OutputCache]]
// * @return boolean whether we need to generate content for caching. False if cached version is available.
// * @see endCache
// */
// public function beginCache($id, $properties = array())
// {
// $properties['id'] = $id;
// $cache = $this->beginWidget('yii\widgets\OutputCache', $properties);
// if ($cache->getIsContentCached()) {
// $this->endCache();
// return false;
// } else {
// return true;
// }
// }
//
// /**
// * Ends fragment caching.
// * This is an alias to [[endWidget()]]
// * @see beginCache
// */
// public function endCache()
// {
// $this->endWidget();
// }
//
// /**
// * Begins the rendering of content that is to be decorated by the specified view.
// * @param mixed $view the name of the view that will be used to decorate the content. The actual view script
// * is resolved via {@link getViewFile}. If this parameter is null (default),
// * the default layout will be used as the decorative view.
// * Note that if the current controller does not belong to
// * any module, the default layout refers to the application's {@link CWebApplication::layout default layout};
// * If the controller belongs to a module, the default layout refers to the module's
// * {@link CWebModule::layout default layout}.
// * @param array $params the variables (name=>value) to be extracted and made available in the decorative view.
// * @see endContent
// * @see yii\widgets\ContentDecorator
// */
// public function beginContent($view, $params = array())
// {
// $this->beginWidget('yii\widgets\ContentDecorator', array(
// 'view' => $view,
// 'params' => $params,
// ));
// }
//
// /**
// * Ends the rendering of content.
// * @see beginContent
// */
// public function endContent()
// {
// $this->endWidget();
// }
}
\ No newline at end of file
......@@ -7,6 +7,9 @@
namespace yii\base;
use Yii;
use yii\util\FileHelper;
/**
* Widget is the base class for widgets.
*
......@@ -70,35 +73,27 @@ class Widget extends Component
/**
* Renders a view.
*
* The method first finds the actual view file corresponding to the specified view.
* It then calls [[renderFile()]] to render the view file. The rendering result is returned
* as a string. If the view file does not exist, an exception will be thrown.
*
* To determine which view file should be rendered, the method calls [[findViewFile()]] which
* will search in the directories as specified by [[basePath]].
*
* View name can be a path alias representing an absolute file path (e.g. `@app/views/layout/index`),
* or a path relative to [[basePath]]. The file suffix is optional and defaults to `.php` if not given
* in the view name.
*
* @param string $view the view to be rendered. This can be either a path alias or a path relative to [[basePath]].
* @param array $params the parameters that should be made available in the view. The PHP function `extract()`
* will be called on this variable to extract the variables from this parameter.
* @return string the rendering result
* @throws Exception if the view file cannot be found
* @param string $view the view name. Please refer to [[findViewFile()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function render($view, $params = array())
{
return $this->createView()->renderPartial($view, $params);
$file = $this->findViewFile($view);
return Yii::$app->getView()->render($this, $file, $params);
}
/**
* @return View
* Renders a view file.
* @param string $file the view file to be rendered. This can be either a file path or a path alias.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
* @throws InvalidParamException if the view file does not exist.
*/
public function createView()
public function renderFile($file, $params = array())
{
return new View($this);
return Yii::$app->getView()->render($this, $file, $params);
}
/**
......@@ -112,4 +107,44 @@ class Widget extends Component
$class = new \ReflectionClass($className);
return dirname($class->getFileName()) . DIRECTORY_SEPARATOR . 'views';
}
/**
* Finds the view file based on the given view name.
*
* The view name can be specified in one of the following formats:
*
* - path alias (e.g. "@app/views/site/index");
* - absolute path within application (e.g. "//site/index"): the view name starts with double slashes.
* The actual view file will be looked for under the [[Application::viewPath|view path]] of the application.
* - absolute path within module (e.g. "/site/index"): the view name starts with a single slash.
* The actual view file will be looked for under the [[Module::viewPath|view path]] of the currently
* active module.
* - relative path (e.g. "index"): the actual view file will be looked for under [[viewPath]].
*
* If the view name does not contain a file extension, it will use the default one `.php`.
*
* @param string $view the view name or the path alias of the view file.
* @return string the view file path. Note that the file may not exist.
* @throws InvalidParamException if the view file is an invalid path alias
*/
public function findViewFile($view)
{
if (strncmp($view, '@', 1) === 0) {
// e.g. "@app/views/common"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '/', 1) !== 0) {
// e.g. "index"
$file = $this->getViewPath() . DIRECTORY_SEPARATOR . $view;
} elseif (strncmp($view, '//', 2) !== 0 && Yii::$app->controller !== null) {
// e.g. "/site/index"
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} else {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
}
if (FileHelper::getExtension($file) === '') {
$file .= '.php';
}
return $file;
}
}
\ No newline at end of file
......@@ -52,9 +52,6 @@ class FileCache extends Cache
{
parent::init();
$this->cachePath = \Yii::getAlias($this->cachePath);
if ($this->cachePath === false) {
throw new InvalidConfigException('FileCache.cachePath must be a valid path alias.');
}
if (!is_dir($this->cachePath)) {
mkdir($this->cachePath, 0777, true);
}
......
......@@ -114,7 +114,7 @@ class MigrateController extends Controller
{
if (parent::beforeAction($action)) {
$path = Yii::getAlias($this->migrationPath);
if ($path === false || !is_dir($path)) {
if (!is_dir($path)) {
throw new Exception("The migration directory \"{$this->migrationPath}\" does not exist.");
}
$this->migrationPath = $path;
......
......@@ -43,7 +43,7 @@ class FileHelper
public static function ensureDirectory($path)
{
$p = \Yii::getAlias($path);
if ($p !== false && ($p = realpath($p)) !== false && is_dir($p)) {
if (($p = realpath($p)) !== false && is_dir($p)) {
return $p;
} else {
throw new InvalidConfigException('Directory does not exist: ' . $path);
......
<?php
/**
* @var \Exception $exception
* @var \yii\base\ErrorHandler $owner
* @var \yii\base\ErrorHandler $context
*/
$owner = $this->owner;
$title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName() : get_class($exception));
$context = $this->context;
$title = $context->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName() : get_class($exception));
?>
<!DOCTYPE html>
<html>
......@@ -52,7 +52,7 @@ $title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $except
<body>
<h1><?php echo $title?></h1>
<h2><?php echo nl2br($owner->htmlEncode($exception->getMessage()))?></h2>
<h2><?php echo nl2br($context->htmlEncode($exception->getMessage()))?></h2>
<p>
The above error occurred while the Web server was processing your request.
</p>
......@@ -61,7 +61,7 @@ $title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $except
</p>
<div class="version">
<?php echo date('Y-m-d H:i:s', time())?>
<?php echo YII_DEBUG ? $owner->versionInfo : ''?>
<?php echo YII_DEBUG ? $context->versionInfo : ''?>
</div>
</body>
</html>
\ No newline at end of file
<?php
/**
* @var \Exception $exception
* @var \yii\base\ErrorHandler $owner
* @var \yii\base\ErrorHandler $context
*/
$owner = $this->owner;
$title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName().' ('.get_class($exception).')' : get_class($exception));
$context = $this->context;
$title = $context->htmlEncode($exception instanceof \yii\base\Exception || $exception instanceof \yii\base\ErrorException ? $exception->getName().' ('.get_class($exception).')' : get_class($exception));
?>
<!DOCTYPE html>
<html>
......@@ -164,26 +164,26 @@ $title = $owner->htmlEncode($exception instanceof \yii\base\Exception || $except
<h1><?php echo $title?></h1>
<p class="message">
<?php echo nl2br($owner->htmlEncode($exception->getMessage()))?>
<?php echo nl2br($context->htmlEncode($exception->getMessage()))?>
</p>
<div class="source">
<p class="file">
<?php echo $owner->htmlEncode($exception->getFile()) . '(' . $exception->getLine() . ')'?>
<?php echo $context->htmlEncode($exception->getFile()) . '(' . $exception->getLine() . ')'?>
</p>
<?php if (YII_DEBUG) $owner->renderSourceCode($exception->getFile(), $exception->getLine(), $owner->maxSourceLines)?>
<?php if (YII_DEBUG) $context->renderSourceCode($exception->getFile(), $exception->getLine(), $context->maxSourceLines)?>
</div>
<?php if (YII_DEBUG):?>
<div class="traces">
<h2>Stack Trace</h2>
<?php $owner->renderTrace($exception->getTrace())?>
<?php $context->renderTrace($exception->getTrace())?>
</div>
<?php endif?>
<div class="version">
<?php echo date('Y-m-d H:i:s', time())?>
<?php echo YII_DEBUG ? $owner->versionInfo : ''?>
<?php echo YII_DEBUG ? $context->versionInfo : ''?>
</div>
</div>
......
......@@ -214,7 +214,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
public function setSavePath($value)
{
$path = Yii::getAlias($value);
if ($path !== false && is_dir($path)) {
if (is_dir($path)) {
session_save_path($path);
} else {
throw new InvalidParamException("Session save path is not a valid directory: $value");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment