Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • 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 (http://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:                 throw new Nette\InvalidArgumentException('Component or subcomponent name must not be empty string.');
134:             }
135:         }
136: 
137:         if (!isset($this->components[$name])) {
138:             $component = $this->createComponent($name);
139:             if ($component instanceof IComponent && $component->getParent() === NULL) {
140:                 $this->addComponent($component, $name);
141:             }
142:         }
143: 
144:         if (isset($this->components[$name])) {
145:             if (!isset($ext)) {
146:                 return $this->components[$name];
147: 
148:             } elseif ($this->components[$name] instanceof IContainer) {
149:                 return $this->components[$name]->getComponent($ext, $need);
150: 
151:             } elseif ($need) {
152:                 throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$ext' component.");
153:             }
154: 
155:         } elseif ($need) {
156:             throw new Nette\InvalidArgumentException("Component with name '$name' does not exist.");
157:         }
158:     }
159: 
160: 
161:     /**
162:      * Component factory. Delegates the creation of components to a createComponent<Name> method.
163:      * @param  string      component name
164:      * @return IComponent  the created component (optionally)
165:      */
166:     protected function createComponent($name)
167:     {
168:         $ucname = ucfirst($name);
169:         $method = 'createComponent' . $ucname;
170:         if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
171:             $component = $this->$method($name);
172:             if (!$component instanceof IComponent && !isset($this->components[$name])) {
173:                 $class = get_class($this);
174:                 throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
175:             }
176:             return $component;
177:         }
178:     }
179: 
180: 
181:     /**
182:      * Iterates over components.
183:      * @param  bool    recursive?
184:      * @param  string  class types filter
185:      * @return \ArrayIterator
186:      */
187:     public function getComponents($deep = FALSE, $filterType = NULL)
188:     {
189:         $iterator = new RecursiveComponentIterator($this->components);
190:         if ($deep) {
191:             $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
192:             $iterator = new \RecursiveIteratorIterator($iterator, $deep);
193:         }
194:         if ($filterType) {
195:             $iterator = new Nette\Iterators\InstanceFilter($iterator, $filterType);
196:         }
197:         return $iterator;
198:     }
199: 
200: 
201:     /**
202:      * Descendant can override this method to disallow insert a child by throwing an Nette\InvalidStateException.
203:      * @return void
204:      * @throws Nette\InvalidStateException
205:      */
206:     protected function validateChildComponent(IComponent $child)
207:     {
208:     }
209: 
210: 
211:     /********************* cloneable, serializable ****************d*g**/
212: 
213: 
214:     /**
215:      * Object cloning.
216:      */
217:     public function __clone()
218:     {
219:         if ($this->components) {
220:             $oldMyself = reset($this->components)->getParent();
221:             $oldMyself->cloning = $this;
222:             foreach ($this->components as $name => $component) {
223:                 $this->components[$name] = clone $component;
224:             }
225:             $oldMyself->cloning = NULL;
226:         }
227:         parent::__clone();
228:     }
229: 
230: 
231:     /**
232:      * Is container cloning now?
233:      * @return NULL|IComponent
234:      * @internal
235:      */
236:     public function _isCloning()
237:     {
238:         return $this->cloning;
239:     }
240: 
241: }
242: 
Nette 2.0 API documentation generated by ApiGen 2.8.0