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_]+$#', $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:
108: public function removeComponent(IComponent $component)
109: {
110: $name = $component->getName();
111: if (!isset($this->components[$name]) || $this->components[$name] !== $component) {
112: throw new Nette\InvalidArgumentException("Component named '$name' is not located in this container.");
113: }
114:
115: unset($this->components[$name]);
116: $component->setParent(NULL);
117: }
118:
119:
120:
121: 122: 123: 124: 125: 126:
127: final public function getComponent($name, $need = TRUE)
128: {
129: if (is_int($name)) {
130: $name = (string) $name;
131:
132: } elseif (!is_string($name)) {
133: throw new Nette\InvalidArgumentException("Component name must be integer or string, " . gettype($name) . " given.");
134:
135: } else {
136: $a = strpos($name, self::NAME_SEPARATOR);
137: if ($a !== FALSE) {
138: $ext = (string) substr($name, $a + 1);
139: $name = substr($name, 0, $a);
140: }
141:
142: if ($name === '') {
143: throw new Nette\InvalidArgumentException("Component or subcomponent name must not be empty string.");
144: }
145: }
146:
147: if (!isset($this->components[$name])) {
148: $component = $this->createComponent($name);
149: if ($component instanceof IComponent && $component->getParent() === NULL) {
150: $this->addComponent($component, $name);
151: }
152: }
153:
154: if (isset($this->components[$name])) {
155: if (!isset($ext)) {
156: return $this->components[$name];
157:
158: } elseif ($this->components[$name] instanceof IContainer) {
159: return $this->components[$name]->getComponent($ext, $need);
160:
161: } elseif ($need) {
162: throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$ext' component.");
163: }
164:
165: } elseif ($need) {
166: throw new Nette\InvalidArgumentException("Component with name '$name' does not exist.");
167: }
168: }
169:
170:
171:
172: 173: 174: 175: 176:
177: protected function createComponent($name)
178: {
179: $ucname = ucfirst($name);
180: $method = 'createComponent' . $ucname;
181: if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
182: $component = $this->$method($name);
183: if (!$component instanceof IComponent && !isset($this->components[$name])) {
184: $class = get_class($this);
185: throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
186: }
187: return $component;
188: }
189: }
190:
191:
192:
193: 194: 195: 196: 197: 198:
199: final public function getComponents($deep = FALSE, $filterType = NULL)
200: {
201: $iterator = new RecursiveComponentIterator($this->components);
202: if ($deep) {
203: $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
204: $iterator = new \RecursiveIteratorIterator($iterator, $deep);
205: }
206: if ($filterType) {
207: $iterator = new Nette\Iterators\InstanceFilter($iterator, $filterType);
208: }
209: return $iterator;
210: }
211:
212:
213:
214: 215: 216: 217: 218: 219:
220: protected function validateChildComponent(IComponent $child)
221: {
222: }
223:
224:
225:
226:
227:
228:
229:
230: 231: 232:
233: public function __clone()
234: {
235: if ($this->components) {
236: $oldMyself = reset($this->components)->getParent();
237: $oldMyself->cloning = $this;
238: foreach ($this->components as $name => $component) {
239: $this->components[$name] = clone $component;
240: }
241: $oldMyself->cloning = NULL;
242: }
243: parent::__clone();
244: }
245:
246:
247:
248: 249: 250: 251: 252:
253: public function _isCloning()
254: {
255: return $this->cloning;
256: }
257:
258: }
259: