Test Failed
Branch master (206474)
by Fabio
18:24
created

TDataList::setHeaderTemplate()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 8
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 2
nop 1
dl 8
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * TDataList class file
4
 *
5
 * @author Qiang Xue <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @copyright Copyright &copy; 2005-2016 The PRADO Group
8
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
9
 * @package Prado\Web\UI\WebControls
10
 */
11
12
namespace Prado\Web\UI\WebControls;
13
14
use Prado\Exceptions\TInvalidOperationException;
15
use Prado\Prado;
16
use Prado\TPropertyValue;
17
use Prado\Exceptions\TInvalidDataValueException;
18
use Prado\Exceptions\TInvalidDataTypeException;
19
use Prado\Web\UI\ITemplate;
20
21
/**
22
 * TDataList class
23
 *
24
 * TDataList represents a data bound and updatable list control.
25
 *
26
 * Like {@link TRepeater}, TDataList displays its content repeatedly based on
27
 * the data fetched from {@link setDataSource DataSource}.
28
 * The repeated contents in TDataList are called items, which are controls and
29
 * can be accessed through {@link getItems Items}. When {@link dataBind()} is
30
 * invoked, TDataList creates an item for each row of data and binds the data
31
 * row to the item. Optionally, a TDataList can have a header, a footer and/or
32
 * separators between items.
33
 *
34
 * TDataList differs from {@link TRepeater} in that it supports tiling the items
35
 * in different manners and it maintains status of items to handle data update.
36
 *
37
 * The layout of the repeated contents are specified by inline templates.
38
 * TDataList items, header, footer, etc. are being instantiated with the corresponding
39
 * templates when data is being bound to the repeater.
40
 *
41
 * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
42
 * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
43
 * as an external template (in fact, it can also be non-templated controls).
44
 *
45
 * A renderer can be any control class.
46
 * - If the class implements {@link \Prado\IDataRenderer}, the <b>Data</b>
47
 * property will be set as the data row during databinding. Many PRADO controls
48
 * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
49
 * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
50
 * as the zero-based index of the item in the datalist item collection, and
51
 * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
52
 * {@link TDataListItemRenderer} may be used as the convenient base class which
53
 * already implements {@link IDataItemRenderer}.
54
 *
55
 * The following properties are used to specify different types of template and renderer
56
 * for a datalist:
57
 * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
58
 * for each repeated row of data
59
 * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
60
 * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
61
 * will be used instead.
62
 * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
63
 * for the datalist header.
64
 * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
65
 * for the datalist footer.
66
 * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
67
 * for content to be displayed between items.
68
 * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
69
 * used when data bound to the datalist is empty.
70
 * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
71
 * for the row being editted.
72
 * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
73
 * for the row being selected.
74
 *
75
 * If a content type is defined with both a template and a renderer, the latter takes precedence.
76
 *
77
 * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
78
 * - create item based on templates or renderers
79
 * - set the row of data to the item
80
 * - raise {@link onItemCreated OnItemCreated}:
81
 * - add the item as a child control
82
 * - call dataBind() of the item
83
 * - raise {@link onItemDataBound OnItemDataBound}:
84
 *
85
 * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
86
 * within some datalist item raises a <b>OnCommand</b> event. Therefore,
87
 * you can handle all sorts of <b>OnCommand</b> event in a central place by
88
 * writing an event handler for {@link onItemCommand OnItemCommand}.
89
 *
90
 * An additional event is raised if the <b>OnCommand</b> event has one of the following
91
 * command names:
92
 * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
93
 * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
94
 * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
95
 * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
96
 * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
97
 *
98
 * TDataList provides a few properties to support tiling the items.
99
 * The number of columns used to display the data items is specified via
100
 * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
101
 * governs the order of the items being rendered.
102
 * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
103
 * which can take one of the following values:
104
 * - Table (default): items are organized using HTML table and cells.
105
 * When using this layout, one can set {@link setCellPadding CellPadding} and
106
 * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
107
 * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
108
 * to add a table caption with the specified alignment.
109
 * - Flow: items are organized using HTML spans and breaks.
110
 * - Raw: TDataList does not generate any HTML tags to do the tiling.
111
 *
112
 * Items in TDataList can be in one of the three status: normal browsing,
113
 * being editted and being selected. To change the status of a particular
114
 * item, set {@link setSelectedItemIndex SelectedItemIndex} or
115
 * {@link setEditItemIndex EditItemIndex}. The former will change
116
 * the indicated item to selected mode, which will cause the item to
117
 * use {@link setSelectedItemTemplate SelectedItemTemplate} or
118
 * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
119
 * The latter will change the indicated item to edit mode and to use corresponding
120
 * template or renderer.
121
 * Note, if an item is in edit mode, then selecting this item will have no effect.
122
 *
123
 * Different styles may be applied to items in different status. The style
124
 * application is performed in a hierarchical way: Style in higher hierarchy
125
 * will inherit from styles in lower hierarchy.
126
 * Starting from the lowest hierarchy, the item styles include
127
 * - item's own style
128
 * - {@link getItemStyle ItemStyle}
129
 * - {@link getAlternatingItemStyle AlternatingItemStyle}
130
 * - {@link getSelectedItemStyle SelectedItemStyle}
131
 * - {@link getEditItemStyle EditItemStyle}.
132
 * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
133
 * {@link getEditItemStyle EditItemStyle} will also have red background color
134
 * unless it is set to a different value explicitly.
135
 *
136
 * When a page containing a datalist is post back, the datalist will restore automatically
137
 * all its contents, including items, header, footer and separators.
138
 * However, the data row associated with each item will not be recovered and become null.
139
 * To access the data, use one of the following ways:
140
 * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
141
 * the specified datalist item and use the key to fetch the corresponding data
142
 * from some persistent storage such as DB.
143
 * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
144
 * Be aware though, if the size of your dataset is big, your page size will become big. Some
145
 * complex data may also have serializing problem if saved in viewstate.
146
 *
147
 * @author Qiang Xue <[email protected]>
148
 * @package Prado\Web\UI\WebControls
149
 * @since 3.0
150
 */
