Completed
Push — 3.7 ( 81b2d8...ef0909 )
by
unknown
09:42
created

GridFieldPaginator   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 279
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 279
rs 9.52
c 0
b 0
f 0
wmc 36
lcom 1
cbo 6

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A setThrowExceptionOnBadDataType() 0 3 1
A getThrowExceptionOnBadDataType() 0 3 1
A checkDataType() 0 11 3
A getActions() 0 5 2
A handleAction() 0 9 3
A getGridPagerState() 0 8 1
A getManipulatedData() 0 22 5
F getTemplateParameters() 0 82 14
A getHTMLFragments() 0 10 2
A setItemsPerPage() 0 4 1
A getItemsPerPage() 0 3 1
1
<?php
2
/**
3
 * GridFieldPaginator paginates the {@link GridField} list and adds controls
4
 * to the bottom of the {@link GridField}.
5
 *
6
 * @package forms
7
 * @subpackage fields-gridfield
8
 */
9
class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider {
10
11
	/**
12
	 * Specifies default items per page
13
	 *
14
	 * @config
15
	 * @var int
16
	 */
17
	private static $default_items_per_page = 15;
18
19
	/**
20
	 * @var int
21
	 */
22
	protected $itemsPerPage;
23
24
	/**
25
	 * Which template to use for rendering
26
	 *
27
	 * @var string
28
	 */
29
	protected $itemClass = 'GridFieldPaginator_Row';
30
31
	/**
32
	 * See {@link setThrowExceptionOnBadDataType()}
33
	 */
34
	protected $throwExceptionOnBadDataType = true;
35
36
	/**
37
	 *
38
	 * @param int $itemsPerPage - How many items should be displayed per page
39
	 */
40
	public function __construct($itemsPerPage=null) {
41
		$this->itemsPerPage = $itemsPerPage
42
			?: Config::inst()->get('GridFieldPaginator', 'default_items_per_page');
43
	}
44
45
	/**
46
	 * Determine what happens when this component is used with a list that isn't {@link SS_Filterable}.
47
	 *
48
	 *  - true: An exception is thrown
49
	 *  - false: This component will be ignored - it won't make any changes to the GridField.
50
	 *
51
	 * By default, this is set to true so that it's clearer what's happening, but the predefined
52
	 * {@link GridFieldConfig} subclasses set this to false for flexibility.
53
	 */
54
	public function setThrowExceptionOnBadDataType($throwExceptionOnBadDataType) {
55
		$this->throwExceptionOnBadDataType = $throwExceptionOnBadDataType;
56
	}
57
58
	/**
59
	 * See {@link setThrowExceptionOnBadDataType()}
60
	 */
61
	public function getThrowExceptionOnBadDataType() {
62
		return $this->throwExceptionOnBadDataType;
63
	}
64
65
	/**
66
	 * Check that this dataList is of the right data type.
67
	 * Returns false if it's a bad data type, and if appropriate, throws an exception.
68
	 */
69
	protected function checkDataType($dataList) {
70
		if($dataList instanceof SS_Limitable) {
71
			return true;
72
		} else {
73
			if($this->throwExceptionOnBadDataType) {
74
				throw new LogicException(
75
					get_class($this) . " expects an SS_Limitable list to be passed to the GridField.");
76
			}
77
			return false;
78
		}
79
	}
80
81
	/**
82
	 *
83
	 * @param GridField $gridField
84
	 * @return array
85
	 */
86
	public function getActions($gridField) {
87
		if(!$this->checkDataType($gridField->getList())) return;
88
89
		return array('paginate');
90
	}
91
92
	/**
93
	 *
94
	 * @param GridField $gridField
95
	 * @param string $actionName
96
	 * @param string $arguments
97
	 * @param array $data
98
	 * @return void
99
	 */
100
	public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
101
		if(!$this->checkDataType($gridField->getList())) return;
102
103
		if($actionName !== 'paginate') {
104
			return;
105
		}
106
		$state = $this->getGridPagerState($gridField);
107
		$state->currentPage = (int)$arguments;
0 ignored issues
show
Documentation introduced by
The property currentPage does not exist on object<GridState_Data>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
108
	}
