PageRenderTime 25ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/shopaholic/lib/Nette/ComponentContainer.php

http://github.com/jakubkulhan/shopaholic
PHP | 271 lines | 121 code | 61 blank | 89 comment | 17 complexity | dff5f0f9d6fa91631f9f5f67e573ebe5 MD5 | raw file
Possible License(s): WTFPL
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * Copyright (c) 2004, 2009 David Grudl (http://davidgrudl.com)
  6. *
  7. * This source file is subject to the "Nette license" that is bundled
  8. * with this package in the file license.txt.
  9. *
  10. * For more information please see http://nettephp.com
  11. *
  12. * @copyright Copyright (c) 2004, 2009 David Grudl
  13. * @license http://nettephp.com/license Nette license
  14. * @link http://nettephp.com
  15. * @category Nette
  16. * @package Nette
  17. * @version $Id: ComponentContainer.php 234 2009-03-26 21:19:54Z david@grudl.com $
  18. */
  19. require_once dirname(__FILE__) . '/Component.php';
  20. require_once dirname(__FILE__) . '/IComponentContainer.php';
  21. /**
  22. * ComponentContainer is default implementation of IComponentContainer.
  23. *
  24. * @author David Grudl
  25. * @copyright Copyright (c) 2004, 2009 David Grudl
  26. * @package Nette
  27. */
  28. class ComponentContainer extends Component implements IComponentContainer
  29. {
  30. /** @var array of IComponent */
  31. private $components = array();
  32. /** @var IComponent|NULL */
  33. private $cloning;
  34. /********************* interface IComponentContainer ****************d*g**/
  35. /**
  36. * Adds the specified component to the IComponentContainer.
  37. * @param IComponent
  38. * @param string
  39. * @param string
  40. * @return void
  41. * @throws InvalidStateException
  42. */
  43. public function addComponent(IComponent $component, $name, $insertBefore = NULL)
  44. {
  45. if ($name === NULL) {
  46. $name = $component->getName();
  47. }
  48. if (is_int($name)) {
  49. $name = (string) $name;
  50. } elseif (!is_string($name)) {
  51. throw new InvalidArgumentException("Component name must be string, " . gettype($name) . " given.");
  52. } elseif (!preg_match('#^[a-zA-Z0-9_]+$#', $name)) {
  53. throw new InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given.");
  54. }
  55. if (isset($this->components[$name])) {
  56. throw new InvalidStateException("Component with name '$name' already exists.");
  57. }
  58. // check circular reference
  59. $obj = $this;
  60. do {
  61. if ($obj === $component) {
  62. throw new InvalidStateException("Circular reference detected.");
  63. }
  64. $obj = $obj->getParent();
  65. } while ($obj !== NULL);
  66. // user checking
  67. $this->validateChildComponent($component);
  68. try {
  69. if (isset($this->components[$insertBefore])) {
  70. $tmp = array();
  71. foreach ($this->components as $k => $v) {
  72. if ($k === $insertBefore) $tmp[$name] = $component;
  73. $tmp[$k] = $v;
  74. }
  75. $this->components = $tmp;
  76. } else {
  77. $this->components[$name] = $component;
  78. }
  79. $component->setParent($this, $name);
  80. } catch (Exception $e) {
  81. unset($this->components[$name]); // undo
  82. throw $e;
  83. }
  84. }
  85. /**
  86. * Removes a component from the IComponentContainer.
  87. * @param IComponent
  88. * @return void
  89. */
  90. public function removeComponent(IComponent $component)
  91. {
  92. $name = $component->getName();
  93. if (!isset($this->components[$name]) || $this->components[$name] !== $component) {
  94. throw new InvalidArgumentException("Component named '$name' is not located in this container.");
  95. }
  96. unset($this->components[$name]);
  97. $component->setParent(NULL);
  98. }
  99. /**
  100. * Returns component specified by name or path.
  101. * @param string
  102. * @param bool throw exception if component doesn't exist?
  103. * @return IComponent|NULL
  104. */
  105. final public function getComponent($name, $need = TRUE)
  106. {
  107. $a = strpos($name, self::NAME_SEPARATOR);
  108. if ($a !== FALSE) {
  109. $ext = substr($name, $a + 1);
  110. $name = substr($name, 0, $a);
  111. }
  112. if (!isset($this->components[$name])) {
  113. $this->createComponent($name);
  114. }
  115. if (isset($this->components[$name])) {
  116. return $a === FALSE ? $this->components[$name] : $this->components[$name]->getComponent($ext);
  117. } elseif ($need) {
  118. throw new InvalidArgumentException("Component with name '$name' does not exist.");
  119. } else {
  120. return NULL;
  121. }
  122. }
  123. /**
  124. * Component factory. Descendant can override this method to enable lazy component loading.
  125. * @param string component name
  126. * @return void
  127. */
  128. protected function createComponent($name)
  129. {
  130. }
  131. /**
  132. * Iterates over a components.
  133. * @param bool recursive?
  134. * @param string class types filter
  135. * @return ArrayIterator
  136. */
  137. final public function getComponents($deep = FALSE, $filterType = NULL)
  138. {
  139. $iterator = new RecursiveComponentIterator($this->components);
  140. if ($deep) {
  141. $deep = $deep > 0 ? RecursiveIteratorIterator::SELF_FIRST : RecursiveIteratorIterator::CHILD_FIRST;
  142. $iterator = new RecursiveIteratorIterator($iterator, $deep);
  143. }
  144. if ($filterType) {
  145. fixNamespace($filterType);
  146. $iterator = new InstanceFilterIterator($iterator, $filterType);
  147. }
  148. return $iterator;
  149. }
  150. /**
  151. * Descendant can override this method to disallow insert a child by throwing an \InvalidStateException.
  152. * @param IComponent
  153. * @return void
  154. * @throws InvalidStateException
  155. */
  156. protected function validateChildComponent(IComponent $child)
  157. {
  158. }
  159. /********************* cloneable, serializable ****************d*g**/
  160. /**
  161. * Object cloning.
  162. */
  163. public function __clone()
  164. {
  165. if ($this->components) {
  166. $oldMyself = reset($this->components)->getParent();
  167. $oldMyself->cloning = $this;
  168. foreach ($this->components as $name => $component) {
  169. $this->components[$name] = clone $component;
  170. }
  171. $oldMyself->cloning = NULL;
  172. }
  173. parent::__clone();
  174. }
  175. /**
  176. * Is container cloning now?
  177. * @return NULL|IComponent
  178. * @internal
  179. */
  180. public function isCloning()
  181. {
  182. return $this->cloning;
  183. }
  184. }
  185. /**
  186. * Recursive component iterator. See ComponentContainer::getComponents().
  187. *
  188. * @author David Grudl
  189. * @copyright Copyright (c) 2004, 2009 David Grudl
  190. * @package Nette
  191. */
  192. class RecursiveComponentIterator extends RecursiveArrayIterator
  193. {
  194. /**
  195. * Has the current element has children?
  196. * @return bool
  197. */
  198. public function hasChildren()
  199. {
  200. return $this->current() instanceof IComponentContainer;
  201. }
  202. /**
  203. * The sub-iterator for the current element.
  204. * @return RecursiveIterator
  205. */
  206. public function getChildren()
  207. {
  208. return $this->current()->getComponents();
  209. }
  210. }