151
class TDataList extends TBaseDataList implements \Prado\Web\UI\INamingContainer, IRepeatInfoUser
152
{
153
	/**
154
	 * Command name that TDataList understands. They are case-insensitive.
155
	 */
156
	const CMD_SELECT = 'Select';
157
	const CMD_EDIT = 'Edit';
158
	const CMD_UPDATE = 'Update';
159
	const CMD_DELETE = 'Delete';
160
	const CMD_CANCEL = 'Cancel';
161
162
	/**
163
	 * @var TDataListItemCollection item list
164
	 */
165
	private $_items;
166
	/**
167
	 * @var Itemplate various item templates
168
	 */
169
	private $_itemTemplate;
170
	private $_emptyTemplate;
171
	private $_alternatingItemTemplate;
172
	private $_selectedItemTemplate;
173
	private $_editItemTemplate;
174
	private $_headerTemplate;
175
	private $_footerTemplate;
176
	private $_separatorTemplate;
177
	/**
178
	 * @var TControl header item
179
	 */
180
	private $_header;
181
	/**
182
	 * @var TControl footer item
183
	 */
184
	private $_footer;
185
186
	/**
187
	 * @return TDataListItemCollection item list
188
	 */
189
	public function getItems()
190
	{
191
		if (!$this->_items) {
192
			$this->_items = new TDataListItemCollection;
193
		}
194
		return $this->_items;
195
	}
196
197
	/**
198
	 * @return int number of items
199
	 */
200
	public function getItemCount()
201
	{
202
		return $this->_items ? $this->_items->getCount() : 0;
203
	}
204
205
	/**
206
	 * @return string the class name for datalist items. Defaults to empty, meaning not set.
207
	 * @since 3.1.0
208
	 */
209
	public function getItemRenderer()
210
	{
211
		return $this->getViewState('ItemRenderer', '');
212
	}
213
214
	/**
215
	 * Sets the item renderer class.
216
	 *
217
	 * If not empty, the class will be used to instantiate as datalist items.
218
	 * This property takes precedence over {@link getItemTemplate ItemTemplate}.
219
	 *
220
	 * @param string $value the renderer class name in namespace format.
221
	 * @see setItemTemplate
222
	 * @since 3.1.0
223
	 */
224
	public function setItemRenderer($value)
225
	{
226
		$this->setViewState('ItemRenderer', $value, '');
227
	}
228
229
	/**
230
	 * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
231
	 * @since 3.1.0
232
	 */
233
	public function getAlternatingItemRenderer()
234
	{
235
		return $this->getViewState('AlternatingItemRenderer', '');
236
	}
237
238
	/**
239
	 * Sets the alternative item renderer class.
240
	 *
241
	 * If not empty, the class will be used to instantiate as alternative datalist items.
242
	 * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
243
	 *
244
	 * @param string $value the renderer class name in namespace format.
245
	 * @param mixed $value
246
	 * @see setAlternatingItemTemplate
247
	 * @since 3.1.0
248
	 */
249
	public function setAlternatingItemRenderer($value)
250
	{
251
		$this->setViewState('AlternatingItemRenderer', $value, '');
252
	}
253
254
	/**
255
	 * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
256
	 * @since 3.1.0
257
	 */
258
	public function getEditItemRenderer()
259
	{
260
		return $this->getViewState('EditItemRenderer', '');
261
	}
262
263
	/**
264
	 * Sets the renderer class for the datalist item being editted.
265
	 *
266
	 * If not empty, the class will be used to instantiate as the datalist item.
267
	 * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
268
	 *
269
	 * @param string $value the renderer class name in namespace format.
270
	 * @see setEditItemTemplate
271
	 * @since 3.1.0
272
	 */
273
	public function setEditItemRenderer($value)
274
	{
275
		$this->setViewState('EditItemRenderer', $value, '');
276
	}
277
278
	/**
279
	 * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
280
	 * @since 3.1.0
281
	 */
282
	public function getSelectedItemRenderer()
283
	{
284
		return $this->getViewState('SelectedItemRenderer', '');
285
	}
286
287
	/**
288
	 * Sets the renderer class for the datalist item being selected.
289
	 *
290
	 * If not empty, the class will be used to instantiate as the datalist item.
291
	 * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
292
	 *
293
	 * @param string $value the renderer class name in namespace format.
294
	 * @see setSelectedItemTemplate
295
	 * @since 3.1.0
296
	 */
297
	public function setSelectedItemRenderer($value)
298
	{
299
		$this->setViewState('SelectedItemRenderer', $value, '');
300
	}
301
302
	/**
303
	 * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
304
	 * @since 3.1.0
305
	 */
306
	public function getSeparatorRenderer()
307
	{
308
		return $this->getViewState('SeparatorRenderer', '');
309
	}
310
311
	/**
312
	 * Sets the datalist item separator renderer class.
313
	 *
314
	 * If not empty, the class will be used to instantiate as datalist item separators.
315
	 * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
316
	 *
317
	 * @param string $value the renderer class name in namespace format.
318
	 * @see setSeparatorTemplate
319
	 * @since 3.1.0
320
	 */
321
	public function setSeparatorRenderer($value)
322
	{
323
		$this->setViewState('SeparatorRenderer', $value, '');
324
	}
325
326
	/**
327
	 * @return string the class name for datalist header item. Defaults to empty, meaning not set.
328
	 * @since 3.1.0
329
	 */
330
	public function getHeaderRenderer()
331
	{
332
		return $this->getViewState('HeaderRenderer', '');
333
	}
334
335
	/**
336
	 * Sets the datalist header renderer class.
337
	 *
338
	 * If not empty, the class will be used to instantiate as datalist header item.
339
	 * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
340
	 *
341
	 * @param string $value the renderer class name in namespace format.
342
	 * @see setHeaderTemplate
343
	 * @since 3.1.0
344
	 */
345
	public function setHeaderRenderer($value)
346
	{
347
		$this->setViewState('HeaderRenderer', $value, '');
348
	}
349
350
	/**
351
	 * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
352
	 * @since 3.1.0
353
	 */
354
	public function getFooterRenderer()
355
	{
356
		return $this->getViewState('FooterRenderer', '');
357
	}
358
359
	/**
360
	 * Sets the datalist footer renderer class.
361
	 *
362
	 * If not empty, the class will be used to instantiate as datalist footer item.
363
	 * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
364
	 *
365
	 * @param string $value the renderer class name in namespace format.
366
	 * @see setFooterTemplate
367
	 * @since 3.1.0
368
	 */
369
	public function setFooterRenderer($value)
370
	{
371
		$this->setViewState('FooterRenderer', $value, '');
372
	}
373
374
	/**
375
	 * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
376
	 * @since 3.1.0
377
	 */
378
	public function getEmptyRenderer()
379
	{
380
		return $this->getViewState('EmptyRenderer', '');
381
	}
382
383
	/**
384
	 * Sets the datalist empty renderer class.
385
	 *
386
	 * The empty renderer is created as the child of the datalist
387
	 * if data bound to the datalist is empty.
388
	 * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
389
	 *
390
	 * @param string $value the renderer class name in namespace format.
391
	 * @see setEmptyTemplate
392
	 * @since 3.1.0
393
	 */
394
	public function setEmptyRenderer($value)
395
	{
396
		$this->setViewState('EmptyRenderer', $value, '');
397
	}
398
399
	/**
400
	 * @return ITemplate the template for item
401
	 */
402
	public function getItemTemplate()
403
	{
404
		return $this->_itemTemplate;
405
	}
406
407
	/**
408
	 * @param ITemplate $value the template for item
409
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
410
	 */
411 View Code Duplication
	public function setItemTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
412
	{
413
		if ($value instanceof ITemplate || $value === null) {
414
			$this->_itemTemplate = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type object<Prado\Web\UI\ITemplate> is incompatible with the declared type object<Prado\Web\UI\WebControls\Itemplate> of property $_itemTemplate.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
415
		} else {
416
			throw new TInvalidDataTypeException('datalist_template_required', 'ItemTemplate');
417
		}
418
	}
419
420
	/**
421
	 * @return TTableItemStyle the style for item
422
	 */
423 View Code Duplication
	public function getItemStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
424
	{
425
		if (($style = $this->getViewState('ItemStyle', null)) === null) {
426
			$style = new TTableItemStyle;
427
			$this->setViewState('ItemStyle', $style, null);
428
		}
429
		return $style;
430
	}
431
432
	/**
433
	 * @return ITemplate the template for each alternating item
434
	 */
435
	public function getAlternatingItemTemplate()
436
	{
437
		return $this->_alternatingItemTemplate;
438
	}
439
440
	/**
441
	 * @param ITemplate $value the template for each alternating item
442
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
443
	 */
444
	public function setAlternatingItemTemplate($value)
445
	{
446
		if ($value instanceof ITemplate || $value === null) {
447
			$this->_alternatingItemTemplate = $value;
448
		} else {
449
			throw new TInvalidDataTypeException('datalist_template_required', 'AlternatingItemType');
450
		}
451
	}
452
453
	/**
454
	 * @return TTableItemStyle the style for each alternating item
455
	 */
456 View Code Duplication
	public function getAlternatingItemStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
457
	{
458
		if (($style = $this->getViewState('AlternatingItemStyle', null)) === null) {
459
			$style = new TTableItemStyle;
460
			$this->setViewState('AlternatingItemStyle', $style, null);
461
		}
462
		return $style;
463
	}
464
465
	/**
466
	 * @return ITemplate the selected item template
467
	 */
468
	public function getSelectedItemTemplate()
469
	{
470
		return $this->_selectedItemTemplate;
471
	}
472
473
	/**
474
	 * @param ITemplate $value the selected item template
475
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
476
	 */
477
	public function setSelectedItemTemplate($value)
478
	{
479
		if ($value instanceof ITemplate || $value === null) {
480
			$this->_selectedItemTemplate = $value;
481
		} else {
482
			throw new TInvalidDataTypeException('datalist_template_required', 'SelectedItemTemplate');
483
		}
484
	}
485
486
	/**
487
	 * @return TTableItemStyle the style for selected item
488
	 */
489 View Code Duplication
	public function getSelectedItemStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
490
	{
491
		if (($style = $this->getViewState('SelectedItemStyle', null)) === null) {
492
			$style = new TTableItemStyle;
493
			$this->setViewState('SelectedItemStyle', $style, null);
494
		}
495
		return $style;
496
	}
497
498
	/**
499
	 * @return ITemplate the edit item template
500
	 */
501
	public function getEditItemTemplate()
502
	{
503
		return $this->_editItemTemplate;
504
	}
505
506
	/**
507
	 * @param ITemplate $value the edit item template
508
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
509
	 */
510 View Code Duplication
	public function setEditItemTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
511
	{
512
		if ($value instanceof ITemplate || $value === null) {
513
			$this->_editItemTemplate = $value;
514
		} else {
515
			throw new TInvalidDataTypeException('datalist_template_required', 'EditItemTemplate');
516
		}
517
	}
518
519
	/**
520
	 * @return TTableItemStyle the style for edit item
521
	 */
522 View Code Duplication
	public function getEditItemStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
523
	{
524
		if (($style = $this->getViewState('EditItemStyle', null)) === null) {
525
			$style = new TTableItemStyle;
526
			$this->setViewState('EditItemStyle', $style, null);
527
		}
528
		return $style;
529
	}
530
531
	/**
532
	 * @return ITemplate the header template
533
	 */
534
	public function getHeaderTemplate()
535
	{
536
		return $this->_headerTemplate;
537
	}
538
539
	/**
540
	 * @param ITemplate $value the header template
541
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
542
	 */
543 View Code Duplication
	public function setHeaderTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
544
	{
545
		if ($value instanceof ITemplate || $value === null) {
546
			$this->_headerTemplate = $value;
547
		} else {
548
			throw new TInvalidDataTypeException('datalist_template_required', 'HeaderTemplate');
549
		}
550
	}
551
552
	/**
553
	 * @return TTableItemStyle the style for header
554
	 */
555 View Code Duplication
	public function getHeaderStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
556
	{
557
		if (($style = $this->getViewState('HeaderStyle', null)) === null) {
558
			$style = new TTableItemStyle;
559
			$this->setViewState('HeaderStyle', $style, null);
560
		}
561
		return $style;
562
	}
563
564
	/**
565
	 * @return TControl the header item
566
	 */
567
	public function getHeader()
568
	{
569
		return $this->_header;
570
	}
571
572
	/**
573
	 * @return ITemplate the footer template
574
	 */
575
	public function getFooterTemplate()
576
	{
577
		return $this->_footerTemplate;
578
	}
579
580
	/**
581
	 * @param ITemplate $value the footer template
582
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
583
	 */
584 View Code Duplication
	public function setFooterTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
585
	{
586
		if ($value instanceof ITemplate || $value === null) {
587
			$this->_footerTemplate = $value;
588
		} else {
589
			throw new TInvalidDataTypeException('datalist_template_required', 'FooterTemplate');
590
		}
591
	}
592
593
	/**
594
	 * @return TTableItemStyle the style for footer
595
	 */
596 View Code Duplication
	public function getFooterStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
597
	{
598
		if (($style = $this->getViewState('FooterStyle', null)) === null) {
599
			$style = new TTableItemStyle;
600
			$this->setViewState('FooterStyle', $style, null);
601
		}
602
		return $style;
603
	}
604
605
	/**
606
	 * @return TControl the footer item
607
	 */
608
	public function getFooter()
609
	{
610
		return $this->_footer;
611
	}
612
613
	/**
614
	 * @return ITemplate the template applied when no data is bound to the datalist
615
	 */
616
	public function getEmptyTemplate()
617
	{
618
		return $this->_emptyTemplate;
619
	}
620
621
	/**
622
	 * @param ITemplate $value the template applied when no data is bound to the datalist
623
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
624
	 */
625 View Code Duplication
	public function setEmptyTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
626
	{
627
		if ($value instanceof ITemplate || $value === null) {
628
			$this->_emptyTemplate = $value;
629
		} else {
630
			throw new TInvalidDataTypeException('datalist_template_required', 'EmptyTemplate');
631
		}
632
	}
633
634
	/**
635
	 * @return ITemplate the separator template
636
	 */
637
	public function getSeparatorTemplate()
638
	{
639
		return $this->_separatorTemplate;
640
	}
641
642
	/**
643
	 * @param ITemplate $value the separator template
644
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
645
	 */
646 View Code Duplication
	public function setSeparatorTemplate($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
647
	{
648
		if ($value instanceof ITemplate || $value === null) {
649
			$this->_separatorTemplate = $value;
650
		} else {
651
			throw new TInvalidDataTypeException('datalist_template_required', 'SeparatorTemplate');
652
		}
653
	}
654
655
	/**
656
	 * @return TTableItemStyle the style for separator
657
	 */
658 View Code Duplication
	public function getSeparatorStyle()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
659
	{
660
		if (($style = $this->getViewState('SeparatorStyle', null)) === null) {
661
			$style = new TTableItemStyle;
662
			$this->setViewState('SeparatorStyle', $style, null);
663
		}
664
		return $style;
665
	}
666
667
	/**
668
	 * @return int the zero-based index of the selected item in {@link getItems Items}.
669
	 * A value -1 means no item selected.
670
	 */
671
	public function getSelectedItemIndex()
672
	{
673
		return $this->getViewState('SelectedItemIndex', -1);
674
	}
675
676
	/**
677
	 * Selects an item by its index in {@link getItems Items}.
678
	 * Previously selected item will be un-selected.
679
	 * If the item to be selected is already in edit mode, it will remain in edit mode.
680
	 * If the index is less than 0, any existing selection will be cleared up.
681
	 * @param int $value the selected item index
682
	 */
683
	public function setSelectedItemIndex($value)
684
	{
685
		if (($value = TPropertyValue::ensureInteger($value)) < 0) {
686
			$value = -1;
687
		}
688
		if (($current = $this->getSelectedItemIndex()) !== $value) {
689
			$this->setViewState('SelectedItemIndex', $value, -1);
690
			$items = $this->getItems();
691
			$itemCount = $items->getCount();
692 View Code Duplication
			if ($current >= 0 && $current < $itemCount) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
693
				$item = $items->itemAt($current);
694
				if (($item instanceof IItemDataRenderer) && $item->getItemType() !== TListItemType::EditItem) {
695
					$item->setItemType($current % 2 ? TListItemType::AlternatingItem : TListItemType::Item);
696
				}
697
			}
698 View Code Duplication
			if ($value >= 0 && $value < $itemCount) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
699
				$item = $items->itemAt($value);
700
				if (($item instanceof IItemDataRenderer) && $item->getItemType() !== TListItemType::EditItem) {
701
					$item->setItemType(TListItemType::SelectedItem);
702
				}
703
			}
704
		}
705
	}
706
707
	/**
708
	 * @return TControl the selected item, null if no item is selected.
709
	 */
710 View Code Duplication
	public function getSelectedItem()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
711
	{
712
		$index = $this->getSelectedItemIndex();
713
		$items = $this->getItems();
714
		if ($index >= 0 && $index < $items->getCount()) {
715
			return $items->itemAt($index);
716
		} else {
717
			return null;
718
		}
719
	}
720
721
	/**
722
	 * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
723
	 * @return mixed the key value of the currently selected item
724
	 */
725
	public function getSelectedDataKey()
726
	{
727
		if ($this->getDataKeyField() === '') {
728
			throw new TInvalidOperationException('datalist_datakeyfield_required');
729
		}
730
		$index = $this->getSelectedItemIndex();
731
		$dataKeys = $this->getDataKeys();
732
		if ($index >= 0 && $index < $dataKeys->getCount()) {
733
			return $dataKeys->itemAt($index);
734
		} else {
735
			return null;
736
		}
737
	}
738
739
	/**
740
	 * @return int the zero-based index of the edit item in {@link getItems Items}.
741
	 * A value -1 means no item is in edit mode.
742
	 */
743
	public function getEditItemIndex()
744
	{
745
		return $this->getViewState('EditItemIndex', -1);
746
	}
747
748
	/**
749
	 * Edits an item by its index in {@link getItems Items}.
750
	 * Previously editting item will change to normal item state.
751
	 * If the index is less than 0, any existing edit item will be cleared up.
752
	 * @param int $value the edit item index
753
	 */
754 View Code Duplication
	public function setEditItemIndex($value)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
755
	{
756
		if (($value = TPropertyValue::ensureInteger($value)) < 0) {
757
			$value = -1;
758
		}
759
		if (($current = $this->getEditItemIndex()) !== $value) {
760
			$this->setViewState('EditItemIndex', $value, -1);
761
			$items = $this->getItems();
762
			$itemCount = $items->getCount();
763
			if ($current >= 0 && $current < $itemCount) {
764
				$items->itemAt($current)->setItemType($current % 2 ? TListItemType::AlternatingItem : TListItemType::Item);
765
			}
766
			if ($value >= 0 && $value < $itemCount) {
767
				$items->itemAt($value)->setItemType(TListItemType::EditItem);
768
			}
769
		}
770
	}
771
772
	/**
773
	 * @return TControl the edit item
774
	 */
775 View Code Duplication
	public function getEditItem()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
776
	{
777
		$index = $this->getEditItemIndex();
778
		$items = $this->getItems();
779
		if ($index >= 0 && $index < $items->getCount()) {
780
			return $items->itemAt($index);
781
		} else {
782
			return null;
783
		}
784
	}
785
786
	/**
787
	 * @return bool whether the header should be shown. Defaults to true.
788
	 */
789
	public function getShowHeader()
790
	{
791
		return $this->getViewState('ShowHeader', true);
792
	}
793
794
	/**
795
	 * @param bool $value whether to show header
796
	 */
797
	public function setShowHeader($value)
798
	{
799
		$this->setViewState('ShowHeader', TPropertyValue::ensureBoolean($value), true);
800
	}
801
802
	/**
803
	 * @return bool whether the footer should be shown. Defaults to true.
804
	 */
805
	public function getShowFooter()
806
	{
807
		return $this->getViewState('ShowFooter', true);
808
	}
809
810
	/**
811
	 * @param bool $value whether to show footer
812
	 */
813
	public function setShowFooter($value)
814
	{
815
		$this->setViewState('ShowFooter', TPropertyValue::ensureBoolean($value), true);
816
	}
817
818
	/**
819
	 * @return TRepeatInfo repeat information (primarily used by control developers)
820
	 */