109
110
	protected $totalItems = 0;
111
112
	/**
113
	 * Retrieves/Sets up the state object used to store and retrieve information
114
	 * about the current paging details of this GridField
115
	 * @param GridField $gridField
116
	 * @return GridState_Data
117
	 */
118
	protected function getGridPagerState(GridField $gridField) {
119
		$state = $gridField->State->GridFieldPaginator;
0 ignored issues
show
Documentation introduced by
The property GridFieldPaginator does not exist on object<GridState_Data>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
120
121
		// Force the state to the initial page if none is set
122
		$state->currentPage(1);
123
124
		return $state;
125
	}
126
127
	/**
128
	 *
129
	 * @param GridField $gridField
130
	 * @param SS_List $dataList
131
	 * @return SS_List
132
	 */
133
	public function getManipulatedData(GridField $gridField, SS_List $dataList) {
134
		if(!$this->checkDataType($dataList)) return $dataList;
135
136
		$state = $this->getGridPagerState($gridField);
137
138
		// Update item count prior to filter. GridFieldPageCount will rely on this value
139
		$this->totalItems = $dataList->count();
140
141
		$startRow = $this->itemsPerPage * ($state->currentPage - 1);
142
143
		// Prevent visiting a page with an offset higher than the total number of items
144
		if($startRow >= $this->totalItems) {
145
			$state->currentPage = 1;
0 ignored issues
show
Documentation introduced by
The property currentPage does not exist on object<GridState_Data>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
146
			$startRow = 0;
147
		}
148
149
		if(!($dataList instanceof SS_Limitable) || ($dataList instanceof UnsavedRelationList)) {
150
			return $dataList;
151
		}
152
153
		return $dataList->limit((int)$this->itemsPerPage, (int)$startRow);
154
	}
155
156
	/**
157
	 * Determines arguments to be passed to the template for building this field
158
	 * @return ArrayData|null If paging is available this will be an ArrayData
159
	 * object of paging details with these parameters:
160
	 * <ul>
161
	 *	<li>OnlyOnePage:				boolean - Is there only one page?</li>
162
	 *  <li>FirstShownRecord:			integer - Number of the first record displayed</li>
163
	 *  <li>LastShownRecord:			integer - Number of the last record displayed</li>
164
	 *  <li>NumRecords:					integer - Total number of records</li>
165
	 *	<li>NumPages:					integer - The number of pages</li>
166
	 *	<li>CurrentPageNum (optional):	integer - If OnlyOnePage is false, the number of the current page</li>
167
	 *  <li>FirstPage (optional):		GridField_FormAction - Button to go to the first page</li>
168
	 *	<li>PreviousPage (optional):	GridField_FormAction - Button to go to the previous page</li>
169
	 *	<li>NextPage (optional):		GridField_FormAction - Button to go to the next page</li>
170
	 *	<li>LastPage (optional):		GridField_FormAction - Button to go to last page</li>
171
	 * </ul>
172
	 */
