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