PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/nette-dev/Collections/Collection.php

https://github.com/bazo/Mokuji
PHP | 364 lines | 139 code | 91 blank | 134 comment | 13 complexity | d5cd1ad0635fa2d392d81bf77e2320ed MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Collections
  10. */
  11. /**
  12. * SPL ArrayObject customization.
  13. *
  14. * @copyright Copyright (c) 2004, 2010 David Grudl
  15. * @package Nette\Collections
  16. *
  17. * @property-read bool $frozen
  18. */
  19. abstract class Collection extends ArrayObject implements ICollection
  20. {
  21. /** @var string type (class, interface, PHP type) */
  22. private $itemType;
  23. /** @var string function to verify type */
  24. private $checkFunc;
  25. /** @var bool */
  26. private $frozen = FALSE;
  27. /**
  28. * @param array to wrap
  29. * @param string class/interface name or ':type'
  30. * @throws InvalidArgumentException
  31. */
  32. public function __construct($arr = NULL, $type = NULL)
  33. {
  34. if (substr($type, 0, 1) === ':') {
  35. $this->itemType = substr($type, 1);
  36. $this->checkFunc = 'is_' . $this->itemType;
  37. } else {
  38. $this->itemType = $type;
  39. }
  40. if ($arr !== NULL) {
  41. $this->import($arr);
  42. }
  43. }
  44. /**
  45. * Appends the specified element to the end of this collection.
  46. * @param mixed
  47. * @return void
  48. * @throws InvalidArgumentException
  49. */
  50. public function append($item)
  51. {
  52. $this->beforeAdd($item);
  53. parent::append($item);
  54. }
  55. /**
  56. * Removes the first occurrence of the specified element.
  57. * @param mixed
  58. * @return bool true if this collection changed as a result of the call
  59. * @throws NotSupportedException
  60. */
  61. public function remove($item)
  62. {
  63. $this->updating();
  64. $index = $this->search($item);
  65. if ($index === FALSE) {
  66. return FALSE;
  67. } else {
  68. parent::offsetUnset($index);
  69. return TRUE;
  70. }
  71. }
  72. /**
  73. * Returns the index of the first occurrence of the specified element,.
  74. * or FALSE if this collection does not contain this element.
  75. * @param mixed
  76. * @return int|FALSE
  77. */
  78. protected function search($item)
  79. {
  80. return array_search($item, $this->getArrayCopy(), TRUE);
  81. }
  82. /**
  83. * Removes all of the elements from this collection.
  84. * @return void
  85. * @throws NotSupportedException
  86. */
  87. public function clear()
  88. {
  89. $this->updating();
  90. parent::exchangeArray(array());
  91. }
  92. /**
  93. * Returns true if this collection contains the specified item.
  94. * @param mixed
  95. * @return bool
  96. */
  97. public function contains($item)
  98. {
  99. return $this->search($item) !== FALSE;
  100. }
  101. /**
  102. * Import from array or any traversable object.
  103. * @param array|\Traversable
  104. * @return void
  105. * @throws InvalidArgumentException
  106. */
  107. public function import($arr)
  108. {
  109. if (!(is_array($arr) || $arr instanceof Traversable)) {
  110. throw new InvalidArgumentException("Argument must be traversable.");
  111. }
  112. $this->clear();
  113. foreach ($arr as $item) {
  114. $this->offsetSet(NULL, $item);
  115. }
  116. }
  117. /**
  118. * Returns the item type.
  119. * @return string
  120. */
  121. public function getItemType()
  122. {
  123. return $this->itemType;
  124. }
  125. /********************* internal notifications ****************d*g**/
  126. /**
  127. * Responds when the item is about to be added to the collection.
  128. * @param mixed
  129. * @return void
  130. * @throws InvalidArgumentException, \NotSupportedException
  131. */
  132. protected function beforeAdd($item)
  133. {
  134. $this->updating();
  135. if ($this->itemType !== NULL) {
  136. if ($this->checkFunc === NULL) {
  137. if (!($item instanceof $this->itemType)) {
  138. throw new InvalidArgumentException("Item must be '$this->itemType' object.");
  139. }
  140. } else {
  141. $fnc = $this->checkFunc;
  142. if (!$fnc($item)) {
  143. throw new InvalidArgumentException("Item must be $this->itemType type.");
  144. }
  145. }
  146. }
  147. }
  148. /********************* ArrayObject cooperation ****************d*g**/
  149. /**
  150. * Returns the iterator.
  151. * @return ArrayIterator
  152. */
  153. public function getIterator()
  154. {
  155. return new ArrayIterator($this->getArrayCopy());
  156. }
  157. /**
  158. * Not supported. Use import().
  159. */
  160. public function exchangeArray($array)
  161. {
  162. throw new NotSupportedException('Use ' . __CLASS__ . '::import()');
  163. }
  164. /**
  165. * Protected exchangeArray().
  166. * @param array new array
  167. * @return Collection provides a fluent interface
  168. */
  169. protected function setArray($array)
  170. {
  171. parent::exchangeArray($array);
  172. return $this;
  173. }
  174. /********************* Nette\Object behaviour ****************d*g**/
  175. /**
  176. * @return ClassReflection
  177. */
  178. public function getReflection()
  179. {
  180. return new ClassReflection($this);
  181. }
  182. /**
  183. * Call to undefined method.
  184. *
  185. * @throws MemberAccessException
  186. */
  187. public function __call($name, $args)
  188. {
  189. return ObjectMixin::call($this, $name, $args);
  190. }
  191. /**
  192. * Call to undefined static method.
  193. *
  194. * @throws MemberAccessException
  195. */
  196. public static function __callStatic($name, $args)
  197. {
  198. $class = get_called_class();
  199. throw new MemberAccessException("Call to undefined static method $class::$name().");
  200. }
  201. /**
  202. * Returns property value. Do not call directly.
  203. *
  204. * @throws MemberAccessException if the property is not defined.
  205. */
  206. public function &__get($name)
  207. {
  208. return ObjectMixin::get($this, $name);
  209. }
  210. /**
  211. * Sets value of a property. Do not call directly.
  212. *
  213. * @throws MemberAccessException if the property is not defined or is read-only
  214. */
  215. public function __set($name, $value)
  216. {
  217. return ObjectMixin::set($this, $name, $value);
  218. }
  219. /**
  220. * Is property defined?
  221. *
  222. * @param string property name
  223. * @return bool
  224. */
  225. public function __isset($name)
  226. {
  227. return ObjectMixin::has($this, $name);
  228. }
  229. /**
  230. * Access to undeclared property.
  231. *
  232. * @throws MemberAccessException
  233. */
  234. public function __unset($name)
  235. {
  236. throw new MemberAccessException("Cannot unset the property {$this->reflection->name}::\$$name.");
  237. }
  238. /********************* Nette\FreezableObject behaviour ****************d*g**/
  239. /**
  240. * Makes the object unmodifiable.
  241. * @return void
  242. */
  243. public function freeze()
  244. {
  245. $this->frozen = TRUE;
  246. }
  247. /**
  248. * Is the object unmodifiable?
  249. * @return bool
  250. */
  251. final public function isFrozen()
  252. {
  253. return $this->frozen;
  254. }
  255. /**
  256. * Creates a modifiable clone of the object.
  257. * @return void
  258. */
  259. public function __clone()
  260. {
  261. $this->frozen = FALSE;
  262. }
  263. /**
  264. * @return void
  265. */
  266. protected function updating()
  267. {
  268. if ($this->frozen) {
  269. $class = get_class($this);
  270. throw new InvalidStateException("Cannot modify a frozen object '$class'.");
  271. }
  272. }
  273. }