173
	public function getTemplateParameters(GridField $gridField) {
174
		if(!$this->checkDataType($gridField->getList())) return null;
175
176
		$state = $this->getGridPagerState($gridField);
177
178
		// Figure out which page and record range we're on
179
		$totalRows = $this->totalItems;
180
		if(!$totalRows) return null;
181
182
		$totalPages = 1;
183
		$firstShownRecord = 1;
184
		$lastShownRecord = $totalRows;
185
		if ($itemsPerPage = $this->getItemsPerPage()) {
186
			$totalPages = (int)ceil($totalRows / $itemsPerPage);
187
			if ($totalPages == 0) {
188
				$totalPages = 1;
189
			}
190
			$firstShownRecord = ($state->currentPage - 1) * $itemsPerPage + 1;
191
			if ($firstShownRecord > $totalRows) {
192
				$firstShownRecord = $totalRows;
193
			}
194
			$lastShownRecord = $state->currentPage * $itemsPerPage;
195
			if ($lastShownRecord > $totalRows) {
196
				$lastShownRecord = $totalRows;
197
			}
198
		}
199
200
		// If there is only 1 page for all the records in list, we don't need to go further
201
		// to sort out those first page, last page, pre and next pages, etc
202
		// we are not render those in to the paginator.
203
		if($totalPages === 1){
204
			return new ArrayData(array(
205
				'OnlyOnePage' => true,
206
				'FirstShownRecord' => $firstShownRecord,
207
				'LastShownRecord' => $lastShownRecord,
208
				'NumRecords' => $totalRows,
209
				'NumPages' => $totalPages
210
			));
211
		} else {
212
			// First page button
213
			$firstPage = new GridField_FormAction($gridField, 'pagination_first', 'First', 'paginate', 1);
214
			$firstPage->addExtraClass('ss-gridfield-firstpage');
215
			if($state->currentPage == 1)
216
				$firstPage = $firstPage->performDisabledTransformation();
217
218
			// Previous page button
219
			$previousPageNum = $state->currentPage <= 1 ? 1 : $state->currentPage - 1;
220
			$previousPage = new GridField_FormAction($gridField, 'pagination_prev', 'Previous',
221
				'paginate', $previousPageNum);
222
			$previousPage->addExtraClass('ss-gridfield-previouspage');
223
			if($state->currentPage == 1)
224
				$previousPage = $previousPage->performDisabledTransformation();
225
226
			// Next page button
227
			$nextPageNum = $state->currentPage >= $totalPages ? $totalPages : $state->currentPage + 1;
228
			$nextPage = new GridField_FormAction($gridField, 'pagination_next', 'Next',
229
				'paginate', $nextPageNum);
230
			$nextPage->addExtraClass('ss-gridfield-nextpage');
231
			if($state->currentPage == $totalPages)
232
				$nextPage = $nextPage->performDisabledTransformation();
233
234
			// Last page button
235
			$lastPage = new GridField_FormAction($gridField, 'pagination_last', 'Last', 'paginate', $totalPages);
236
			$lastPage->addExtraClass('ss-gridfield-lastpage');
237
			if($state->currentPage == $totalPages)
238
				$lastPage = $lastPage->performDisabledTransformation();
239
240
			// Render in template
241
			return new ArrayData(array(
242
				'OnlyOnePage' => false,
243
				'FirstPage' => $firstPage,
244
				'PreviousPage' => $previousPage,
245
				'CurrentPageNum' => $state->currentPage,
246
				'NumPages' => $totalPages,
247
				'NextPage' => $nextPage,
248
				'LastPage' => $lastPage,
249
				'FirstShownRecord' => $firstShownRecord,
250
				'LastShownRecord' => $lastShownRecord,
251
				'NumRecords' => $totalRows
252
			));
253
		}
254
	}
255
256
	/**
257
	 *
258
	 * @param GridField $gridField
259
	 * @return array
260
	 */
261
	public function getHTMLFragments($gridField) {
262
263
		$forTemplate = $this->getTemplateParameters($gridField);
264
		if($forTemplate) {
265
			return array(
266
				'footer' => $forTemplate->renderWith($this->itemClass,
267
					array('Colspan'=>count($gridField->getColumns())))
268
			);
269
		}
270
	}
271
272
	/**
273
	 * @param Int
274
	 */
275
	public function setItemsPerPage($num) {
276
		$this->itemsPerPage = $num;
277
		return $this;
278
	}
279
280
	/**
281
	 * @return Int
282
	 */
283
	public function getItemsPerPage() {
284
		return $this->itemsPerPage;
285
	}
286
287
}
288