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