821 View Code Duplication
	protected function getRepeatInfo()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
822
	{
823
		if (($repeatInfo = $this->getViewState('RepeatInfo', null)) === null) {
824
			$repeatInfo = new TRepeatInfo;
825
			$this->setViewState('RepeatInfo', $repeatInfo, null);
826
		}
827
		return $repeatInfo;
828
	}
829
830
	/**
831
	 * @return string caption of the table layout
832
	 */
833
	public function getCaption()
834
	{
835
		return $this->getRepeatInfo()->getCaption();
836
	}
837
838
	/**
839
	 * @param string $value caption of the table layout
840
	 */
841
	public function setCaption($value)
842
	{
843
		$this->getRepeatInfo()->setCaption($value);
844
	}
845
846
	/**
847
	 * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
848
	 */
849
	public function getCaptionAlign()
850
	{
851
		return $this->getRepeatInfo()->getCaptionAlign();
852
	}
853
854
	/**
855
	 * @param mixed $value
856
	 * @return TTableCaptionAlign alignment of the caption of the table layout.
857
	 */
858
	public function setCaptionAlign($value)
859
	{
860
		$this->getRepeatInfo()->setCaptionAlign($value);
861
	}
862
863
	/**
864
	 * @return int the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
865
	 */
866
	public function getRepeatColumns()
867
	{
868
		return $this->getRepeatInfo()->getRepeatColumns();
869
	}
870
871
	/**
872
	 * @param int $value the number of columns that the list should be displayed with.
873
	 */
874
	public function setRepeatColumns($value)
875
	{
876
		$this->getRepeatInfo()->setRepeatColumns($value);
877
	}
878
879
	/**
880
	 * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
881
	 */
882
	public function getRepeatDirection()
883
	{
884
		return $this->getRepeatInfo()->getRepeatDirection();
885
	}
886
887
	/**
888
	 * @param TRepeatDirection $value the direction of traversing the list
889
	 */
890
	public function setRepeatDirection($value)
891
	{
892
		$this->getRepeatInfo()->setRepeatDirection($value);
893
	}
894
895
	/**
896
	 * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
897
	 */
898
	public function getRepeatLayout()
899
	{
900
		return $this->getRepeatInfo()->getRepeatLayout();
901
	}
902
903
	/**
904
	 * @param TRepeatLayout $value how the list should be displayed, using table or using line breaks
905
	 */
906
	public function setRepeatLayout($value)
907
	{
908
		$this->getRepeatInfo()->setRepeatLayout($value);
909
	}
910
911
	/**
912
	 * This method overrides parent's implementation to handle
913
	 * {@link onItemCommand OnItemCommand} event which is bubbled from
914
	 * datalist items and their child controls.
915
	 * If the event parameter is {@link TDataListCommandEventParameter} and
916
	 * the command name is a recognized one, which includes 'select', 'edit',
917
	 * 'delete', 'update', and 'cancel' (case-insensitive), then a
918
	 * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
919
	 * This method should only be used by control developers.
920
	 * @param TControl $sender the sender of the event
921
	 * @param TEventParameter $param event parameter
922
	 * @return bool whether the event bubbling should stop here.
923
	 */
924
	public function bubbleEvent($sender, $param)
925
	{
926
		if ($param instanceof TDataListCommandEventParameter) {
927
			$this->onItemCommand($param);
928
			$command = $param->getCommandName();
929
			if (strcasecmp($command, self::CMD_SELECT) === 0) {
930
				if (($item = $param->getItem()) instanceof IItemDataRenderer) {
931
					$this->setSelectedItemIndex($item->getItemIndex());
932
				}
933
				$this->onSelectedIndexChanged($param);
934
				return true;
935
			} elseif (strcasecmp($command, self::CMD_EDIT) === 0) {
936
				$this->onEditCommand($param);
937
				return true;
938
			} elseif (strcasecmp($command, self::CMD_DELETE) === 0) {
939
				$this->onDeleteCommand($param);
940
				return true;
941
			} elseif (strcasecmp($command, self::CMD_UPDATE) === 0) {
942
				$this->onUpdateCommand($param);
943
				return true;
944
			} elseif (strcasecmp($command, self::CMD_CANCEL) === 0) {
945
				$this->onCancelCommand($param);
946
				return true;
947
			}
948
		}
949
		return false;
950
	}
951
952
953
	/**
954
	 * Raises <b>OnItemCreated</b> event.
955
	 * This method is invoked after a data list item is created and instantiated with
956
	 * template, but before added to the page hierarchy.
957
	 * The datalist item control responsible for the event
958
	 * can be determined from the event parameter.
959
	 * If you override this method, be sure to call parent's implementation
960
	 * so that event handlers have chance to respond to the event.
961
	 * @param TDataListItemEventParameter $param event parameter
962
	 */
963
	public function onItemCreated($param)
964
	{
965
		$this->raiseEvent('OnItemCreated', $this, $param);
966
	}
967
968
	/**
969
	 * Raises <b>OnItemDataBound</b> event.
970
	 * This method is invoked right after an item is data bound.
971
	 * The datalist item control responsible for the event
972
	 * can be determined from the event parameter.
973
	 * If you override this method, be sure to call parent's implementation
974
	 * so that event handlers have chance to respond to the event.
975
	 * @param TDataListItemEventParameter $param event parameter
976
	 */
977
	public function onItemDataBound($param)
978
	{
979
		$this->raiseEvent('OnItemDataBound', $this, $param);
980
	}
981
982
	/**
983
	 * Raises <b>OnItemCommand</b> event.
984
	 * This method is invoked when a child control of the data list
985
	 * raises an <b>OnCommand</b> event.
986
	 * @param TDataListCommandEventParameter $param event parameter
987
	 */
988
	public function onItemCommand($param)
989
	{
990
		$this->raiseEvent('OnItemCommand', $this, $param);
991
	}
992
993
	/**
994
	 * Raises <b>OnEditCommand</b> event.
995
	 * This method is invoked when a child control of the data list
996
	 * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
997
	 * @param TDataListCommandEventParameter $param event parameter
998
	 */
999
	public function onEditCommand($param)
1000
	{
1001
		$this->raiseEvent('OnEditCommand', $this, $param);
1002
	}
1003
1004
	/**
1005
	 * Raises <b>OnDeleteCommand</b> event.
1006
	 * This method is invoked when a child control of the data list
1007
	 * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
1008
	 * @param TDataListCommandEventParameter $param event parameter
1009
	 */
1010
	public function onDeleteCommand($param)
1011
	{
1012
		$this->raiseEvent('OnDeleteCommand', $this, $param);
1013
	}
