Commit 539be8eb by Qiang Xue

Refactored ListView.

parent b1c67b86
......@@ -111,7 +111,8 @@ class DetailView extends Widget
$this->formatter = Yii::$app->getFormatter();
} elseif (is_array($this->formatter)) {
$this->formatter = Yii::createObject($this->formatter);
} elseif (!$this->formatter instanceof Formatter) {
}
if (!$this->formatter instanceof Formatter) {
throw new InvalidConfigException('The "formatter" property must be either a Format object or a configuration array.');
}
$this->normalizeAttributes();
......@@ -173,7 +174,7 @@ class DetailView extends Widget
foreach ($this->attributes as $i => $attribute) {
if (is_string($attribute)) {
if (!preg_match('/^(\w+)(\s*:\s*(\w+))?$/', $attribute, $matches)) {
throw new InvalidConfigException('The attribute must be in the format of "Name" or "Name:Type"');
throw new InvalidConfigException('The attribute must be specified in the format of "Name" or "Name:Type"');
}
$attribute = array(
'name' => $matches[1],
......
......@@ -8,9 +8,6 @@
namespace yii\widgets;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\Model;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
......@@ -19,18 +16,9 @@ use yii\helpers\Html;
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class ListView extends Widget
class ListView extends ListViewBase
{
/**
* @var array the HTML attributes for the container tag of the list view.
* The "tag" element specifies the tag name of the container element and defaults to "div".
*/
public $options = array();
/**
* @var \yii\data\IDataProvider the data provider for the view. This property is required.
*/
public $dataProvider;
/**
* @var array the HTML attributes for the container of the rendering result of each data item.
* The "tag" element specifies the tag name of the container element and defaults to "div".
* If "tag" is false, it means no container element will be rendered.
......@@ -59,129 +47,9 @@ class ListView extends Widget
* @var string the HTML code to be displayed between any two consecutive items.
*/
public $separator = "\n";
/**
* @var array the configuration for the pager widget. By default, [[LinkPager]] will be
* used to render the pager. You can use a different widget class by configuring the "class" element.
*/
public $pager = array();
/**
* @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be
* used to render the sorter. You can use a different widget class by configuring the "class" element.
*/
public $sorter = array();
/**
* @var string the HTML content to be displayed as the summary of the list view.
* If you do not want to show the summary, you may set it with an empty string.
*
* The following tokens will be replaced with the corresponding values:
*
* - `{begin}`: the starting row number (1-based) currently being displayed
* - `{end}`: the ending row number (1-based) currently being displayed
* - `{count}`: the number of rows currently being displayed
* - `{totalCount}`: the total number of rows available
* - `{page}`: the page number (1-based) current being displayed
* - `{pageCount}`: the number of pages available
*/
public $summary;
/**
* @var string the HTML content to be displayed when [[dataProvider]] does not have any data.
* If you do not want to show anything when [[dataProvider]] is empty, you may set this property with an empty string.
*/
public $empty;
/**
* @var string the layout that determines how different sections of the list view should be organized.
* The following tokens will be replaced with the corresponding section contents:
*
* - `{summary}`: the summary section. See [[renderSummary()]].
* - `{items}`: the list items. See [[renderItems()]].
* - `{sorter}`: the sorter. See [[renderSorter()]].
* - `{pager}`: the pager. See [[renderPager()]].
*/
public $layout = "{summary}\n{sorter}\n{items}\n{pager}";
/**
* Initializes the view.
*/
public function init()
{
if ($this->dataProvider === null) {
throw new InvalidConfigException('The "dataProvider" property must be set.');
}
if ($this->empty === null) {
$this->empty = '<div class="empty">' . Yii::t('yii', 'No results found.') . '</div>';
}
}
/**
* Runs the widget.
*/
public function run()
{
if ($this->dataProvider->getCount() > 0) {
$tag = ArrayHelper::remove($this->options, 'tag', 'div');
$content = preg_replace_callback("/{\\w+}/", array($this, 'renderSection'), $this->layout);
echo Html::tag($tag, $content, $this->options);
} else {
echo $this->empty;
}
}
/**
* Renders a section of the list view.
* This method is invoked for every placeholder found in [[layout]].
* It should return the rendering result that would replace the placeholder.
* @param array $matches the matches, where $matches[0] represents the matching placeholder.
* @return string the rendering result of the section
*/
protected function renderSection($matches)
{
switch ($matches[0]) {
case '{summary}': return $this->renderSummary();
case '{items}': return $this->renderItems();
case '{sorter}': return $this->renderSorter();
case '{pager}': return $this->renderPager();
default: return $matches[0];
}
}
/**
* Renders the summary text.
*/
public function renderSummary()
{
$count = $this->dataProvider->getCount();
if (($pagination = $this->dataProvider->getPagination()) !== false) {
$totalCount = $this->dataProvider->getTotalCount();
$begin = $pagination->getPage() * $pagination->pageSize + 1;
$end = $begin + $count - 1;
if ($end > $totalCount) {
$end = $totalCount;
$begin = $end - $count + 1;
}
$page = $pagination->getPage() + 1;
$pageCount = $pagination->pageCount;
if (($summaryContent = $this->summary) === null) {
$summaryContent = '<div class="summary">' . Yii::t('yii', 'Total <b>1</b> result.|Showing <b>{begin}-{end}</b> of <b>{totalCount}</b> results.', $totalCount) . '</div>';
}
} else {
$begin = $page = $pageCount = 1;
$end = $totalCount = $count;
if (($summaryContent = $this->summary) === null) {
$summaryContent = '<div class="summary">' . Yii::t('yii', 'Total <b>1</b> result.|Total <b>{count}</b> results.', $count) . '</div>';
}
}
return strtr($summaryContent, array(
'{begin}' => $begin,
'{end}' => $end,
'{count}' => $count,
'{totalCount}' => $totalCount,
'{page}' => $page,
'{pageCount}' => $pageCount,
));
}
/**
* Renders all data items.
* @return string the rendering result
*/
......@@ -226,36 +94,4 @@ class ListView extends Widget
return $content;
}
}
/**
* Renders the sorter.
* @return string the rendering result
*/
public function renderSorter()
{
$sort = $this->dataProvider->getSort();
if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) {
return '';
}
/** @var LinkSorter $class */
$class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className());
$this->sorter['sort'] = $sort;
return $class::widget($this->sorter);
}
/**
* Renders the pager.
* @return string the rendering result
*/
public function renderPager()
{
$pagination = $this->dataProvider->getPagination();
if ($pagination === false || $this->dataProvider->getCount() <= 0) {
return '';
}
/** @var LinkPager $class */
$class = ArrayHelper::remove($this->pager, 'class', LinkPager::className());
$this->pager['pagination'] = $pagination;
return $class::widget($this->pager);
}
}
<?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\InvalidConfigException;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
abstract class ListViewBase extends Widget
{
/**
* @var array the HTML attributes for the container tag of the list view.
* The "tag" element specifies the tag name of the container element and defaults to "div".
*/
public $options = array();
/**
* @var \yii\data\IDataProvider the data provider for the view. This property is required.
*/
public $dataProvider;
/**
* @var array the configuration for the pager widget. By default, [[LinkPager]] will be
* used to render the pager. You can use a different widget class by configuring the "class" element.
*/
public $pager = array();
/**
* @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be
* used to render the sorter. You can use a different widget class by configuring the "class" element.
*/
public $sorter = array();
/**
* @var string the HTML content to be displayed as the summary of the list view.
* If you do not want to show the summary, you may set it with an empty string.
*
* The following tokens will be replaced with the corresponding values:
*
* - `{begin}`: the starting row number (1-based) currently being displayed
* - `{end}`: the ending row number (1-based) currently being displayed
* - `{count}`: the number of rows currently being displayed
* - `{totalCount}`: the total number of rows available
* - `{page}`: the page number (1-based) current being displayed
* - `{pageCount}`: the number of pages available
*/
public $summary;
/**
* @var string|boolean the HTML content to be displayed when [[dataProvider]] does not have any data.
* If false, the list view will still be displayed (without body content though).
*/
public $empty;
/**
* @var string the layout that determines how different sections of the list view should be organized.
* The following tokens will be replaced with the corresponding section contents:
*
* - `{summary}`: the summary section. See [[renderSummary()]].
* - `{items}`: the list items. See [[renderItems()]].
* - `{sorter}`: the sorter. See [[renderSorter()]].
* - `{pager}`: the pager. See [[renderPager()]].
*/
public $layout = "{summary}\n{sorter}\n{items}\n{pager}";
/**
* Renders the data items.
* @return string the rendering result.
*/
abstract public function renderItems();
/**
* Initializes the view.
*/
public function init()
{
if ($this->dataProvider === null) {
throw new InvalidConfigException('The "dataProvider" property must be set.');
}
}
/**
* Runs the widget.
*/
public function run()
{
if ($this->dataProvider->getCount() > 0 || $this->empty === false) {
$content = preg_replace_callback("/{\\w+}/", function ($matches) {
$content = $this->renderSection($matches[0]);
return $content === false ? $matches[0] : $content;
}, $this->layout);
} else {
$content = '<div class="empty">' . ($this->empty === null ? Yii::t('yii', 'No results found.') : $this->empty) . '</div>';
}
$tag = ArrayHelper::remove($this->options, 'tag', 'div');
echo Html::tag($tag, $content, $this->options);
}
/**
* Renders a section of the specified name.
* If the named section is not supported, false will be returned.
* @param string $name the section name, e.g., `{summary}`, `{items}`.
* @return string|boolean the rendering result of the section, or false if the named section is not supported.
*/
protected function renderSection($name)
{
switch ($name) {
case '{summary}':
return $this->renderSummary();
case '{items}':
return $this->renderItems();
case '{pager}':
return $this->renderPager();
case '{sorter}':
return $this->renderSorter();
default:
return false;
}
}
/**
* Renders the summary text.
*/
public function renderSummary()
{
$count = $this->dataProvider->getCount();
if (($pagination = $this->dataProvider->getPagination()) !== false) {
$totalCount = $this->dataProvider->getTotalCount();
$begin = $pagination->getPage() * $pagination->pageSize + 1;
$end = $begin + $count - 1;
if ($end > $totalCount) {
$end = $totalCount;
$begin = $end - $count + 1;
}
$page = $pagination->getPage() + 1;
$pageCount = $pagination->pageCount;
if (($summaryContent = $this->summary) === null) {
$summaryContent = '<div class="summary">' . Yii::t('yii', 'Total <b>1</b> item.|Showing <b>{begin}-{end}</b> of <b>{totalCount}</b> items.', $totalCount) . '</div>';
}
} else {
$begin = $page = $pageCount = 1;
$end = $totalCount = $count;
if (($summaryContent = $this->summary) === null) {
$summaryContent = '<div class="summary">' . Yii::t('yii', 'Total <b>1</b> item.|Total <b>{count}</b> items.', $count) . '</div>';
}
}
return strtr($summaryContent, array(
'{begin}' => $begin,
'{end}' => $end,
'{count}' => $count,
'{totalCount}' => $totalCount,
'{page}' => $page,
'{pageCount}' => $pageCount,
));
}
/**
* Renders the pager.
* @return string the rendering result
*/
public function renderPager()
{
$pagination = $this->dataProvider->getPagination();
if ($pagination === false || $this->dataProvider->getCount() <= 0) {
return '';
}
/** @var LinkPager $class */
$class = ArrayHelper::remove($this->pager, 'class', LinkPager::className());
$this->pager['pagination'] = $pagination;
return $class::widget($this->pager);
}
/**
* Renders the sorter.
* @return string the rendering result
*/
public function renderSorter()
{
$sort = $this->dataProvider->getSort();
if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) {
return '';
}
/** @var LinkSorter $class */
$class = ArrayHelper::remove($this->sorter, 'class', LinkSorter::className());
$this->sorter['sort'] = $sort;
return $class::widget($this->sorter);
}
}
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