Source for file Collection.php

Documentation is available at Collection.php

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