1014
1015
	/**
1016
	 * Raises <b>OnUpdateCommand</b> event.
1017
	 * This method is invoked when a child control of the data list
1018
	 * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
1019
	 * @param TDataListCommandEventParameter $param event parameter
1020
	 */
1021
	public function onUpdateCommand($param)
1022
	{
1023
		$this->raiseEvent('OnUpdateCommand', $this, $param);
1024
	}
1025
1026
	/**
1027
	 * Raises <b>OnCancelCommand</b> event.
1028
	 * This method is invoked when a child control of the data list
1029
	 * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
1030
	 * @param TDataListCommandEventParameter $param event parameter
1031
	 */
1032
	public function onCancelCommand($param)
1033
	{
1034
		$this->raiseEvent('OnCancelCommand', $this, $param);
1035
	}
1036
1037
	/**
1038
	 * Returns a value indicating whether this control contains header item.
1039
	 * This method is required by {@link IRepeatInfoUser} interface.
1040
	 * @return bool whether the datalist has header
1041
	 */
1042
	public function getHasHeader()
1043
	{
1044
		return ($this->getShowHeader() && ($this->_headerTemplate !== null || $this->getHeaderRenderer() !== ''));
1045
	}
1046
1047
	/**
1048
	 * Returns a value indicating whether this control contains footer item.
1049
	 * This method is required by {@link IRepeatInfoUser} interface.
1050
	 * @return bool whether the datalist has footer
1051
	 */
1052
	public function getHasFooter()
1053
	{
1054
		return ($this->getShowFooter() && ($this->_footerTemplate !== null || $this->getFooterRenderer() !== ''));
1055
	}
1056
1057
	/**
1058
	 * Returns a value indicating whether this control contains separator items.
1059
	 * This method is required by {@link IRepeatInfoUser} interface.
1060
	 * @return bool always false.
1061
	 */
1062
	public function getHasSeparators()
1063
	{
1064
		return $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== '';
1065
	}
1066
1067
	/**
1068
	 * Returns a style used for rendering items.
1069
	 * This method is required by {@link IRepeatInfoUser} interface.
1070
	 * @param string $itemType item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
1071
	 * @param int $index index of the item being rendered
1072
	 * @return TStyle item style
1073
	 */
1074
	public function generateItemStyle($itemType, $index)
1075
	{
1076
		if (($item = $this->getItem($itemType, $index)) !== null && ($item instanceof IStyleable) && $item->getHasStyle()) {
1077
			$style = $item->getStyle();
1078
			$item->clearStyle();
1079
			return $style;
1080
		} else {
1081
			return null;
1082
		}
1083
	}
1084
1085
	/**
1086
	 * Renders an item in the list.
1087
	 * This method is required by {@link IRepeatInfoUser} interface.
1088
	 * @param THtmlWriter $writer writer for rendering purpose
1089
	 * @param TRepeatInfo $repeatInfo repeat information
1090
	 * @param string $itemType item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
1091
	 * @param int $index zero-based index of the item in the item list
1092
	 */
1093
	public function renderItem($writer, $repeatInfo, $itemType, $index)
1094
	{
1095
		$item = $this->getItem($itemType, $index);
1096
		if ($repeatInfo->getRepeatLayout() === TRepeatLayout::Raw && get_class($item) === 'TDataListItem') {
1097
			$item->setTagName('div');
1098
		}
1099
		$item->renderControl($writer);
1100
	}
1101
1102
	/**
1103
	 * @param TListItemType $itemType item type
1104
	 * @param int $index item index
1105
	 * @return TControl data list item with the specified item type and index
1106
	 */
1107
	private function getItem($itemType, $index)
1108
	{
1109
		switch ($itemType) {
1110
			case TListItemType::Item:
1111
			case TListItemType::AlternatingItem:
1112
			case TListItemType::SelectedItem:
1113
			case TListItemType::EditItem:
1114
				return $this->getItems()->itemAt($index);
1115
			case TListItemType::Header:
1116
				return $this->getControls()->itemAt(0);
1117
			case TListItemType::Footer:
1118
				return $this->getControls()->itemAt($this->getControls()->getCount() - 1);
1119
			case TListItemType::Separator:
1120
				$i = $index + $index + 1;
1121
				if ($this->_headerTemplate !== null || $this->getHeaderRenderer() !== '') {
1122
					$i++;
1123
				}
1124
				return $this->getControls()->itemAt($i);
1125
		}
1126
		return null;
1127
	}
1128
1129
	/**
1130
	 * Creates a datalist item.
1131
	 * This method invokes {@link createItem} to create a new datalist item.
1132
	 * @param int $itemIndex zero-based item index.
1133
	 * @param TListItemType $itemType item type
1134
	 * @return TControl the created item, null if item is not created
1135
	 */
1136 View Code Duplication
	private function createItemInternal($itemIndex, $itemType)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1137
	{
1138
		if (($item = $this->createItem($itemIndex, $itemType)) !== null) {
1139
			$param = new TDataListItemEventParameter($item);
0 ignored issues
show
Compatibility introduced by
$item of type object<Prado\TComponent> is not a sub-type of object<Prado\Web\UI\TControl>. It seems like you assume a child class of the class Prado\TComponent to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1140
			$this->onItemCreated($param);
1141
			$this->getControls()->add($item);
1142
			return $item;
1143
		} else {
1144
			return null;
1145
		}
1146
	}
1147
1148
	/**
1149
	 * Creates a datalist item and performs databinding.
1150
	 * This method invokes {@link createItem} to create a new datalist item.
1151
	 * @param int $itemIndex zero-based item index.
1152
	 * @param TListItemType $itemType item type
1153
	 * @param mixed $dataItem data to be associated with the item
1154
	 * @return TControl the created item, null if item is not created
1155
	 */
1156 View Code Duplication
	private function createItemWithDataInternal($itemIndex, $itemType, $dataItem)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1157
	{
1158
		if (($item = $this->createItem($itemIndex, $itemType)) !== null) {
1159
			$param = new TDataListItemEventParameter($item);
0 ignored issues
show
Compatibility introduced by
$item of type object<Prado\TComponent> is not a sub-type of object<Prado\Web\UI\TControl>. It seems like you assume a child class of the class Prado\TComponent to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
1160
			if ($item instanceof \Prado\IDataRenderer) {
1161
				$item->setData($dataItem);
1162
			}
1163
			$this->onItemCreated($param);
1164
			$this->getControls()->add($item);
1165
			$item->dataBind();
1166
			$this->onItemDataBound($param);
1167
			return $item;
1168
		} else {
1169
			return null;
1170
		}
1171
	}
1172
1173
	private function getAlternatingItemDisplay()
