1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\ComponentModel;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17: 18: 19:
20: class Container extends Component implements IContainer
21: {
22:
23: private $components = array();
24:
25:
26: private $cloning;
27:
28:
29:
30:
31:
32: 33: 34: 35: 36: 37: 38: 39:
40: public function addComponent(IComponent $component, $name, $insertBefore = NULL)
41: {
42: if ($name === NULL) {
43: $name = $component->getName();
44: }
45:
46: if (is_int($name)) {
47: $name = (string) $name;
48:
49: } elseif (!is_string($name)) {
50: throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
51:
52: } elseif (!preg_match('#^[a-zA-Z0-9_]+\z#', $name)) {
53: throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given.");
54: }
55:
56: if (isset($this->components[$name])) {
57: throw new Nette\InvalidStateException("Component with name '$name' already exists.");
58: }
59:
60:
61: $obj = $this;
62: do {
63: if ($obj === $component) {
64: throw new Nette\InvalidStateException("Circular reference detected while adding component '$name'.");
65: }
66: $obj = $obj->getParent();
67: } while ($obj !== NULL);
68:
69:
70: $this->validateChildComponent($component);
71:
72: try {
73: if (isset($this->components[$insertBefore])) {
74: $tmp = array();
75: foreach ($this->components as $k => $v) {
76: if ($k === $insertBefore) {
77: $tmp[$name] = $component;
78: }
79: $tmp[$k] = $v;
80: }
81: $this->components = $tmp;
82: } else {
83: $this->components[$name] = $component;
84: }
85: $component->setParent($this, $name);
86:
87: } catch (\Exception $e) {
88: unset($this->components[$name]);
89: throw $e;
90: }
91: return $this;
92: }
93:
94:
95: 96: 97: 98:
99: public function removeComponent(IComponent $component)
100: {
101: $name = $component->getName();
102: if (!isset($this->components[$name]) || $this->components[$name] !== $component) {
103: throw new Nette\InvalidArgumentException("Component named '$name' is not located in this container.");
104: }
105:
106: unset($this->components[$name]);
107: $component->setParent(NULL);
108: }
109:
110:
111: 112: 113: 114: 115: 116:
117: public function getComponent($name, $need = TRUE)
118: {
119: if (is_int($name)) {
120: $name = (string) $name;
121:
122: } elseif (!is_string($name)) {
123: throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
124:
125: } else {
126: $a = strpos($name, self::NAME_SEPARATOR);
127: if ($a !== FALSE) {
128: $ext = (string) substr($name, $a + 1);
129: $name = substr($name, 0, $a);
130: }
131:
132: if ($name === '') {
133: if ($need) {
134: throw new Nette\InvalidArgumentException('Component or subcomponent name must not be empty string.');
135: }
136: return;
137: }
138: }
139:
140: if (!isset($this->components[$name])) {
141: $component = $this->createComponent($name);
142: if ($component) {
143: if (!$component instanceof IComponent) {
144: throw new Nette\UnexpectedValueException('Method createComponent() did not return Nette\ComponentModel\IComponent.');
145:
146: } elseif (!isset($this->components[$name])) {
147: $this->addComponent($component, $name);
148: }
149: }
150: }
151:
152: if (isset($this->components[$name])) {
153: if (!isset($ext)) {
154: return $this->components[$name];
155:
156: } elseif ($this->components[$name] instanceof IContainer) {
157: return $this->components[$name]->getComponent($ext, $need);
158:
159: } elseif ($need) {
160: throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$ext' component.");
161: }
162:
163: } elseif ($need) {
164: throw new Nette\InvalidArgumentException("Component with name '$name' does not exist.");
165: }
166: }
167:
168:
169: 170: 171: 172: 173:
174: protected function createComponent($name)
175: {
176: $ucname = ucfirst($name);
177: $method = 'createComponent' . $ucname;
178: if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
179: $component = $this->$method($name);
180: if (!$component instanceof IComponent && !isset($this->components[$name])) {
181: $class = get_class($this);
182: throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
183: }
184: return $component;
185: }
186: }
187:
188:
189: 190: 191: 192: 193: 194:
195: public function getComponents($deep = FALSE, $filterType = NULL)
196: {
197: $iterator = new RecursiveComponentIterator($this->components);
198: if ($deep) {
199: $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
200: $iterator = new \RecursiveIteratorIterator($iterator, $deep);
201: }
202: if ($filterType) {
203: $iterator = new Nette\Iterators\Filter($iterator, function($item) use ($filterType) {
204: return $item instanceof $filterType;
205: });
206: }
207: return $iterator;
208: }
209:
210:
211: 212: 213: 214: 215:
216: protected function validateChildComponent(IComponent $child)
217: {
218: }
219:
220:
221:
222:
223:
224: 225: 226:
227: public function __clone()
228: {
229: if ($this->components) {
230: $oldMyself = reset($this->components)->getParent();
231: $oldMyself->cloning = $this;
232: foreach ($this->components as $name => $component) {
233: $this->components[$name] = clone $component;
234: }
235: $oldMyself->cloning = NULL;
236: }
237: parent::__clone();
238: }
239:
240:
241: 242: 243: 244: 245:
246: public function _isCloning()
247: {
248: return $this->cloning;
249: }
250:
251: }
252: