Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • none

Classes

  • Component
  • Container

Interfaces

  • IComponent
  • IContainer
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\ComponentModel;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * ComponentContainer is default implementation of IContainer.
 15:  *
 16:  * @author     David Grudl
 17:  *
 18:  * @property-read \ArrayIterator $components
 19:  */
 20: class Container extends Component implements IContainer
 21: {
 22:     /** @var IComponent[] */
 23:     private $components = array();
 24: 
 25:     /** @var IComponent|NULL */
 26:     private $cloning;
 27: 
 28: 
 29:     /********************* interface IContainer ****************d*g**/
 30: 
 31: 
 32:     /**
 33:      * Adds the specified component to the IContainer.
 34:      * @param  IComponent
 35:      * @param  string
 36:      * @param  string
 37:      * @return self
 38:      * @throws Nette\InvalidStateException
 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:         // check circular reference
 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:         // user checking
 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]); // undo
 89:             throw $e;
 90:         }
 91:         return $this;
 92:     }
 93: 
 94: 
 95:     /**
 96:      * Removes a component from the IContainer.
 97:      * @return void
 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:      * Returns component specified by name or path.
113:      * @param  string
114:      * @param  bool   throw exception if component doesn't exist?
115:      * @return IComponent|NULL
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 instanceof IComponent && $component->getParent() === NULL) {
143:                 $this->addComponent($component, $name);
144:             }
145:         }
146: 
147:         if (isset($this->components[$name])) {
148:             if (!isset($ext)) {
149:                 return $this->components[$name];
150: 
151:             } elseif ($this->components[$name] instanceof IContainer) {
152:                 return $this->components[$name]->getComponent($ext, $need);
153: 
154:             } elseif ($need) {
155:                 throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$ext' component.");
156:             }
157: 
158:         } elseif ($need) {
159:             throw new Nette\InvalidArgumentException("Component with name '$name' does not exist.");
160:         }
161:     }
162: 
163: 
164:     /**
165:      * Component factory. Delegates the creation of components to a createComponent<Name> method.
166:      * @param  string      component name
167:      * @return IComponent  the created component (optionally)
168:      */
169:     protected function createComponent($name)
170:     {
171:         $ucname = ucfirst($name);
172:         $method = 'createComponent' . $ucname;
173:         if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
174:             $component = $this->$method($name);
175:             if (!$component instanceof IComponent && !isset($this->components[$name])) {
176:                 $class = get_class($this);
177:                 throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
178:             }
179:             return $component;
180:         }
181:     }
182: 
183: 
184:     /**
185:      * Iterates over components.
186:      * @param  bool    recursive?
187:      * @param  string  class types filter
188:      * @return \ArrayIterator
189:      */
190:     public function getComponents($deep = FALSE, $filterType = NULL)
191:     {
192:         $iterator = new RecursiveComponentIterator($this->components);
193:         if ($deep) {
194:             $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
195:             $iterator = new \RecursiveIteratorIterator($iterator, $deep);
196:         }
197:         if ($filterType) {
198:             $iterator = new Nette\Iterators\Filter($iterator, function ($item) use ($filterType) {
199:                 return $item instanceof $filterType;
200:             });
201:         }
202:         return $iterator;
203:     }
204: 
205: 
206:     /**
207:      * Descendant can override this method to disallow insert a child by throwing an Nette\InvalidStateException.
208:      * @return void
209:      * @throws Nette\InvalidStateException
210:      */
211:     protected function validateChildComponent(IComponent $child)
212:     {
213:     }
214: 
215: 
216:     /********************* cloneable, serializable ****************d*g**/
217: 
218: 
219:     /**
220:      * Object cloning.
221:      */
222:     public function __clone()
223:     {
224:         if ($this->components) {
225:             $oldMyself = reset($this->components)->getParent();
226:             $oldMyself->cloning = $this;
227:             foreach ($this->components as $name => $component) {
228:                 $this->components[$name] = clone $component;
229:             }
230:             $oldMyself->cloning = NULL;
231:         }
232:         parent::__clone();
233:     }
234: 
235: 
236:     /**
237:      * Is container cloning now?
238:      * @return NULL|IComponent
239:      * @internal
240:      */
241:     public function _isCloning()
242:     {
243:         return $this->cloning;
244:     }
245: 
246: }
247: 
Nette 2.1 API documentation generated by ApiGen 2.8.0