1174
	{
1175
		if (($classPath = $this->getAlternatingItemRenderer()) === '' && $this->_alternatingItemTemplate === null) {
1176
			return [$this->getItemRenderer(), $this->_itemTemplate];
1177
		} else {
1178
			return [$classPath, $this->_alternatingItemTemplate];
1179
		}
1180
	}
1181
1182
	private function getSelectedItemDisplay($itemIndex)
1183
	{
1184
		if (($classPath = $this->getSelectedItemRenderer()) === '' && $this->_selectedItemTemplate === null) {
1185
			if ($itemIndex % 2 === 0) {
1186
				return [$this->getItemRenderer(), $this->_itemTemplate];
1187
			} else {
1188
				return $this->getAlternatingItemDisplay();
1189
			}
1190
		} else {
1191
			return [$classPath, $this->_selectedItemTemplate];
1192
		}
1193
	}
1194
1195
	private function getEditItemDisplay($itemIndex)
1196
	{
1197
		if (($classPath = $this->getEditItemRenderer()) === '' && $this->_editItemTemplate === null) {
1198
			return $this->getSelectedItemDisplay($itemIndex);
1199
		} else {
1200
			return [$classPath, $this->_editItemTemplate];
1201
		}
1202
	}
1203
1204
	/**
1205
	 * Creates a datalist item instance based on the item type and index.
1206
	 * @param int $itemIndex zero-based item index
1207
	 * @param TListItemType $itemType item type
1208
	 * @return TControl created datalist item
1209
	 */
1210
	protected function createItem($itemIndex, $itemType)
1211
	{
1212
		$template = null;
1213
		$classPath = null;
1214
		switch ($itemType) {
1215
			case TListItemType::Item:
1216
				$classPath = $this->getItemRenderer();
1217
				$template = $this->_itemTemplate;
1218
				break;
1219
			case TListItemType::AlternatingItem:
1220
				list($classPath, $template) = $this->getAlternatingItemDisplay();
1221
				break;
1222
			case TListItemType::SelectedItem:
1223
				list($classPath, $template) = $this->getSelectedItemDisplay($itemIndex);
1224
				break;
1225
			case TListItemType::EditItem:
1226
				list($classPath, $template) = $this->getEditItemDisplay($itemIndex);
1227
				break;
1228
			case TListItemType::Header:
1229
				$classPath = $this->getHeaderRenderer();
1230
				$template = $this->_headerTemplate;
1231
				break;
1232
			case TListItemType::Footer:
1233
				$classPath = $this->getFooterRenderer();
1234
				$template = $this->_footerTemplate;
1235
				break;
1236
			case TListItemType::Separator:
1237
				$classPath = $this->getSeparatorRenderer();
1238
				$template = $this->_separatorTemplate;
1239
				break;
1240
			default:
1241
				throw new TInvalidDataValueException('datalist_itemtype_unknown', $itemType);
1242
		}
1243 View Code Duplication
		if ($classPath !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1244
			$item = Prado::createComponent($classPath);
1245
			if ($item instanceof IItemDataRenderer) {
1246
				$item->setItemIndex($itemIndex);
1247
				$item->setItemType($itemType);
1248
			}
1249
		} elseif ($template !== null) {
1250
			$item = new TDataListItem;
1251
			$item->setItemIndex($itemIndex);
1252
			$item->setItemType($itemType);
1253
			$template->instantiateIn($item);
1254
		} else {
1255
			$item = null;
1256
		}
1257
1258
		return $item;
1259
	}
1260
1261
	/**
1262
	 * Creates empty datalist content.
1263
	 */
1264 View Code Duplication
	protected function createEmptyContent()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1265
	{
1266
		if (($classPath = $this->getEmptyRenderer()) !== '') {
1267
			$this->getControls()->add(Prado::createComponent($classPath));
1268
		} elseif ($this->_emptyTemplate !== null) {
1269
			$this->_emptyTemplate->instantiateIn($this);
1270
		}
1271
	}
1272
1273
	/**
1274
	 * Applies styles to items, header, footer and separators.
1275
	 * Item styles are applied in a hierarchical way. Style in higher hierarchy
1276
	 * will inherit from styles in lower hierarchy.
1277
	 * Starting from the lowest hierarchy, the item styles include
1278
	 * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
1279
	 * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
1280
	 * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
1281
	 * {@link getEditItemStyle EditItemStyle} will also have red background color
1282
	 * unless it is set to a different value explicitly.
1283
	 */
1284
	protected function applyItemStyles()
1285
	{
1286
		$itemStyle = $this->getViewState('ItemStyle', null);
1287
1288
		$alternatingItemStyle = $this->getViewState('AlternatingItemStyle', null);
1289 View Code Duplication
		if ($itemStyle !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1290
			if ($alternatingItemStyle === null) {
1291
				$alternatingItemStyle = $itemStyle;
1292
			} else {
1293
				$alternatingItemStyle->mergeWith($itemStyle);
1294
			}
1295
		}
1296
1297
		$selectedItemStyle = $this->getViewState('SelectedItemStyle', null);
1298
1299
		$editItemStyle = $this->getViewState('EditItemStyle', null);
1300 View Code Duplication
		if ($selectedItemStyle !== null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1301
			if ($editItemStyle === null) {
1302
				$editItemStyle = $selectedItemStyle;
1303
			} else {
1304
				$editItemStyle->mergeWith($selectedItemStyle);
1305
			}
1306
		}
1307
1308
		// apply header style if any
1309 View Code Duplication
		if ($this->_header !== null && $this->_header instanceof IStyleable) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1310
			if ($headerStyle = $this->getViewState('HeaderStyle', null)) {
1311
				$this->_header->getStyle()->mergeWith($headerStyle);
1312
			}
1313
		}
1314
1315
		// apply footer style if any
1316 View Code Duplication
		if ($this->_footer !== null && $this->_footer instanceof IStyleable) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1317
			if ($footerStyle = $this->getViewState('FooterStyle', null)) {
1318
				$this->_footer->getStyle()->mergeWith($footerStyle);
1319
			}
1320
		}
1321
1322
		$selectedIndex = $this->getSelectedItemIndex();
1323
		$editIndex = $this->getEditItemIndex();
1324
1325
		// apply item styles if any
1326
		foreach ($this->getItems() as $index => $item) {
1327
			if ($index === $editIndex) {
1328
				$style = $editItemStyle;
1329
			} elseif ($index === $selectedIndex) {
1330
				$style = $selectedItemStyle;
1331
			} elseif ($index % 2 === 0) {
1332
				$style = $itemStyle;
1333
			} else {
1334
				$style = $alternatingItemStyle;
1335
			}
1336
			if ($style && $item instanceof IStyleable) {
1337
				$item->getStyle()->mergeWith($style);
1338
			}
1339
		}
1340
1341
		// apply separator style if any
