BaseListView.php 10 KB

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