7c5f47247350d1d9e1dced18d2ae60286c448725
[Packages/TYPO3.CMS.git] / typo3 / sysext / fluid / Classes / ViewHelpers / Widget / Controller / PaginateController.php
1 <?php
2 namespace TYPO3\CMS\Fluid\ViewHelpers\Widget\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 use TYPO3\CMS\Core\Utility\ArrayUtility;
17 use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
18 use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
19 use TYPO3\CMS\Fluid\Core\Widget\AbstractWidgetController;
20
21 /**
22 * Class PaginateController
23 */
24 class PaginateController extends AbstractWidgetController
25 {
26 /**
27 * @var array
28 */
29 protected $configuration = [
30 'itemsPerPage' => 10,
31 'insertAbove' => false,
32 'insertBelow' => true,
33 'maximumNumberOfLinks' => 99,
34 'addQueryStringMethod' => '',
35 'section' => ''
36 ];
37
38 /**
39 * @var QueryResultInterface|ObjectStorage|array
40 */
41 protected $objects;
42
43 /**
44 * @var int
45 */
46 protected $currentPage = 1;
47
48 /**
49 * @var int
50 */
51 protected $maximumNumberOfLinks = 99;
52
53 /**
54 * @var int
55 */
56 protected $numberOfPages = 1;
57
58 /**
59 * @var int
60 */
61 protected $displayRangeStart = null;
62
63 /**
64 * @var int
65 */
66 protected $displayRangeEnd = null;
67
68 /**
69 * @return void
70 */
71 public function initializeAction()
72 {
73 $this->objects = $this->widgetConfiguration['objects'];
74 ArrayUtility::mergeRecursiveWithOverrule($this->configuration, $this->widgetConfiguration['configuration'], false);
75 $itemsPerPage = (int)$this->configuration['itemsPerPage'];
76 $this->numberOfPages = $itemsPerPage > 0 ? ceil(count($this->objects) / $itemsPerPage) : 0;
77 $this->maximumNumberOfLinks = (int)$this->configuration['maximumNumberOfLinks'];
78 }
79
80 /**
81 * @param int $currentPage
82 * @return void
83 */
84 public function indexAction($currentPage = 1)
85 {
86 // set current page
87 $this->currentPage = (int)$currentPage;
88 if ($this->currentPage < 1) {
89 $this->currentPage = 1;
90 }
91 if ($this->currentPage > $this->numberOfPages) {
92 // set $modifiedObjects to NULL if the page does not exist
93 $modifiedObjects = null;
94 } else {
95 // modify query
96 $itemsPerPage = (int)$this->configuration['itemsPerPage'];
97 $offset = 0;
98 if ($this->currentPage > 1) {
99 $offset = ((int)($itemsPerPage * ($this->currentPage - 1)));
100 }
101 $modifiedObjects = $this->prepareObjectsSlice($itemsPerPage, $offset);
102 }
103 $this->view->assign('contentArguments', [
104 $this->widgetConfiguration['as'] => $modifiedObjects
105 ]);
106 $this->view->assign('configuration', $this->configuration);
107 $this->view->assign('pagination', $this->buildPagination());
108 }
109
110 /**
111 * If a certain number of links should be displayed, adjust before and after
112 * amounts accordingly.
113 *
114 * @return void
115 */
116 protected function calculateDisplayRange()
117 {
118 $maximumNumberOfLinks = $this->maximumNumberOfLinks;
119 if ($maximumNumberOfLinks > $this->numberOfPages) {
120 $maximumNumberOfLinks = $this->numberOfPages;
121 }
122 $delta = floor($maximumNumberOfLinks / 2);
123 $this->displayRangeStart = $this->currentPage - $delta;
124 $this->displayRangeEnd = $this->currentPage + $delta - ($maximumNumberOfLinks % 2 === 0 ? 1 : 0);
125 if ($this->displayRangeStart < 1) {
126 $this->displayRangeEnd -= $this->displayRangeStart - 1;
127 }
128 if ($this->displayRangeEnd > $this->numberOfPages) {
129 $this->displayRangeStart -= $this->displayRangeEnd - $this->numberOfPages;
130 }
131 $this->displayRangeStart = (int)max($this->displayRangeStart, 1);
132 $this->displayRangeEnd = (int)min($this->displayRangeEnd, $this->numberOfPages);
133 }
134
135 /**
136 * Returns an array with the keys "pages", "current", "numberOfPages",
137 * "nextPage" & "previousPage"
138 *
139 * @return array
140 */
141 protected function buildPagination()
142 {
143 $this->calculateDisplayRange();
144 $pages = [];
145 for ($i = $this->displayRangeStart; $i <= $this->displayRangeEnd; $i++) {
146 $pages[] = ['number' => $i, 'isCurrent' => $i === $this->currentPage];
147 }
148 $pagination = [
149 'pages' => $pages,
150 'current' => $this->currentPage,
151 'numberOfPages' => $this->numberOfPages,
152 'displayRangeStart' => $this->displayRangeStart,
153 'displayRangeEnd' => $this->displayRangeEnd,
154 'hasLessPages' => $this->displayRangeStart > 2,
155 'hasMorePages' => $this->displayRangeEnd + 1 < $this->numberOfPages
156 ];
157 if ($this->currentPage < $this->numberOfPages) {
158 $pagination['nextPage'] = $this->currentPage + 1;
159 }
160 if ($this->currentPage > 1) {
161 $pagination['previousPage'] = $this->currentPage - 1;
162 }
163 return $pagination;
164 }
165
166 /**
167 * @param int $itemsPerPage
168 * @param int $offset
169 *
170 * @return array|QueryResultInterface
171 * @throws \InvalidArgumentException
172 */
173 protected function prepareObjectsSlice($itemsPerPage, $offset)
174 {
175 if ($this->objects instanceof QueryResultInterface) {
176 $query = $this->objects->getQuery();
177 $query->setLimit($itemsPerPage);
178 if ($offset > 0) {
179 $query->setOffset($offset);
180 }
181 $modifiedObjects = $query->execute();
182 return $modifiedObjects;
183 } elseif ($this->objects instanceof ObjectStorage) {
184 $modifiedObjects = [];
185 $endOfRange = $offset + $itemsPerPage;
186 for ($i = $offset; $i < $endOfRange; $i++) {
187 $modifiedObjects[] = $this->objects->toArray()[$i];
188 }
189 return $modifiedObjects;
190 } elseif (is_array($this->objects)) {
191 $modifiedObjects = array_slice($this->objects, $offset, $itemsPerPage);
192 return $modifiedObjects;
193 } else {
194 throw new \InvalidArgumentException('The view helper "' . get_class($this)
195 . '" accepts as argument "QueryResultInterface", "\SplObjectStorage", "ObjectStorage" or an array. '
196 . 'given: ' . get_class($this->objects), 1385547291
197 );
198 }
199 }
200 }