1342
		if (($separatorStyle = $this->getViewState('SeparatorStyle', null)) !== null && $this->getHasSeparators()) {
1343
			$controls = $this->getControls();
1344
			$count = $controls->getCount();
1345
			for ($i = $this->_header ? 2 : 1;$i < $count;$i += 2) {
1346
				if (($separator = $controls->itemAt($i)) instanceof IStyleable) {
1347
					$separator->getStyle()->mergeWith($separatorStyle);
1348
				}
1349
			}
1350
		}
1351
	}
1352
1353
	/**
1354
	 * Saves item count in viewstate.
1355
	 * This method is invoked right before control state is to be saved.
1356
	 */
1357 View Code Duplication
	public function saveState()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1358
	{
1359
		parent::saveState();
1360
		if ($this->_items) {
1361
			$this->setViewState('ItemCount', $this->_items->getCount(), 0);
1362
		} else {
1363
			$this->clearViewState('ItemCount');
1364
		}
1365
	}
1366
1367
	/**
1368
	 * Loads item count information from viewstate.
1369
	 * This method is invoked right after control state is loaded.
1370
	 */
1371
	public function loadState()
1372
	{
1373
		parent::loadState();
1374
		if (!$this->getIsDataBound()) {
1375
			$this->restoreItemsFromViewState();
1376
		}
1377
		$this->clearViewState('ItemCount');
1378
	}
1379
1380
	/**
1381
	 * Clears up all items in the data list.
1382
	 */
1383 View Code Duplication
	public function reset()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1384
	{
1385
		$this->getControls()->clear();
1386
		$this->getItems()->clear();
1387
		$this->_header = null;
1388
		$this->_footer = null;
1389
	}
1390
1391
	/**
1392
	 * Creates data list items based on viewstate information.
1393
	 */
1394
	protected function restoreItemsFromViewState()
1395
	{
1396
		$this->reset();
1397
		if (($itemCount = $this->getViewState('ItemCount', 0)) > 0) {
1398
			$items = $this->getItems();
1399
			$selectedIndex = $this->getSelectedItemIndex();
1400
			$editIndex = $this->getEditItemIndex();
1401
			$hasSeparator = $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== '';
1402
			$this->_header = $this->createItemInternal(-1, TListItemType::Header);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createItemInterna...\TListItemType::Header) can also be of type object<Prado\TComponent>. However, the property $_header is declared as type object<Prado\Web\UI\WebControls\TControl>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1403
			for ($i = 0;$i < $itemCount;++$i) {
1404
				if ($hasSeparator && $i > 0) {
1405
					$this->createItemInternal($i - 1, TListItemType::Separator);
1406
				}
1407 View Code Duplication
				if ($i === $editIndex) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1408
					$itemType = TListItemType::EditItem;
1409
				} elseif ($i === $selectedIndex) {
1410
					$itemType = TListItemType::SelectedItem;
1411
				} else {
1412
					$itemType = $i % 2 ? TListItemType::AlternatingItem : TListItemType::Item;
1413
				}
1414
				$items->add($this->createItemInternal($i, $itemType));
1415
			}
1416
			$this->_footer = $this->createItemInternal(-1, TListItemType::Footer);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createItemInterna...\TListItemType::Footer) can also be of type object<Prado\TComponent>. However, the property $_footer is declared as type object<Prado\Web\UI\WebControls\TControl>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1417
		} else {
1418
			$this->createEmptyContent();
1419
		}
1420
		$this->clearChildState();
1421
	}
1422
1423
	/**
1424
	 * Performs databinding to populate data list items from data source.
1425
	 * This method is invoked by dataBind().
1426
	 * You may override this function to provide your own way of data population.
1427
	 * @param Traversable $data the data
1428
	 */
1429
	protected function performDataBinding($data)
1430
	{
1431
		$this->reset();
1432
		$keys = $this->getDataKeys();
1433
		$keys->clear();
1434
		$keyField = $this->getDataKeyField();
1435
		$itemIndex = 0;
1436
		$items = $this->getItems();
1437
		$hasSeparator = $this->_separatorTemplate !== null || $this->getSeparatorRenderer() !== '';
1438
		$selectedIndex = $this->getSelectedItemIndex();
1439
		$editIndex = $this->getEditItemIndex();
1440
		foreach ($data as $key => $dataItem) {
1441
			if ($keyField !== '') {
1442
				$keys->add($this->getDataFieldValue($dataItem, $keyField));
1443
			} else {
1444
				$keys->add($key);
1445
			}
1446
			if ($itemIndex === 0) {
1447
				$this->_header = $this->createItemWithDataInternal(-1, TListItemType::Header, null);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createItemWithDat...ItemType::Header, null) can also be of type object<Prado\TComponent>. However, the property $_header is declared as type object<Prado\Web\UI\WebControls\TControl>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1448
			}
1449
			if ($hasSeparator && $itemIndex > 0) {
1450
				$this->createItemWithDataInternal($itemIndex - 1, TListItemType::Separator, null);
1451
			}
1452 View Code Duplication
			if ($itemIndex === $editIndex) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1453
				$itemType = TListItemType::EditItem;
1454
			} elseif ($itemIndex === $selectedIndex) {
1455
				$itemType = TListItemType::SelectedItem;
1456
			} else {
1457
				$itemType = $itemIndex % 2 ? TListItemType::AlternatingItem : TListItemType::Item;
1458
			}
1459
			$items->add($this->createItemWithDataInternal($itemIndex, $itemType, $dataItem));
1460
			$itemIndex++;
1461
		}
1462 View Code Duplication
		if ($itemIndex > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1463
			$this->_footer = $this->createItemWithDataInternal(-1, TListItemType::Footer, null);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->createItemWithDat...ItemType::Footer, null) can also be of type object<Prado\TComponent>. However, the property $_footer is declared as type object<Prado\Web\UI\WebControls\TControl>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1464
		} else {
1465
			$this->createEmptyContent();
1466
			$this->dataBindChildren();
1467
		}
1468
		$this->setViewState('ItemCount', $itemIndex, 0);
1469
	}
1470
1471
	/**
1472
	 * Renders the data list control.
1473
	 * This method overrides the parent implementation.
1474
	 * @param THtmlWriter $writer writer for rendering purpose.
1475
	 */
1476
	public function render($writer)
1477
	{
1478
		if ($this->getHasControls()) {
1479
			if ($this->getItemCount() > 0) {
1480
				$this->applyItemStyles();
1481
				$repeatInfo = $this->getRepeatInfo();
1482
				$repeatInfo->renderRepeater($writer, $this);
1483
			} elseif ($this->_emptyTemplate !== null || $this->getEmptyRenderer() !== '') {
1484
				parent::render($writer);
1485
			}
1486
		}
1487
	}
1488
}
1489