Passed
Branch php-cs-fixer (b9836a)
by Fabio
15:02
created

TList::contains()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * TList class
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\Collections
10
 */
11
12
namespace Prado\Collections;
13
14
use Prado\Exceptions\TInvalidOperationException;
15
use Prado\Exceptions\TInvalidDataTypeException;
16
use Prado\Exceptions\TInvalidDataValueException;
17
use Prado\TPropertyValue;
18
19
/**
20
 * TList class
21
 *
22
 * TList implements an integer-indexed collection class.
23
 *
24
 * You can access, append, insert, remove an item by using
25
 * {@link itemAt}, {@link add}, {@link insertAt}, {@link remove}, and {@link removeAt}.
26
 * To get the number of the items in the list, use {@link getCount}.
27
 * TList can also be used like a regular array as follows,
28
 * <code>
29
 * $list[]=$item;  // append at the end
30
 * $list[$index]=$item; // $index must be between 0 and $list->Count
31
 * unset($list[$index]); // remove the item at $index
32
 * if(isset($list[$index])) // if the list has an item at $index
33
 * foreach($list as $index=>$item) // traverse each item in the list
34
 * $n=count($list); // returns the number of items in the list
35
 * </code>
36
 *
37
 * To extend TList by doing additional operations with each addition or removal
38
 * operation, override {@link insertAt()}, and {@link removeAt()}.
39
 *
40
 * @author Qiang Xue <[email protected]>
41
 * @package Prado\Collections
42
 * @since 3.0
43
 */
44
class TList extends \Prado\TComponent implements \IteratorAggregate, \ArrayAccess, \Countable
45
{
46
	/**
47
	 * internal data storage
48
	 * @var array
49
	 */
50
	private $_d = [];
51
	/**
52
	 * number of items
53
	 * @var integer
54
	 */
55
	private $_c = 0;
56
	/**
57
	 * @var boolean whether this list is read-only
58
	 */
59
	private $_r = false;
60
61
	/**
62
	 * Constructor.
63
	 * Initializes the list with an array or an iterable object.
0 ignored issues
show
Bug introduced by
The type Prado\Collections\the was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
64
	 * @param array|Iterator the initial data. Default is null, meaning no initialization.
65
	 * @param boolean whether the list is read-only
0 ignored issues
show
Bug introduced by
The type Prado\Collections\whether was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
66
	 * @throws TInvalidDataTypeException If data is not null and neither an array nor an iterator.
67
	 */
68
	public function __construct($data = null, $readOnly = false)
69
	{
70
		if($data !== null)
71
			$this->copyFrom($data);
72
		$this->setReadOnly($readOnly);
73
	}
74
75
	/**
76
	 * @return boolean whether this list is read-only or not. Defaults to false.
77
	 */
78
	public function getReadOnly()
79
	{
80
		return $this->_r;
81
	}
82
83
	/**
84
	 * @param boolean whether this list is read-only or not
85
	 */
86
	protected function setReadOnly($value)
87
	{
88
		$this->_r = TPropertyValue::ensureBoolean($value);
89
	}
90
91
	/**
92
	 * Returns an iterator for traversing the items in the list.
93
	 * This method is required by the interface \IteratorAggregate.
94
	 * @return Iterator an iterator for traversing the items in the list.
0 ignored issues
show
Bug introduced by
The type Prado\Collections\Iterator was not found. Did you mean Iterator? If so, make sure to prefix the type with \.
Loading history...
95
	 */
96
	public function getIterator()
97
	{
98
		return new \ArrayIterator($this->_d);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new ArrayIterator($this->_d) returns the type ArrayIterator which is incompatible with the documented return type Prado\Collections\Iterator.
Loading history...
99
	}
100
101
	/**
102
	 * Returns the number of items in the list.
103
	 * This method is required by \Countable interface.
104
	 * @return integer number of items in the list.
105
	 */
106
	public function count()
107
	{
108
		return $this->getCount();
109
	}
110
111
	/**
112
	 * @return integer the number of items in the list
113
	 */
114
	public function getCount()
115
	{
116
		return $this->_c;
117
	}
118
119
	/**
120
	 * Returns the item at the specified offset.
121
	 * This method is exactly the same as {@link offsetGet}.
122
	 * @param integer the index of the item
123
	 * @return mixed the item at the index
124
	 * @throws TInvalidDataValueException if the index is out of the range
125
	 */
126
	public function itemAt($index)
127
	{
128
		if($index >= 0 && $index < $this->_c)
129
			return $this->_d[$index];
130
		else
131
			throw new TInvalidDataValueException('list_index_invalid', $index);
132
	}
133
134
	/**
135
	 * Appends an item at the end of the list.
136
	 * @param mixed new item
0 ignored issues
show
Bug introduced by
The type Prado\Collections\new was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
137
	 * @return integer the zero-based index at which the item is added
138
	 * @throws TInvalidOperationException if the list is read-only
139
	 */
140
	public function add($item)
141
	{
142
		$this->insertAt($this->_c, $item);
143
		return $this->_c - 1;
144
	}
145
146
	/**
147
	 * Inserts an item at the specified position.
148
	 * Original item at the position and the next items
149
	 * will be moved one step towards the end.
150
	 * @param integer the specified position.
151
	 * @param mixed new item
152
	 * @throws TInvalidDataValueException If the index specified exceeds the bound
153
	 * @throws TInvalidOperationException if the list is read-only
154
	 */
155
	public function insertAt($index, $item)
156
	{
157
		if(!$this->_r)
158
		{
159
			if($index === $this->_c)
160
				$this->_d[$this->_c++] = $item;
161
			elseif($index >= 0 && $index < $this->_c)
162
			{
163
				array_splice($this->_d, $index, 0, [$item]);
164
				$this->_c++;
165
			}
166
			else
167
				throw new TInvalidDataValueException('list_index_invalid', $index);
168
		}
169
		else
170
			throw new TInvalidOperationException('list_readonly', get_class($this));
171
	}
172
173
	/**
174
	 * Removes an item from the list.
175
	 * The list will first search for the item.
176
	 * The first item found will be removed from the list.
177
	 * @param mixed the item to be removed.
178
	 * @return integer the index at which the item is being removed
179
	 * @throws TInvalidDataValueException If the item does not exist
180
	 * @throws TInvalidOperationException if the list is read-only
181
	 */
182
	public function remove($item)
183
	{
184
		if(!$this->_r)
185
		{
186
			if(($index = $this->indexOf($item)) >= 0)
187
			{
188
				$this->removeAt($index);
189
				return $index;
190
			}
191
			else
192
				throw new TInvalidDataValueException('list_item_inexistent');
193
		}
194
		else
195
			throw new TInvalidOperationException('list_readonly', get_class($this));
196
	}
197
198
	/**
199
	 * Removes an item at the specified position.
200
	 * @param integer the index of the item to be removed.
201
	 * @return mixed the removed item.
202
	 * @throws TInvalidDataValueException If the index specified exceeds the bound
203
	 * @throws TInvalidOperationException if the list is read-only
204
	 */
205
	public function removeAt($index)
206
	{
207
		if(!$this->_r)
208
		{
209
			if($index >= 0 && $index < $this->_c)
210
			{
211
				$this->_c--;
212
				if($index === $this->_c)
213
					return array_pop($this->_d);
214
				else
215
				{
216
					$item = $this->_d[$index];
217
					array_splice($this->_d, $index, 1);
218
					return $item;
219
				}
220
			}
221
			else
222
				throw new TInvalidDataValueException('list_index_invalid', $index);
223
		}
224
		else
225
			throw new TInvalidOperationException('list_readonly', get_class($this));
226
	}
227
228
	/**
229
	 * Removes all items in the list.
230
	 * @throws TInvalidOperationException if the list is read-only
231
	 */
232
	public function clear()
233
	{
234
		for($i = $this->_c - 1;$i >= 0;--$i)
235
			$this->removeAt($i);
236
	}
237
238
	/**
239
	 * @param mixed the item
240
	 * @return boolean whether the list contains the item
241
	 */
242
	public function contains($item)
243
	{
244
		return $this->indexOf($item) >= 0;
245
	}
246
247
	/**
248
	 * @param mixed the item
249
	 * @return integer the index of the item in the list (0 based), -1 if not found.
250
	 */
251
	public function indexOf($item)
252
	{
253
		if(($index = array_search($item, $this->_d, true)) === false)
254
			return -1;
255
		else
256
			return $index;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $index also could return the type string which is incompatible with the documented return type integer.
Loading history...
257
	}
258
259
	/**
260
	 * Finds the base item.  If found, the item is inserted before it.
261
	 * @param mixed the base item which will be pushed back by the second parameter
262
	 * @param mixed the item
263
	 * @return int the index where the item is inserted
264
	 * @throws TInvalidDataValueException if the base item is not within this list
265
	 * @throws TInvalidOperationException if the list is read-only
266
	 * @since 3.2a
267
	 */
268
	public function insertBefore($baseitem, $item)
269
	{
270
		if(!$this->_r)
271
		{
272
			if(($index = $this->indexOf($baseitem)) == -1)
273
				throw new TInvalidDataValueException('list_item_inexistent');
274
275
			$this->insertAt($index, $item);
276
277
			return $index;
278
		}
279
		else
280
			throw new TInvalidOperationException('list_readonly', get_class($this));
281
	}
282
283
	/**
284
	 * Finds the base item.  If found, the item is inserted after it.
285
	 * @param mixed the base item which comes before the second parameter when added to the list
286
	 * @param mixed the item
287
	 * @return int the index where the item is inserted
288
	 * @throws TInvalidDataValueException if the base item is not within this list
289
	 * @throws TInvalidOperationException if the list is read-only
290
	 * @since 3.2a
291
	 */
292
	public function insertAfter($baseitem, $item)
293
	{
294
		if(!$this->_r)
295
		{
296
			if(($index = $this->indexOf($baseitem)) == -1)
297
				throw new TInvalidDataValueException('list_item_inexistent');
298
299
			$this->insertAt($index + 1, $item);
300
301
			return $index + 1;
302
		}
303
		else
304
			throw new TInvalidOperationException('list_readonly', get_class($this));
305
	}
306
307
	/**
308
	 * @return array the list of items in array
309
	 */
310
	public function toArray()
311
	{
312
		return $this->_d;
313
	}
314
315
	/**
316
	 * Copies iterable data into the list.
317
	 * Note, existing data in the list will be cleared first.
318
	 * @param mixed the data to be copied from, must be an array or object implementing Traversable
319
	 * @throws TInvalidDataTypeException If data is neither an array nor a Traversable.
320
	 */
321
	public function copyFrom($data)
322
	{
323
		if(is_array($data) || ($data instanceof \Traversable))
324
		{
325
			if($this->_c > 0)
326
				$this->clear();
327
			foreach($data as $item)
328
				$this->add($item);
329
		}
330
		elseif($data !== null)
331
			throw new TInvalidDataTypeException('list_data_not_iterable');
332
	}
333
334
	/**
335
	 * Merges iterable data into the map.
336
	 * New data will be appended to the end of the existing data.
337
	 * @param mixed the data to be merged with, must be an array or object implementing Traversable
338
	 * @throws TInvalidDataTypeException If data is neither an array nor an iterator.
339
	 */
340
	public function mergeWith($data)
341
	{
342
		if(is_array($data) || ($data instanceof \Traversable))
343
		{
344
			foreach($data as $item)
345
				$this->add($item);
346
		}
347
		elseif($data !== null)
348
			throw new TInvalidDataTypeException('list_data_not_iterable');
349
	}
350
351
	/**
352
	 * Returns whether there is an item at the specified offset.
353
	 * This method is required by the interface \ArrayAccess.
354
	 * @param integer the offset to check on
355
	 * @return boolean
356
	 */
357
	public function offsetExists($offset)
358
	{
359
		return ($offset >= 0 && $offset < $this->_c);
360
	}
361
362
	/**
363
	 * Returns the item at the specified offset.
364
	 * This method is required by the interface \ArrayAccess.
365
	 * @param integer the offset to retrieve item.
366
	 * @return mixed the item at the offset
367
	 * @throws TInvalidDataValueException if the offset is invalid
368
	 */
369
	public function offsetGet($offset)
370
	{
371
		return $this->itemAt($offset);
372
	}
373
374
	/**
375
	 * Sets the item at the specified offset.
376
	 * This method is required by the interface \ArrayAccess.
377
	 * @param integer the offset to set item
378
	 * @param mixed the item value
379
	 */
380
	public function offsetSet($offset, $item)
381
	{
382
		if($offset === null || $offset === $this->_c)
383
			$this->insertAt($this->_c, $item);
384
		else
385
		{
386
			$this->removeAt($offset);
387
			$this->insertAt($offset, $item);
388
		}
389
	}
390
391
	/**
392
	 * Unsets the item at the specified offset.
393
	 * This method is required by the interface \ArrayAccess.
394
	 * @param integer the offset to unset item
395
	 */
396
	public function offsetUnset($offset)
397
	{
398
		$this->removeAt($offset);
399
	}
400
}
401