Browse Source

view WIP

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
a5ee5b842b
  1. 52
      framework/base/Controller.php
  2. 188
      framework/base/View.php
  3. 45
      framework/base/Widget.php
  4. 57
      framework/widgets/Clip.php
  5. 81
      framework/widgets/ContentDecorator.php

52
framework/base/Controller.php

@ -304,9 +304,13 @@ class Controller extends Component
*/
public function render($view, $params = array())
{
$viewFile = $this->findViewFile($view);
$output = Yii::$app->getView()->render($view, $params, $this);
$layoutFile = $this->findLayoutFile();
return Yii::$app->getView()->render($this, $viewFile, $params, $layoutFile);
if ($layoutFile !== false) {
return Yii::$app->getView()->renderFile($layoutFile, array('content' => $output), $this);
} else {
return $output;
}
}
/**
@ -319,7 +323,7 @@ class Controller extends Component
*/
public function renderPartial($view, $params = array())
{
return $this->renderFile($this->findViewFile($view), $params);
return Yii::$app->getView()->render($view, $params, $this);
}
/**
@ -331,7 +335,7 @@ class Controller extends Component
*/
public function renderFile($file, $params = array())
{
return Yii::$app->getView()->render($this, $file, $params);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
@ -346,46 +350,6 @@ class Controller extends Component
}
/**
* 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.

188
framework/base/View.php

@ -39,6 +39,12 @@ class View extends Component
* If not set, it means theming is not enabled.
*/
public $theme;
/**
* @var array a list of named output clips. You can call [[beginClip()]] and [[endClip()]]
* to capture small fragments of a view. They can be later accessed at somewhere else
* through this property.
*/
public $clips;
/**
* @var Widget[] the widgets that are currently not ended
@ -61,35 +67,29 @@ class View extends Component
}
/**
* Renders a view file under a context with an optional layout.
* Renders a view.
*
* 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.
* This method will call [[findViewFile()]] to convert the view name into the corresponding view
* file path, and it will then call [[renderFile()]] to render the view.
*
* 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 string $view the view name. Please refer to [[findViewFile()]] on how to specify this parameter.
* @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.
* @param object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @return string the rendering result
* @throws InvalidParamException if the view file or the layout file does not exist.
* @throws InvalidParamException if the view cannot be resolved or the view file does not exist.
* @see renderFile
* @see findViewFile
*/
public function render($view, $params = array())
public function render($view, $params = array(), $context = null)
{
$viewFile = $this->findViewFile($this->context, $view);
return $this->renderFile($viewFile, $params);
$viewFile = $this->findViewFile($context, $view);
return $this->renderFile($viewFile, $params, $context);
}
/**
* Renders a view file.
*
* 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.
*
@ -99,12 +99,14 @@ class View extends Component
* 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 string $viewFile the view file. This can be either 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 object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @return string the rendering result
* @throws InvalidParamException if the view file does not exist
*/
public function renderFile($viewFile, $params = array())
public function renderFile($viewFile, $params = array(), $context = null)
{
$viewFile = Yii::getAlias($viewFile);
if (is_file($viewFile)) {
@ -116,11 +118,18 @@ class View extends Component
throw new InvalidParamException("The view file does not exist: $viewFile");
}
$oldContext = $this->context;
$this->context = $context;
if ($this->renderer !== null) {
return $this->renderer->render($this, $viewFile, $params);
$output = $this->renderer->render($this, $viewFile, $params);
} else {
return $this->renderPhpFile($viewFile, $params);
$output = $this->renderPhpFile($viewFile, $params);
}
$this->context = $oldContext;
return $output;
}
/**
@ -156,36 +165,36 @@ class View extends Component
* - 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]].
* - relative path (e.g. "index"): the actual view file will be looked for under [[Controller::viewPath|viewPath]]
* of the context object, assuming the context is either a [[Controller]] or a [[Widget]].
*
* If the view name does not contain a file extension, it will use the default one `.php`.
*
* @param object $context the view context object
* @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
* @throws InvalidParamException if the view file is an invalid path alias or the context cannot be
* used to determine the actual view file corresponding to the specified view.
*/
protected function findViewFile($context, $view)
{
if (FileHelper::getExtension($view) === '') {
$view .= '.php';
}
if (strncmp($view, '//', 2) === 0) {
if (strncmp($view, '@', 1) === 0) {
// e.g. "@app/views/main"
$file = Yii::getAlias($view);
} elseif (strncmp($view, '//', 2) === 0) {
// e.g. "//layouts/main"
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif (strncmp($view, '/', 1) === 0) {
// e.g. "/site/index"
$file = Yii::$app->controller->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif (strncmp($view, '@', 1) !== 0) {
// e.g. "index" or "view/item"
if (method_exists($context, 'getViewPath')) {
$file = $context->getViewPath() . DIRECTORY_SEPARATOR . $view;
} else {
$file = Yii::$app->getViewPath() . DIRECTORY_SEPARATOR . $view;
}
$file = Yii::$app->controller->module->getViewPath() . DIRECTORY_SEPARATOR . ltrim($view, '/');
} elseif ($context instanceof Controller || $context instanceof Widget) {
/** @var $context Controller|Widget */
$file = $context->getViewPath() . DIRECTORY_SEPARATOR . $view;
} else {
throw new InvalidParamException("Unable to resolve the view file for '$view'.");
}
return $file;
return FileHelper::getExtension($file) === '' ? $file . '.php' : $file;
}
/**
@ -260,26 +269,31 @@ class View extends Component
}
}
//
// /**
// * 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 recording a clip.
* This method is a shortcut to beginning [[yii\widgets\Clip]]
* @param string $id the clip ID.
* @param boolean $renderInPlace whether to render the clip content in place.
* Defaults to false, meaning the captured clip will not be displayed.
* @return \yii\widgets\Clip the Clip widget instance
*/
public function beginClip($id, $renderInPlace = false)
{
return $this->beginWidget('yii\widgets\Clip', array(
'id' => $id,
'renderInPlace' => $renderInPlace,
'view' => $this,
));
}
/**
* Ends recording a clip.
*/
public function endClip()
{
$this->endWidget();
}
//
// /**
// * Begins fragment caching.
@ -322,33 +336,33 @@ class View extends Component
// $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();
// }
/**
* 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();
}
}

45
framework/base/Widget.php

@ -80,8 +80,7 @@ class Widget extends Component
*/
public function render($view, $params = array())
{
$file = $this->findViewFile($view);
return Yii::$app->getView()->render($this, $file, $params);
return Yii::$app->getView()->render($view, $params, $this);
}
/**
@ -93,7 +92,7 @@ class Widget extends Component
*/
public function renderFile($file, $params = array())
{
return Yii::$app->getView()->render($this, $file, $params);
return Yii::$app->getView()->renderFile($file, $params, $this);
}
/**
@ -107,44 +106,4 @@ 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;
}
}

57
framework/widgets/Clip.php

@ -0,0 +1,57 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\widgets;
use Yii;
use yii\base\Widget;
use yii\base\View;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Clip extends Widget
{
/**
* @var string the ID of this clip.
*/
public $id;
/**
* @var View the view object for keeping the clip. If not set, the view registered with the application
* will be used.
*/
public $view;
/**
* @var boolean whether to render the clip content in place. Defaults to false,
* meaning the captured clip will not be displayed.
*/
public $renderInPlace = false;
/**
* Starts recording a clip.
*/
public function init()
{
ob_start();
ob_implicit_flush(false);
}
/**
* Ends recording a clip.
* This method stops output buffering and saves the rendering result as a named clip in the controller.
*/
public function run()
{
$clip = ob_get_clean();
if ($this->renderClip) {
echo $clip;
}
$view = $this->view !== null ? $this->view : Yii::$app->getView();
$view->clips[$this->id] = $clip;
}
}

81
framework/widgets/ContentDecorator.php

@ -0,0 +1,81 @@
<?php
/**
* CContentDecorator class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright 2008-2013 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
/**
* CContentDecorator decorates the content it encloses with the specified view.
*
* CContentDecorator is mostly used to implement nested layouts, i.e., a layout
* is embedded within another layout. {@link CBaseController} defines a pair of
* convenient methods to use CContentDecorator:
* <pre>
* $this->beginContent('path/to/view');
* // ... content to be decorated
* $this->endContent();
* </pre>
*
* The property {@link view} specifies the name of the view that is used to
* decorate the content. In the view, the content being decorated may be
* accessed with variable <code>$content</code>.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @package system.web.widgets
* @since 1.0
*/
class CContentDecorator extends COutputProcessor
{
/**
* @var mixed the name of the view that will be used to decorate the captured content.
* If this property is null (default value), 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}.
*/
public $view;
/**
* @var array the variables (name=>value) to be extracted and made available in the decorative view.
*/
public $data=array();
/**
* Processes the captured output.
* This method decorates the output with the specified {@link view}.
* @param string $output the captured output to be processed
*/
public function processOutput($output)
{
$output=$this->decorate($output);
parent::processOutput($output);
}
/**
* Decorates the content by rendering a view and embedding the content in it.
* The content being embedded can be accessed in the view using variable <code>$content</code>
* The decorated content will be displayed directly.
* @param string $content the content to be decorated
* @return string the decorated content
*/
protected function decorate($content)
{
$owner=$this->getOwner();
if($this->view===null)
$viewFile=Yii::app()->getController()->getLayoutFile(null);
else
$viewFile=$owner->getViewFile($this->view);
if($viewFile!==false)
{
$data=$this->data;
$data['content']=$content;
return $owner->renderFile($viewFile,$data,true);
}
else
return $content;
}
}
Loading…
Cancel
Save