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