You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 line
9.5KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\widgets;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. use yii\base\Widget;
  11. use yii\helpers\ArrayHelper;
  12. use yii\helpers\Html;
  13. /**
  14. * BaseListView is a base class for widgets displaying data from data provider
  15. * such as ListView and GridView.
  16. *
  17. * It provides features like sorting, paging and also filtering the data.
  18. *
  19. * @author Qiang Xue <qiang.xue@gmail.com>
  20. * @since 2.0
  21. */
  22. abstract class BaseListView extends Widget
  23. {
  24. /**
  25. * @var array the HTML attributes for the container tag of the list view.
  26. * The "tag" element specifies the tag name of the container element and defaults to "div".
  27. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
  28. */
  29. public $options = [];
  30. /**
  31. * @var \yii\data\DataProviderInterface the data provider for the view. This property is required.
  32. */
  33. public $dataProvider;
  34. /**
  35. * @var array the configuration for the pager widget. By default, [[LinkPager]] will be
  36. * used to render the pager. You can use a different widget class by configuring the "class" element.
  37. * Note that the widget must support the `pagination` property which will be populated with the
  38. * [[\yii\data\BaseDataProvider::pagination|pagination]] value of the [[dataProvider]].
  39. */
  40. public $pager = [];
  41. /**
  42. * @var array the configuration for the sorter widget. By default, [[LinkSorter]] will be
  43. * used to render the sorter. You can use a different widget class by configuring the "class" element.
  44. * Note that the widget must support the `sort` property which will be populated with the
  45. * [[\yii\data\BaseDataProvider::sort|sort]] value of the [[dataProvider]].
  46. */
  47. public $sorter = [];
  48. /**
  49. * @var string the HTML content to be displayed as the summary of the list view.
  50. * If you do not want to show the summary, you may set it with an empty string.
  51. *
  52. * The following tokens will be replaced with the corresponding values:
  53. *
  54. * - `{begin}`: the starting row number (1-based) currently being displayed
  55. * - `{end}`: the ending row number (1-based) currently being displayed
  56. * - `{count}`: the number of rows currently being displayed
  57. * - `{totalCount}`: the total number of rows available
  58. * - `{page}`: the page number (1-based) current being displayed
  59. * - `{pageCount}`: the number of pages available
  60. */
  61. public $summary;
  62. /**
  63. * @var array the HTML attributes for the summary of the list view.
  64. * The "tag" element specifies the tag name of the summary element and defaults to "div".
  65. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
  66. */
  67. public $summaryOptions = ['class' => 'summary'];
  68. /**
  69. * @var boolean whether to show the list view if [[dataProvider]] returns no data.
  70. */
  71. public $showOnEmpty = false;
  72. /**
  73. * @var string the HTML content to be displayed when [[dataProvider]] does not have any data.
  74. */
  75. public $emptyText;
  76. /**
  77. * @var array the HTML attributes for the emptyText of the list view.
  78. * The "tag" element specifies the tag name of the emptyText element and defaults to "div".
  79. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
  80. */
  81. public $emptyTextOptions = ['class' => 'empty'];
  82. /**
  83. * @var string the layout that determines how different sections of the list view should be organized.
  84. * The following tokens will be replaced with the corresponding section contents:
  85. *
  86. * - `{summary}`: the summary section. See [[renderSummary()]].
  87. * - `{items}`: the list items. See [[renderItems()]].
  88. * - `{sorter}`: the sorter. See [[renderSorter()]].
  89. * - `{pager}`: the pager. See [[renderPager()]].
  90. */
  91. public $layout = "{summary}\n{items}\n{pager}";
  92. /**
  93. * Renders the data models.
  94. * @return string the rendering result.
  95. */
  96. abstract public function renderItems();
  97. /**
  98. * Initializes the view.
  99. */
  100. public function init()
  101. {
  102. if ($this->dataProvider === null) {
  103. throw new InvalidConfigException('The "dataProvider" property must be set.');
  104. }
  105. if ($this->emptyText === null) {
  106. $this->emptyText = Yii::t('yii', 'No results found.');
  107. }
  108. if (!isset($this->options['id'])) {
  109. $this->options['id'] = $this->getId();
  110. }
  111. }
  112. /**
  113. * Runs the widget.
  114. */
  115. public function run()
  116. {
  117. if ($this->showOnEmpty || $this->dataProvider->getCount() > 0) {
  118. $content = preg_replace_callback("/{\\w+}/", function ($matches) {
  119. $content = $this->renderSection($matches[0]);
  120. return $content === false ? $matches[0] : $content;
  121. }, $this->layout);
  122. } else {
  123. $content = $this->renderEmpty();
  124. }
  125. $options = $this->options;
  126. $tag = ArrayHelper::remove($options, 'tag', 'div');
  127. echo Html::tag($tag, $content, $options);
  128. }
  129. /**
  130. * Renders a section of the specified name.
  131. * If the named section is not supported, false will be returned.
  132. * @param string $name the section name, e.g., `{summary}`, `{items}`.
  133. * @return string|boolean the rendering result of the section, or false if the named section is not supported.
  134. */
  135. public function renderSection($name)
  136. {
  137. switch ($name) {
  138. case '{summary}':
  139. return $this->renderSummary();
  140. case '{items}':
  141. return $this->renderItems();
  142. case '{pager}':
  143. return $this->renderPager();
  144. case '{sorter}':
  145. return $this->renderSorter();
  146. default:
  147. return false;
  148. }
  149. }
  150. /**
  151. * Renders the HTML content indicating that the list view has no data.
  152. * @return string the rendering result
  153. * @see emptyText
  154. */
  155. public function renderEmpty()
  156. {
  157. $options = $this->emptyTextOptions;
  158. $tag = ArrayHelper::remove($options, 'tag', 'div');
  159. return Html::tag($tag, $this->emptyText, $options);
  160. }
  161. /**
  162. * Renders the summary text.
  163. */
  164. public function renderSummary()
  165. {
  166. $count = $this->dataProvider->getCount();
  167. if ($count <= 0) {
  168. return '';
  169. }
  170. $summaryOptions = $this->summaryOptions;
  171. $tag = ArrayHelper::remove($summaryOptions, 'tag', 'div');
  172. if (($pagination = $this->dataProvider->getPagination()) !== false) {
  173. $totalCount = $this->dataProvider->getTotalCount();
  174. $begin = $pagination->getPage() * $pagination->pageSize + 1;
  175. $end = $begin + $count - 1;
  176. if ($begin > $end) {
  177. $begin = $end;
  178. }
  179. $page = $pagination->getPage() + 1;
  180. $pageCount = $pagination->pageCount;
  181. if (($summaryContent = $this->summary) === null) {
  182. return Html::tag($tag, Yii::t('yii', 'Showing <b>{begin, number}-{end, number}</b> of <b>{totalCount, number}</b> {totalCount, plural, one{item} other{items}}.', [
  183. 'begin' => $begin,
  184. 'end' => $end,
  185. 'count' => $count,
  186. 'totalCount' => $totalCount,
  187. 'page' => $page,
  188. 'pageCount' => $pageCount,
  189. ]), $summaryOptions);
  190. }
  191. } else {
  192. $begin = $page = $pageCount = 1;
  193. $end = $totalCount = $count;
  194. if (($summaryContent = $this->summary) === null) {
  195. return Html::tag($tag, Yii::t('yii', 'Total <b>{count, number}</b> {count, plural, one{item} other{items}}.', [
  196. 'begin' => $begin,
  197. 'end' => $end,
  198. 'count' => $count,
  199. 'totalCount' => $totalCount,
  200. 'page' => $page,
  201. 'pageCount' => $pageCount,
  202. ]), $summaryOptions);
  203. }
  204. }
  205. return Yii::$app->getI18n()->format($summaryContent, [
  206. 'begin' => $begin,
  207. 'end' => $end,
  208. 'count' => $count,
  209. 'totalCount' => $totalCount,
  210. 'page' => $page,
  211. 'pageCount' => $pageCount,
  212. ], Yii::$app->language);
  213. }
  214. /**
  215. * Renders the pager.
  216. * @return string the rendering result
  217. */
  218. public function renderPager()
  219. {
  220. $pagination = $this->dataProvider->getPagination();
  221. if ($pagination === false || $this->dataProvider->getCount() <= 0) {
  222. return '';
  223. }
  224. /* @var $class LinkPager */
  225. $pager = $this->pager;
  226. $class = ArrayHelper::remove($pager, 'class', LinkPager::className());
  227. $pager['pagination'] = $pagination;
  228. $pager['view'] = $this->getView();
  229. return $class::widget($pager);
  230. }
  231. /**
  232. * Renders the sorter.
  233. * @return string the rendering result
  234. */
  235. public function renderSorter()
  236. {
  237. $sort = $this->dataProvider->getSort();
  238. if ($sort === false || empty($sort->attributes) || $this->dataProvider->getCount() <= 0) {
  239. return '';
  240. }
  241. /* @var $class LinkSorter */
  242. $sorter = $this->sorter;
  243. $class = ArrayHelper::remove($sorter, 'class', LinkSorter::className());
  244. $sorter['sort'] = $sort;
  245. $sorter['view'] = $this->getView();
  246. return $class::widget($sorter);
  247. }
  248. }