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;
/**
......@@ -94,7 +94,7 @@ class YiiBase
*/
public static $objectConfig = array();
private static $_imported = array(); // alias => class name or directory
private static $_imported = array(); // alias => class name or directory
private static $_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,24 +189,30 @@ 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])) {
return self::$aliases[$alias];
} elseif ($alias === '' || $alias[0] !== '@') { // not an alias
return $alias;
} elseif (($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 (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 || ($pos = strpos($alias, '\\')) !== false) {
$rootAlias = substr($alias, 0, $pos);
if (isset(self::$aliases[$rootAlias])) {
return self::$aliases[$alias] = self::$aliases[$rootAlias] . substr($alias, $pos);
}
}
}
return false;
if ($throwException) {
throw new InvalidParamException("Invalid path alias: $alias");
} else {
return false;
}
}
/**
......@@ -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) {
......
......@@ -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