Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • ArrayList
  • Collection
  • Hashtable
  • Set

Interfaces

  • ICollection
  • IList
  • IMap
  • ISet

Exceptions

  • KeyNotFoundException
  • Overview
  • Namespace
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Collections;
 13: 
 14: use Nette,
 15:     Nette\ObjectMixin;
 16: 
 17: 
 18: 
 19: /**
 20:  * SPL ArrayObject customization.
 21:  *
 22:  * @author     David Grudl
 23:  *
 24:  * @property-read bool $frozen
 25:  */
 26: abstract class Collection extends \ArrayObject implements ICollection
 27: {
 28:     /** @var string  type (class, interface, PHP type) */
 29:     private $itemType;
 30: 
 31:     /** @var string  function to verify type */
 32:     private $checkFunc;
 33: 
 34:     /** @var bool */
 35:     private $frozen = FALSE;
 36: 
 37: 
 38: 
 39:     /**
 40:      * @param  array to wrap
 41:      * @param  string class/interface name or ':type'
 42:      * @throws \InvalidArgumentException
 43:      */
 44:     public function __construct($arr = NULL, $type = NULL)
 45:     {
 46:         if (substr($type, 0, 1) === ':') {
 47:             $this->itemType = substr($type, 1);
 48:             $this->checkFunc = 'is_' . $this->itemType;
 49:         } else {
 50:             $this->itemType = $type;
 51:         }
 52: 
 53:         if ($arr !== NULL) {
 54:             $this->import($arr);
 55:         }
 56:     }
 57: 
 58: 
 59: 
 60:     /**
 61:      * Appends the specified element to the end of this collection.
 62:      * @param  mixed
 63:      * @return void
 64:      * @throws \InvalidArgumentException
 65:      */
 66:     public function append($item)
 67:     {
 68:         $this->beforeAdd($item);
 69:         parent::append($item);
 70:     }
 71: 
 72: 
 73: 
 74:     /**
 75:      * Removes the first occurrence of the specified element.
 76:      * @param  mixed
 77:      * @return bool  true if this collection changed as a result of the call
 78:      * @throws \NotSupportedException
 79:      */
 80:     public function remove($item)
 81:     {
 82:         $this->updating();
 83:         $index = $this->search($item);
 84:         if ($index === FALSE) {
 85:             return FALSE;
 86:         } else {
 87:             parent::offsetUnset($index);
 88:             return TRUE;
 89:         }
 90:     }
 91: 
 92: 
 93: 
 94:     /**
 95:      * Returns the index of the first occurrence of the specified element,.
 96:      * or FALSE if this collection does not contain this element.
 97:      * @param  mixed
 98:      * @return int|FALSE
 99:      */
100:     protected function search($item)
101:     {
102:         return array_search($item, $this->getArrayCopy(), TRUE);
103:     }
104: 
105: 
106: 
107:     /**
108:      * Removes all of the elements from this collection.
109:      * @return void
110:      * @throws \NotSupportedException
111:      */
112:     public function clear()
113:     {
114:         $this->updating();
115:         parent::exchangeArray(array());
116:     }
117: 
118: 
119: 
120:     /**
121:      * Returns true if this collection contains the specified item.
122:      * @param  mixed
123:      * @return bool
124:      */
125:     public function contains($item)
126:     {
127:         return $this->search($item) !== FALSE;
128:     }
129: 
130: 
131: 
132:     /**
133:      * Import from array or any traversable object.
134:      * @param  array|\Traversable
135:      * @return void
136:      * @throws \InvalidArgumentException
137:      */
138:     public function import($arr)
139:     {
140:         if (!(is_array($arr) || $arr instanceof \Traversable)) {
141:             throw new \InvalidArgumentException("Argument must be traversable.");
142:         }
143: 
144:         $this->clear();
145:         foreach ($arr as $item) {
146:             $this->offsetSet(NULL, $item);
147:         }
148:     }
149: 
150: 
151: 
152:     /**
153:      * Returns the item type.
154:      * @return string
155:      */
156:     public function getItemType()
157:     {
158:         return $this->itemType;
159:     }
160: 
161: 
162: 
163:     /**
164:      * @deprecated
165:      */
166:     public function setReadOnly()
167:     {
168:         throw new \DeprecatedException(__METHOD__ . '() is deprecated; use freeze() instead.');
169:     }
170: 
171: 
172: 
173:     /**
174:      * @deprecated
175:      */
176:     public function isReadOnly()
177:     {
178:         throw new \DeprecatedException(__METHOD__ . '() is deprecated; use isFrozen() instead.');
179:     }
180: 
181: 
182: 
183:     /********************* internal notifications ****************d*g**/
184: 
185: 
186: 
187:     /**
188:      * Responds when the item is about to be added to the collection.
189:      * @param  mixed
190:      * @return void
191:      * @throws \InvalidArgumentException, \NotSupportedException
192:      */
193:     protected function beforeAdd($item)
194:     {
195:         $this->updating();
196: 
197:         if ($this->itemType !== NULL) {
198:             if ($this->checkFunc === NULL) {
199:                 if (!($item instanceof $this->itemType)) {
200:                     throw new \InvalidArgumentException("Item must be '$this->itemType' object.");
201:                 }
202:             } else {
203:                 $fnc = $this->checkFunc;
204:                 if (!$fnc($item)) {
205:                     throw new \InvalidArgumentException("Item must be $this->itemType type.");
206:                 }
207:             }
208:         }
209:     }
210: 
211: 
212: 
213:     /********************* ArrayObject cooperation ****************d*g**/
214: 
215: 
216: 
217:     /**
218:      * Returns the iterator.
219:      * @return ArrayIterator
220:      */
221:     public function getIterator()
222:     {
223:         return new \ArrayIterator($this->getArrayCopy());
224:     }
225: 
226: 
227: 
228:     /**
229:      * Not supported. Use import().
230:      */
231:     public function exchangeArray($array)
232:     {
233:         throw new \NotSupportedException('Use ' . __CLASS__ . '::import()');
234:     }
235: 
236: 
237: 
238:     /**
239:      * Protected exchangeArray().
240:      * @param  array  new array
241:      * @return Collection  provides a fluent interface
242:      */
243:     protected function setArray($array)
244:     {
245:         parent::exchangeArray($array);
246:         return $this;
247:     }
248: 
249: 
250: 
251:     /********************* Nette\Object behaviour ****************d*g**/
252: 
253: 
254: 
255:     /**
256:      * @return Nette\Reflection\ClassReflection
257:      */
258:     public static function getReflection()
259:     {
260:         return new Nette\Reflection\ClassReflection(get_called_class());
261:     }
262: 
263: 
264: 
265:     /**
266:      * Call to undefined method.
267:      * @throws \MemberAccessException
268:      */
269:     public function __call($name, $args)
270:     {
271:         return ObjectMixin::call($this, $name, $args);
272:     }
273: 
274: 
275: 
276:     /**
277:      * Call to undefined static method.
278:      * @throws \MemberAccessException
279:      */
280:     public static function __callStatic($name, $args)
281:     {
282:         $class = get_called_class();
283:         throw new \MemberAccessException("Call to undefined static method $class::$name().");
284:     }
285: 
286: 
287: 
288:     /**
289:      * Returns property value. Do not call directly.
290:      * @throws \MemberAccessException if the property is not defined.
291:      */
292:     public function &__get($name)
293:     {
294:         return ObjectMixin::get($this, $name);
295:     }
296: 
297: 
298: 
299:     /**
300:      * Sets value of a property. Do not call directly.
301:      * @throws \MemberAccessException if the property is not defined or is read-only
302:      */
303:     public function __set($name, $value)
304:     {
305:         return ObjectMixin::set($this, $name, $value);
306:     }
307: 
308: 
309: 
310:     /**
311:      * Is property defined?
312:      * @param  string  property name
313:      * @return bool
314:      */
315:     public function __isset($name)
316:     {
317:         return ObjectMixin::has($this, $name);
318:     }
319: 
320: 
321: 
322:     /**
323:      * Access to undeclared property.
324:      * @throws \MemberAccessException
325:      */
326:     public function __unset($name)
327:     {
328:         throw new \MemberAccessException("Cannot unset the property {$this->reflection->name}::\$$name.");
329:     }
330: 
331: 
332: 
333:     /********************* Nette\FreezableObject behaviour ****************d*g**/
334: 
335: 
336: 
337:     /**
338:      * Makes the object unmodifiable.
339:      * @return void
340:      */
341:     public function freeze()
342:     {
343:         $this->frozen = TRUE;
344:     }
345: 
346: 
347: 
348:     /**
349:      * Is the object unmodifiable?
350:      * @return bool
351:      */
352:     final public function isFrozen()
353:     {
354:         return $this->frozen;
355:     }
356: 
357: 
358: 
359:     /**
360:      * Creates a modifiable clone of the object.
361:      * @return void
362:      */
363:     public function __clone()
364:     {
365:         $this->frozen = FALSE;
366:     }
367: 
368: 
369: 
370:     /**
371:      * @return void
372:      */
373:     protected function updating()
374:     {
375:         if ($this->frozen) {
376:             $class = get_class($this);
377:             throw new \InvalidStateException("Cannot modify a frozen object '$class'.");
378:         }
379:     }
380: 
381: }
382: 
Nette Framework 0.9.7 API documentation generated by ApiGen 2.3.0