CBaseListView.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. <?php
  2. /**
  3. * CBaseListView class file.
  4. *
  5. * @author Qiang Xue <qiang.xue@gmail.com>
  6. * @link http://www.yiiframework.com/
  7. * @copyright 2008-2013 Yii Software LLC
  8. * @license http://www.yiiframework.com/license/
  9. */
  10. /**
  11. * CBaseListView is the base class for {@link CListView} and {@link CGridView}.
  12. *
  13. * CBaseListView implements the common features needed by a view wiget for rendering multiple models.
  14. *
  15. * @author Qiang Xue <qiang.xue@gmail.com>
  16. * @package zii.widgets
  17. * @since 1.1
  18. */
  19. abstract class CBaseListView extends CWidget
  20. {
  21. /**
  22. * @var IDataProvider the data provider for the view.
  23. */
  24. public $dataProvider;
  25. /**
  26. * @var string the tag name for the view container. Defaults to 'div'.
  27. */
  28. public $tagName='div';
  29. /**
  30. * @var array the HTML options for the view container tag.
  31. */
  32. public $htmlOptions=array();
  33. /**
  34. * @var boolean whether to enable sorting. Note that if the {@link IDataProvider::sort} property
  35. * of {@link dataProvider} is false, this will be treated as false as well. When sorting is enabled,
  36. * sortable columns will have their headers clickable to trigger sorting along that column.
  37. * Defaults to true.
  38. * @see sortableAttributes
  39. */
  40. public $enableSorting=true;
  41. /**
  42. * @var boolean whether to enable pagination. Note that if the {@link IDataProvider::pagination} property
  43. * of {@link dataProvider} is false, this will be treated as false as well. When pagination is enabled,
  44. * a pager will be displayed in the view so that it can trigger pagination of the data display.
  45. * Defaults to true.
  46. */
  47. public $enablePagination=true;
  48. /**
  49. * @var array|string the configuration for the pager. Defaults to <code>array('class'=>'CLinkPager')</code>.
  50. * String value will be treated as the class name of the pager (<code>'ClassName'</code> value is similar
  51. * to the <code>array('class'=>'ClassName')</code> value). See {@link CBasePager} and {@link CLinkPager}
  52. * for more details about pager configuration array values.
  53. * @see enablePagination
  54. */
  55. public $pager=array('class'=>'CLinkPager');
  56. /**
  57. * @var string the template to be used to control the layout of various sections in the view.
  58. * These tokens are recognized: {summary}, {items} and {pager}. They will be replaced with the
  59. * summary text, the items, and the pager.
  60. */
  61. public $template="{summary}\n{items}\n{pager}";
  62. /**
  63. * @var string the summary text template for the view. These tokens are recognized and will be replaced
  64. * with the corresponding values:
  65. * <ul>
  66. * <li>{start}: the starting row number (1-based) currently being displayed</li>
  67. * <li>{end}: the ending row number (1-based) currently being displayed</li>
  68. * <li>{count}: the total number of rows</li>
  69. * <li>{page}: the page number (1-based) current being displayed, available since version 1.1.3</li>
  70. * <li>{pages}: the total number of pages, available since version 1.1.3</li>
  71. * </ul>
  72. */
  73. public $summaryText;
  74. /**
  75. * @var string the HTML tag name for the container of the {@link summaryText} property.
  76. * @since 1.1.16
  77. */
  78. public $summaryTagName='div';
  79. /**
  80. * @var string the message to be displayed when {@link dataProvider} does not have any data.
  81. */
  82. public $emptyText;
  83. /**
  84. * @var string the HTML tag name for the container of the {@link emptyText} property.
  85. */
  86. public $emptyTagName='span';
  87. /**
  88. * @var string the CSS class name for the container of the {@link emptyText} property. Defaults to 'empty'.
  89. * @since 1.1.16
  90. */
  91. public $emptyCssClass='empty';
  92. /**
  93. * @var string the CSS class name for the container of all data item display. Defaults to 'items'.
  94. * Note, this property must not contain false, null or empty string values. Otherwise such values may
  95. * cause undefined behavior.
  96. */
  97. public $itemsCssClass='items';
  98. /**
  99. * @var string the CSS class name for the summary text container. Defaults to 'summary'.
  100. */
  101. public $summaryCssClass='summary';
  102. /**
  103. * @var string the CSS class name for the pager container. Defaults to 'pager'.
  104. * Note, this property must not contain false, null or empty string values. Otherwise such values may
  105. * cause undefined behavior.
  106. */
  107. public $pagerCssClass='pager';
  108. /**
  109. * @var string the CSS class name that will be assigned to the widget container element
  110. * when the widget is updating its content via AJAX. Defaults to 'loading'.
  111. * @since 1.1.1
  112. */
  113. public $loadingCssClass='loading';
  114. /**
  115. * Initializes the view.
  116. * This method will initialize required property values and instantiate {@link columns} objects.
  117. */
  118. public function init()
  119. {
  120. if($this->dataProvider===null)
  121. throw new CException(Yii::t('zii','The "dataProvider" property cannot be empty.'));
  122. $this->dataProvider->getData();
  123. if(isset($this->htmlOptions['id']))
  124. $this->id=$this->htmlOptions['id'];
  125. else
  126. $this->htmlOptions['id']=$this->id;
  127. if($this->enableSorting && $this->dataProvider->getSort()===false)
  128. $this->enableSorting=false;
  129. if($this->enablePagination && $this->dataProvider->getPagination()===false)
  130. $this->enablePagination=false;
  131. }
  132. /**
  133. * Renders the view.
  134. * This is the main entry of the whole view rendering.
  135. * Child classes should mainly override {@link renderContent} method.
  136. */
  137. public function run()
  138. {
  139. $this->registerClientScript();
  140. echo CHtml::openTag($this->tagName,$this->htmlOptions)."\n";
  141. $this->renderContent();
  142. $this->renderKeys();
  143. echo CHtml::closeTag($this->tagName);
  144. }
  145. /**
  146. * Renders the main content of the view.
  147. * The content is divided into sections, such as summary, items, pager.
  148. * Each section is rendered by a method named as "renderXyz", where "Xyz" is the section name.
  149. * The rendering results will replace the corresponding placeholders in {@link template}.
  150. */
  151. public function renderContent()
  152. {
  153. ob_start();
  154. echo preg_replace_callback("/{(\w+)}/",array($this,'renderSection'),$this->template);
  155. ob_end_flush();
  156. }
  157. /**
  158. * Renders a section.
  159. * This method is invoked by {@link renderContent} for every placeholder found in {@link template}.
  160. * It should return the rendering result that would replace the placeholder.
  161. * @param array $matches the matches, where $matches[0] represents the whole placeholder,
  162. * while $matches[1] contains the name of the matched placeholder.
  163. * @return string the rendering result of the section
  164. */
  165. protected function renderSection($matches)
  166. {
  167. $method='render'.$matches[1];
  168. if(method_exists($this,$method))
  169. {
  170. $this->$method();
  171. $html=ob_get_contents();
  172. ob_clean();
  173. return $html;
  174. }
  175. else
  176. return $matches[0];
  177. }
  178. /**
  179. * Renders the empty message when there is no data.
  180. */
  181. public function renderEmptyText()
  182. {
  183. $emptyText=$this->emptyText===null ? Yii::t('zii','No results found.') : $this->emptyText;
  184. echo CHtml::tag($this->emptyTagName, array('class'=>$this->emptyCssClass), $emptyText);
  185. }
  186. /**
  187. * Renders the key values of the data in a hidden tag.
  188. */
  189. public function renderKeys()
  190. {
  191. echo CHtml::openTag('div',array(
  192. 'class'=>'keys',
  193. 'style'=>'display:none',
  194. 'title'=>Yii::app()->getRequest()->getUrl(),
  195. ));
  196. foreach($this->dataProvider->getKeys() as $key)
  197. echo "<span>".CHtml::encode($key)."</span>";
  198. echo "</div>\n";
  199. }
  200. /**
  201. * Renders the summary text.
  202. */
  203. public function renderSummary()
  204. {
  205. if(($count=$this->dataProvider->getItemCount())<=0)
  206. return;
  207. echo CHtml::openTag($this->summaryTagName, array('class'=>$this->summaryCssClass));
  208. if($this->enablePagination)
  209. {
  210. $pagination=$this->dataProvider->getPagination();
  211. $total=$this->dataProvider->getTotalItemCount();
  212. $start=$pagination->currentPage*$pagination->pageSize+1;
  213. $end=$start+$count-1;
  214. if($end>$total)
  215. {
  216. $end=$total;
  217. $start=$end-$count+1;
  218. }
  219. if(($summaryText=$this->summaryText)===null)
  220. $summaryText=Yii::t('zii','Displaying {start}-{end} of 1 result.|Displaying {start}-{end} of {count} results.',$total);
  221. echo strtr($summaryText,array(
  222. '{start}'=>$start,
  223. '{end}'=>$end,
  224. '{count}'=>$total,
  225. '{page}'=>$pagination->currentPage+1,
  226. '{pages}'=>$pagination->pageCount,
  227. ));
  228. }
  229. else
  230. {
  231. if(($summaryText=$this->summaryText)===null)
  232. $summaryText=Yii::t('zii','Total 1 result.|Total {count} results.',$count);
  233. echo strtr($summaryText,array(
  234. '{count}'=>$count,
  235. '{start}'=>1,
  236. '{end}'=>$count,
  237. '{page}'=>1,
  238. '{pages}'=>1,
  239. ));
  240. }
  241. echo CHtml::closeTag($this->summaryTagName);
  242. }
  243. /**
  244. * Renders the pager.
  245. */
  246. public function renderPager()
  247. {
  248. if(!$this->enablePagination)
  249. return;
  250. $pager=array();
  251. $class='CLinkPager';
  252. if(is_string($this->pager))
  253. $class=$this->pager;
  254. elseif(is_array($this->pager))
  255. {
  256. $pager=$this->pager;
  257. if(isset($pager['class']))
  258. {
  259. $class=$pager['class'];
  260. unset($pager['class']);
  261. }
  262. }
  263. $pager['pages']=$this->dataProvider->getPagination();
  264. if($pager['pages']->getPageCount()>1)
  265. {
  266. echo '<div class="'.$this->pagerCssClass.'">';
  267. $this->widget($class,$pager);
  268. echo '</div>';
  269. }
  270. else
  271. $this->widget($class,$pager);
  272. }
  273. /**
  274. * Registers necessary client scripts.
  275. * This method is invoked by {@link run}.
  276. * Child classes may override this method to register customized client scripts.
  277. */
  278. public function registerClientScript()
  279. {
  280. }
  281. /**
  282. * Renders the data items for the view.
  283. * Each item is corresponding to a single data model instance.
  284. * Child classes should override this method to provide the actual item rendering logic.
  285. */
  286. abstract public function renderItems();
  287. }