DatePager.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <?php
  2. namespace app\forks\ListView;
  3. use app\models\base\News;
  4. use Cassandra\Date;
  5. use yii\data\ActiveDataProvider;
  6. use yii\db\ActiveQueryInterface;
  7. use yii\db\QueryInterface;
  8. use yii\helpers\ArrayHelper;
  9. use yii\helpers\Html;
  10. use yii\helpers\Url;
  11. use yii\jui\Widget;
  12. class DatePager extends Widget
  13. {
  14. public ActiveDataProvider $dataProvider;
  15. public \DateTime $now;
  16. public $options = ['class' => 'pagination'];
  17. /**
  18. * @var array HTML attributes which will be applied to all link containers
  19. * @since 2.0.13
  20. */
  21. public $linkContainerOptions = [];
  22. /**
  23. * @var array HTML attributes for the link in a pager container tag.
  24. * @see \yii\helpers\Html::renderTagAttributes() for details on how attributes are being rendered.
  25. */
  26. public $pageCssClass;
  27. /**
  28. * @var string the CSS class for the "first" page button.
  29. */
  30. public $firstPageCssClass = 'first';
  31. /**
  32. * @var string the CSS class for the "last" page button.
  33. */
  34. public $lastPageCssClass = 'last';
  35. /**
  36. * @var string the CSS class for the "previous" page button.
  37. */
  38. public $prevPageCssClass = 'prev';
  39. /**
  40. * @var string the CSS class for the "next" page button.
  41. */
  42. public $nextPageCssClass = 'next';
  43. /**
  44. * @var string the CSS class for the active (currently selected) page button.
  45. */
  46. public $activePageCssClass = 'active';
  47. /**
  48. * @var string the CSS class for the disabled page buttons.
  49. */
  50. public $disabledPageCssClass = 'disabled';
  51. /**
  52. * @var array the options for the disabled tag to be generated inside the disabled list element.
  53. * In order to customize the html tag, please use the tag key.
  54. *
  55. * ```php
  56. * $disabledListItemSubTagOptions = ['tag' => 'div', 'class' => 'disabled-div'];
  57. * ```
  58. * @since 2.0.11
  59. */
  60. public $disabledListItemSubTagOptions = [];
  61. /**
  62. * @var int maximum number of page buttons that can be displayed. Defaults to 10.
  63. */
  64. public $maxButtonCount = 10;
  65. /**
  66. * @var string|bool the label for the "next" page button. Note that this will NOT be HTML-encoded.
  67. * If this property is false, the "next" page button will not be displayed.
  68. */
  69. public $nextPageLabel = '&raquo;';
  70. /**
  71. * @var string|bool the text label for the "previous" page button. Note that this will NOT be HTML-encoded.
  72. * If this property is false, the "previous" page button will not be displayed.
  73. */
  74. public $prevPageLabel = '&laquo;';
  75. /**
  76. * @var string|bool the text label for the "first" page button. Note that this will NOT be HTML-encoded.
  77. * If it's specified as true, page number will be used as label.
  78. * Default is false that means the "first" page button will not be displayed.
  79. */
  80. public $firstPageLabel = false;
  81. /**
  82. * @var string|bool the text label for the "last" page button. Note that this will NOT be HTML-encoded.
  83. * If it's specified as true, page number will be used as label.
  84. * Default is false that means the "last" page button will not be displayed.
  85. */
  86. public $lastPageLabel = false;
  87. /**
  88. * @var bool whether to register link tags in the HTML header for prev, next, first and last page.
  89. * Defaults to `false` to avoid conflicts when multiple pagers are used on one page.
  90. * @see https://www.w3.org/TR/html401/struct/links.html#h-12.1.2
  91. * @see registerLinkTags()
  92. */
  93. public $registerLinkTags = false;
  94. /**
  95. * @var bool Hide widget when only one page exist.
  96. */
  97. public $hideOnSinglePage = true;
  98. /**
  99. * @var bool whether to render current page button as disabled.
  100. * @since 2.0.12
  101. */
  102. public $disableCurrentPageButton = false;
  103. public $linkOptions = [];
  104. function __construct($config = [])
  105. {
  106. $this->now = new \DateTime("now",new \DateTimeZone('Asia/Novosibirsk'));
  107. parent::__construct($config);
  108. }
  109. /**
  110. * Executes the widget.
  111. * This overrides the parent implementation by displaying the generated page buttons.
  112. */
  113. public function run()
  114. {
  115. echo $this->renderPageButtons();
  116. }
  117. /**
  118. * Renders the page buttons.
  119. * @return string the rendering result
  120. */
  121. protected function renderPageButtons()
  122. {
  123. $firstPost = $this->dataProvider->query->orderBy(['dt_pub'=>SORT_ASC])->limit(1)->one();
  124. if(!$firstPost instanceof News) return '';
  125. if($firstPost->dt_pub > $this->now->format('Y-m-d 00:00:00')) return '';
  126. $firstPostDateTime = new \DateTime($firstPost->dt_pub, new \DateTimeZone('Asia/Novosibirsk'));
  127. $pageCount = $this->now->diff($firstPostDateTime)->days;
  128. if ($pageCount < 2 && $this->hideOnSinglePage) {
  129. return '';
  130. }
  131. $buttons = [];
  132. $currentPage = \Yii::$app->request->get("page", $this->now->format("Y-m-d"));
  133. try{
  134. $currentPageDate = new \DateTime($currentPage);
  135. } catch (\Exception $exception){
  136. $currentPageDate = new \DateTime("now");
  137. }
  138. $pages = $this->getRealPages($currentPageDate,$this->dataProvider->query);
  139. $currentPageIndex = array_search($currentPageDate->format("Y-m-d"),array_column($pages,'dt_pub'));
  140. if(false === $currentPageIndex){
  141. $currentPageIndex = 0;
  142. $currentPageDate = new \DateTime(ArrayHelper::getValue($pages,"0.dt_pub","now"));
  143. }
  144. // prev page
  145. if ($this->prevPageLabel !== false) {
  146. if (($page = (clone $currentPageDate)->modify("+1 day"))->format("Y-m-d") > $this->now->format("Y-m-d")) {
  147. $page = clone $this->now;
  148. }
  149. $buttons[] = $this->renderPageButton($this->prevPageLabel, $page->format('Y-m-d'), $this->prevPageCssClass, $currentPage <= 0, false);
  150. }
  151. foreach ($pages as $page)
  152. {
  153. $date = new \DateTime($page['dt_pub']);
  154. $buttons[] = $this->renderPageButton($date->format('d.m'), $date->format('Y-m-d'), null, $this->disableCurrentPageButton && $date->format('Y-m-d') == $currentPage, $date->format('Y-m-d') == $currentPage);
  155. }
  156. // internal pages
  157. // list($beginPage, $endPage) = $this->getPageRange($currentPageDate->format("Y-m-d"), $firstPostDateTime);
  158. // $diff = $beginPage->diff($endPage)->days;
  159. // for ($i = 0; $i <= $diff; ++$i) {
  160. // $date = (clone $beginPage)->modify("-{$i} days");
  161. // if($date->format("Y") >= $this->now->format("Y")){
  162. // $internalLabel = $date->format('d.m');
  163. // } else {
  164. // $internalLabel = $date->format('d.m.y');
  165. // }
  166. // $buttons[] = $this->renderPageButton($internalLabel, $date->format('Y-m-d'), null, $this->disableCurrentPageButton && $date->format('Y-m-d') == $currentPage, $date->format('Y-m-d') == $currentPage);
  167. // }
  168. // next page
  169. if ($this->nextPageLabel !== false) {
  170. if (($page = (clone $currentPageDate)->modify("-1 day"))->format("Y-m-d") < $firstPostDateTime->format("Y-m-d")) {
  171. $page = clone ($firstPostDateTime);
  172. }
  173. $buttons[] = $this->renderPageButton($this->nextPageLabel, $page->format('Y-m-d'), $this->nextPageCssClass, $currentPage <= 0, false);
  174. }
  175. $options = $this->options;
  176. $tag = ArrayHelper::remove($options, 'tag', 'ul');
  177. return Html::tag($tag, implode("\n", $buttons), $options);
  178. }
  179. /**
  180. * Renders a page button.
  181. * You may override this method to customize the generation of page buttons.
  182. * @param string $label the text label for the button
  183. * @param int $page the page number
  184. * @param string $class the CSS class for the page button.
  185. * @param bool $disabled whether this page button is disabled
  186. * @param bool $active whether this page button is active
  187. * @return string the rendering result
  188. */
  189. protected function renderPageButton($label, $page, $class, $disabled, $active)
  190. {
  191. $options = $this->linkContainerOptions;
  192. $linkWrapTag = ArrayHelper::remove($options, 'tag', 'li');
  193. Html::addCssClass($options, empty($class) ? $this->pageCssClass : $class);
  194. if ($active) {
  195. Html::addCssClass($options, $this->activePageCssClass);
  196. }
  197. if ($disabled) {
  198. Html::addCssClass($options, $this->disabledPageCssClass);
  199. $disabledItemOptions = $this->disabledListItemSubTagOptions;
  200. $tag = ArrayHelper::remove($disabledItemOptions, 'tag', 'span');
  201. return Html::tag($linkWrapTag, Html::tag($tag, $label, $disabledItemOptions), $options);
  202. }
  203. $linkOptions = $this->linkOptions;
  204. $linkOptions['data-page'] = $page;
  205. return Html::tag($linkWrapTag, Html::a($label, $this->createUrl($page), $linkOptions), $options);
  206. }
  207. public function createUrl($page)
  208. {
  209. $url = parse_url(Url::to());
  210. return Url::to([ArrayHelper::getValue($url, "path","/"),"page"=>$page]);
  211. }
  212. /**
  213. * @return array the begin and end pages that need to be displayed.
  214. */
  215. protected function getPageRange($currentPage, \DateTime $firstPostDateTime)
  216. {
  217. $currentPageDate = new \DateTime($currentPage);
  218. $beginPage = min((new \DateTime("now"))->format("Y-m-d"), $currentPageDate->modify("+".($this->maxButtonCount / 2)." days")->format("Y-m-d"));
  219. $beginPageDate = new \DateTime($beginPage);
  220. if (($endPageDate = (clone $beginPageDate)->modify("-".($this->maxButtonCount - 1)." days")) <= $firstPostDateTime->format("Y-m-d")) {
  221. $endPageDate = $firstPostDateTime->modify("+1 day");
  222. $beginPageDate = (clone $endPageDate)->modify("+". ($this->maxButtonCount + 1)." days");
  223. }
  224. return [$beginPageDate, $endPageDate];
  225. }
  226. public $_realPages = false;
  227. public function getRealPages(\DateTime $currentPageDate, QueryInterface $query)
  228. {
  229. if($this->_realPages === false){
  230. $this->_realPages = $query
  231. ->select(["dt_pub"=>"Date(dt_pub)",'cnt'=>"count(*)"])
  232. ->andWhere("dt_pub < NOW()")
  233. ->andWhere(['<','dt_pub',$currentPageDate->format('Y-m-d 23:59:59')])
  234. ->groupBy("Date(dt_pub)")
  235. ->orderBy(["dt_pub"=>SORT_DESC])
  236. ->limit(10)
  237. ->asArray()
  238. ->all();
  239. }
  240. return $this->_realPages;
  241. }
  242. }