Commit 51f44243 by Qiang Xue

Fixes issue #172: Implemented new usage of widgets.

parent 98d2e183
<?php
use yii\helpers\Html;
use yii\widgets\Menu;
use yii\widgets\Breadcrumbs;
use yii\debug\Toolbar;
/**
* @var $this \yii\base\View
......@@ -25,7 +27,7 @@ $this->registerAssetBundle('app');
<div class="navbar">
<div class="navbar-inner">
<div class="container">
<?php $this->widget(Menu::className(), array(
<?php echo Menu::widget($this, array(
'options' => array('class' => 'nav'),
'items' => array(
array('label' => 'Home', 'url' => array('/site/index')),
......@@ -42,7 +44,7 @@ $this->registerAssetBundle('app');
<!-- /.navbar -->
</div>
<?php $this->widget('yii\widgets\Breadcrumbs', array(
<?php echo Breadcrumbs::widget($this, array(
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
)); ?>
<?php echo $content; ?>
......@@ -58,7 +60,7 @@ $this->registerAssetBundle('app');
</div>
<?php $this->endBody(); ?>
</div>
<?php $this->widget('yii\debug\Toolbar'); ?>
<?php echo Toolbar::widget($this); ?>
</body>
</html>
<?php $this->endPage(); ?>
......@@ -23,7 +23,7 @@ $this->params['breadcrumbs'][] = $this->title;
If you have business inquiries or other questions, please fill out the following form to contact us. Thank you.
</p>
<?php $form = $this->beginWidget(ActiveForm::className(), array(
<?php $form = ActiveForm::begin($this, array(
'options' => array('class' => 'form-horizontal'),
'fieldConfig' => array('inputOptions' => array('class' => 'input-xlarge')),
)); ?>
......@@ -33,14 +33,14 @@ $this->params['breadcrumbs'][] = $this->title;
<?php echo $form->field($model, 'body')->textArea(array('rows' => 6)); ?>
<?php
$field = $form->field($model, 'verifyCode');
echo $field->begin();
echo $field->label();
$this->widget(Captcha::className());
echo Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium'));
echo $field->error();
echo $field->end();
echo $field->begin()
. $field->label()
. Captcha::widget($this)
. Html::activeTextInput($model, 'verifyCode', array('class' => 'input-medium'))
. $field->error()
. $field->end();
?>
<div class="form-actions">
<?php echo Html::submitButton('Submit', null, null, array('class' => 'btn btn-primary')); ?>
</div>
<?php $this->endWidget(); ?>
<?php ActiveForm::end(); ?>
......@@ -14,11 +14,11 @@ $this->params['breadcrumbs'][] = $this->title;
<p>Please fill out the following fields to login:</p>
<?php $form = $this->beginWidget(ActiveForm::className(), array('options' => array('class' => 'form-horizontal'))); ?>
<?php $form = ActiveForm::begin($this, array('options' => array('class' => 'form-horizontal'))); ?>
<?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?>
<?php echo $form->field($model, 'rememberMe')->checkbox(); ?>
<div class="form-actions">
<?php echo Html::submitButton('Login', null, null, array('class' => 'btn btn-primary')); ?>
</div>
<?php $this->endWidget(); ?>
<?php ActiveForm::end(); ?>
......@@ -209,6 +209,26 @@ if (isset($_POST['Post'])) {
```
Widgets
-------
Using a widget is more straightforward in 2.0. You mainly use the `begin()`, `end()` and `widget()`
methods of the `Widget` class. For example,
```php
// $this refers to the View object
// Note that you have to "echo" the result to display it
echo \yii\widgets\Menu::widget($this, array('items' => $items));
// $this refers to the View object
$form = \yii\widgets\ActiveForm::begin($this);
... form inputs here ...
\yii\widgets\ActiveForm::end();
```
Previously in 1.1, you would have to enter the widget class names as strings via the `beginWidget()`,
`endWidget()` and `widget()` methods of `CBaseController`. The approach above gets better IDE support.
Themes
------
......@@ -309,13 +329,13 @@ is a container consisting of a label, an input, and an error message. It is repr
as an `ActiveField` object. Using fields, you can build a form more cleanly than before:
```php
<?php $form = $this->beginWidget('yii\widgets\ActiveForm'); ?>
<?php $form = yii\widgets\ActiveForm::begin(); ?>
<?php echo $form->field($model, 'username')->textInput(); ?>
<?php echo $form->field($model, 'password')->passwordInput(); ?>
<div class="form-actions">
<?php echo Html::submitButton('Login'); ?>
</div>
<?php $this->endWidget(); ?>
<?php yii\widgets\ActiveForm::end(); ?>
```
......
......@@ -11,6 +11,9 @@ use Yii;
use yii\base\Application;
use yii\helpers\FileHelper;
use yii\helpers\Html;
use yii\widgets\Block;
use yii\widgets\ContentDecorator;
use yii\widgets\FragmentCache;
/**
* View represents a view object in the MVC pattern.
......@@ -108,12 +111,6 @@ class View extends Component
*/
public $blocks;
/**
* @var Widget[] the widgets that are currently being rendered (not ended). This property
* is maintained by [[beginWidget()]] and [[endWidget()]] methods. Do not modify it directly.
* @internal
*/
public $widgetStack = array();
/**
* @var array a list of currently active fragment cache widgets. This property
* is used internally to implement the content caching feature. Do not modify it directly.
* @internal
......@@ -364,91 +361,16 @@ class View extends Component
}
/**
* Creates a widget.
* This method will use [[Yii::createObject()]] to create the widget.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @return Widget the newly created widget instance
*/
public function createWidget($class, $properties = array())
{
$properties['class'] = $class;
if (!isset($properties['view'])) {
$properties['view'] = $this;
}
return Yii::createObject($properties);
}
/**
* Creates and runs a widget.
* Compared with [[createWidget()]], this method does one more thing: it will
* run the widget after it is created.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @param boolean $captureOutput whether to capture the output of the widget and return it as a string
* @return string|Widget if $captureOutput is true, the output of the widget will be returned;
* otherwise the widget object will be returned.
*/
public function widget($class, $properties = array(), $captureOutput = false)
{
if ($captureOutput) {
ob_start();
ob_implicit_flush(false);
$widget = $this->createWidget($class, $properties);
$widget->run();
return ob_get_clean();
} else {
$widget = $this->createWidget($class, $properties);
$widget->run();
return $widget;
}
}
/**
* Begins a widget.
* This method is similar to [[createWidget()]] except that it will expect a matching
* [[endWidget()]] call after this.
* @param string $class the widget class name or path alias
* @param array $properties the initial property values of the widget.
* @return Widget the widget instance
*/
public function beginWidget($class, $properties = array())
{
$widget = $this->createWidget($class, $properties);
$this->widgetStack[] = $widget;
return $widget;
}
/**
* Ends a widget.
* Note that the rendering result of the widget is directly echoed out.
* If you want to capture the rendering result of a widget, you may use
* [[createWidget()]] and [[Widget::run()]].
* @return Widget the widget instance
* @throws InvalidCallException if [[beginWidget()]] and [[endWidget()]] calls are not properly nested
*/
public function endWidget()
{
$widget = array_pop($this->widgetStack);
if ($widget instanceof Widget) {
$widget->run();
return $widget;
} else {
throw new InvalidCallException("Unmatched beginWidget() and endWidget() calls.");
}
}
/**
* Begins recording a block.
* This method is a shortcut to beginning [[yii\widgets\Block]]
* This method is a shortcut to beginning [[Block]]
* @param string $id the block ID.
* @param boolean $renderInPlace whether to render the block content in place.
* Defaults to false, meaning the captured block will not be displayed.
* @return \yii\widgets\Block the Block widget instance
* @return Block the Block widget instance
*/
public function beginBlock($id, $renderInPlace = false)
{
return $this->beginWidget('yii\widgets\Block', array(
return Block::begin($this, array(
'id' => $id,
'renderInPlace' => $renderInPlace,
));
......@@ -459,7 +381,7 @@ class View extends Component
*/
public function endBlock()
{
$this->endWidget();
Block::end();
}
/**
......@@ -476,12 +398,12 @@ class View extends Component
* @param string $viewFile the view file that will be used to decorate the content enclosed by this widget.
* This can be specified as either the view file path or path alias.
* @param array $params the variables (name => value) to be extracted and made available in the decorative view.
* @return \yii\widgets\ContentDecorator the ContentDecorator widget instance
* @see \yii\widgets\ContentDecorator
* @return ContentDecorator the ContentDecorator widget instance
* @see ContentDecorator
*/
public function beginContent($viewFile, $params = array())
{
return $this->beginWidget('yii\widgets\ContentDecorator', array(
return ContentDecorator::begin($this, array(
'viewFile' => $viewFile,
'params' => $params,
));
......@@ -492,7 +414,7 @@ class View extends Component
*/
public function endContent()
{
$this->endWidget();
ContentDecorator::end();
}
/**
......@@ -510,15 +432,15 @@ class View extends Component
* ~~~
*
* @param string $id a unique ID identifying the fragment to be cached.
* @param array $properties initial property values for [[\yii\widgets\FragmentCache]]
* @param array $properties initial property values for [[FragmentCache]]
* @return boolean whether you should generate the content for caching.
* False if the cached version is available.
*/
public function beginCache($id, $properties = array())
{
$properties['id'] = $id;
/** @var $cache \yii\widgets\FragmentCache */
$cache = $this->beginWidget('yii\widgets\FragmentCache', $properties);
/** @var $cache FragmentCache */
$cache = FragmentCache::begin($this, $properties);
if ($cache->getCachedContent() !== false) {
$this->endCache();
return false;
......@@ -532,7 +454,7 @@ class View extends Component
*/
public function endCache()
{
$this->endWidget();
FragmentCache::end();
}
......
......@@ -8,7 +8,6 @@
namespace yii\base;
use Yii;
use yii\helpers\FileHelper;
/**
* Widget is the base class for widgets.
......@@ -19,9 +18,9 @@ use yii\helpers\FileHelper;
class Widget extends Component
{
/**
* @var View the view object that is used to create this widget.
* This property is automatically set by [[View::createWidget()]].
* This property is required by [[render()]] and [[renderFile()]].
* @var View the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* This property is also required by [[render()]] and [[renderFile()]].
*/
public $view;
/**
......@@ -29,9 +28,85 @@ class Widget extends Component
*/
private $_id;
/**
* @var integer a counter used to generate IDs for widgets.
* @var integer a counter used to generate [[id]] for widgets.
* @internal
*/
private static $_counter = 0;
public static $_counter = 0;
/**
* @var Widget[] the widgets that are currently being rendered (not ended). This property
* is maintained by [[begin()]] and [[end()]] methods.
* @internal
*/
public static $_stack = array();
/**
* Constructor.
* @param View $view the view object that this widget is associated with.
* The widget will use this view object to register any needed assets.
* It is also required by [[render()]] and [[renderFile()]].
* @param array $config name-value pairs that will be used to initialize the object properties
*/
public function __construct($view, $config = array())
{
$this->view = $view;
parent::__construct($config);
}
/**
* Begins a widget.
* This method creates an instance of the calling class. It will apply the configuration
* to the created instance. A matching [[end()]] call should be called later.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return Widget the newly created widget instance
*/
public static function begin($view, $config = array())
{
$config['class'] = get_called_class();
/** @var Widget $widget */
$widget = Yii::createObject($config, $view);
self::$_stack[] = $widget;
return $widget;
}
/**
* Ends a widget.
* Note that the rendering result of the widget is directly echoed out.
* @return Widget the widget instance that is ended.
* @throws InvalidCallException if [[begin()]] and [[end()]] calls are not properly nested
*/
public static function end()
{
if (!empty(self::$_stack)) {
$widget = array_pop(self::$_stack);
if (get_class($widget) === get_called_class()) {
$widget->run();
return $widget;
} else {
throw new InvalidCallException("Expecting end() of " . get_class($widget) . ", found " . get_called_class());
}
} else {
throw new InvalidCallException("Unexpected " . get_called_class() . '::end() call. A matching begin() is not found.');
}
}
/**
* Creates a widget instance and runs it.
* The widget rendering result is returned by this method.
* @param View $view the view object that the newly created widget is associated with.
* @param array $config name-value pairs that will be used to initialize the object properties
* @return string the rendering result of the widget.
*/
public static function widget($view, $config = array())
{
ob_start();
ob_implicit_flush(false);
/** @var Widget $widget */
$config['class'] = get_called_class();
$widget = Yii::createObject($config, $view);
$widget->run();
return ob_get_clean();
}
/**
* Returns the ID of the widget.
......
......@@ -47,7 +47,7 @@ use Yii;
* }
*
* // display pagination
* $this->widget('yii\widgets\LinkPager', array(
* LinkPager::widget($this, array(
* 'pages' => $pages,
* ));
* ~~~
......
......@@ -19,10 +19,11 @@ use yii\helpers\Html;
* for the "Sample Post". He can click on "Sample Post" to view that page, or he can click on "Home"
* to return to the homepage.
*
* To use Breadcrumbs, you need to configure its [[links]] property, which specifiesthe links to be displayed. For example,
* To use Breadcrumbs, you need to configure its [[links]] property, which specifies the links to be displayed. For example,
*
* ~~~
* $this->widget('yii\widgets\Breadcrumbs', array(
* // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array(
* 'links' => array(
* array('label' => 'Sample Post', 'url' => array('post/edit', 'id' => 1)),
* 'Edit',
......@@ -30,12 +31,13 @@ use yii\helpers\Html;
* ));
* ~~~
*
* Because breadcrumbs usually appears in nearly every page of a website, you may consider place it in a layout view.
* You can then use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different
* Because breadcrumbs usually appears in nearly every page of a website, you may consider placing it in a layout view.
* You can use a view parameter (e.g. `$this->params['breadcrumbs']`) to configure the links in different
* views. In the layout view, you assign this view parameter to the [[links]] property like the following:
*
* ~~~
* $this->widget('yii\widgets\Breadcrumbs', array(
* // $this is the view object currently being used
* echo Breadcrumbs::widget($this, array(
* 'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : array(),
* ));
* ~~~
......
......@@ -26,10 +26,11 @@ use yii\helpers\Html;
* The following example shows how to use Menu:
*
* ~~~
* $this->widget('yii\widgets\Menu', array(
* // $this is the view object currently being used
* echo Menu::widget($this, array(
* 'items' => array(
* // Important: you need to specify url as 'controller/action',
* // not just as 'controller' even if default acion is used.
* // not just as 'controller' even if default action is used.
* array('label' => 'Home', 'url' => array('site/index')),
* // 'Products' menu item will be selected as long as the route is 'product/index'
* array('label' => 'Products', 'url' => array('product/index'), 'items' => array(
......
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