Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Component
  • Container
  • RecursiveComponentIterator

Interfaces

  • IComponent
  • IContainer

Traits

  • ArrayAccess
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  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:  * @property-read \Iterator $components
 17:  */
 18: class Container extends Component implements IContainer
 19: {
 20:     /** @var IComponent[] */
 21:     private $components = [];
 22: 
 23:     /** @var Container|null */
 24:     private $cloning;
 25: 
 26: 
 27:     /********************* interface IContainer ****************d*g**/
 28: 
 29: 
 30:     /**
 31:      * Adds the component to the container.
 32:      * @param  string|int|null  $name
 33:      * @param  string|int  $insertBefore
 34:      * @return static
 35:      * @throws Nette\InvalidStateException
 36:      */
 37:     public function addComponent(IComponent $component, $name, $insertBefore = null)
 38:     {
 39:         if ($name === null) {
 40:             $name = $component->getName();
 41:         }
 42: 
 43:         if (is_int($name)) {
 44:             $name = (string) $name;
 45: 
 46:         } elseif (!is_string($name)) {
 47:             throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
 48: 
 49:         } elseif (!preg_match('#^[a-zA-Z0-9_]+\z#', $name)) {
 50:             throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given.");
 51:         }
 52: 
 53:         if (isset($this->components[$name])) {
 54:             throw new Nette\InvalidStateException("Component with name '$name' already exists.");
 55:         }
 56: 
 57:         // check circular reference
 58:         $obj = $this;
 59:         do {
 60:             if ($obj === $component) {
 61:                 throw new Nette\InvalidStateException("Circular reference detected while adding component '$name'.");
 62:             }
 63:             $obj = $obj->getParent();
 64:         } while ($obj !== null);
 65: 
 66:         // user checking
 67:         $this->validateChildComponent($component);
 68: 
 69:         if (isset($this->components[$insertBefore])) {
 70:             $tmp = [];
 71:             foreach ($this->components as $k => $v) {
 72:                 if ($k === $insertBefore) {
 73:                     $tmp[$name] = $component;
 74:                 }
 75:                 $tmp[$k] = $v;
 76:             }
 77:             $this->components = $tmp;
 78:         } else {
 79:             $this->components[$name] = $component;
 80:         }
 81: 
 82:         try {
 83:             $component->setParent($this, $name);
 84:         } catch (\Exception $e) {
 85:             unset($this->components[$name]); // undo
 86:             throw $e;
 87:         }
 88:         return $this;
 89:     }
 90: 
 91: 
 92:     /**
 93:      * Removes the component from the container.
 94:      * @return void
 95:      */
 96:     public function removeComponent(IComponent $component)
 97:     {
 98:         $name = $component->getName();
 99:         if (!isset($this->components[$name]) || $this->components[$name] !== $component) {
100:             throw new Nette\InvalidArgumentException("Component named '$name' is not located in this container.");
101:         }
102: 
103:         unset($this->components[$name]);
104:         $component->setParent(null);
105:     }
106: 
107: 
108:     /**
109:      * Returns component specified by name or path.
110:      * @param  string|int  $name
111:      * @param  bool  $throw  throw exception if component doesn't exist?
112:      * @return IComponent|null
113:      */
114:     public function getComponent($name, $throw = true)
115:     {
116:         if (!is_int($name) && !is_string($name)) {
117:             throw new Nette\InvalidArgumentException(sprintf('Component name must be integer or string, %s given.', gettype($name)));
118:         }
119: 
120:         list($name) = $parts = explode(self::NAME_SEPARATOR, (string) $name, 2);
121: 
122:         if (!isset($this->components[$name])) {
123:             if (!preg_match('#^[a-zA-Z0-9_]+\z#', $name)) {
124:                 if ($throw) {
125:                     throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given.");
126:                 }
127:                 return;
128:             }
129: 
130:             $component = $this->createComponent($name);
131:             if ($component) {
132:                 if (!$component instanceof IComponent) {
133:                     throw new Nette\UnexpectedValueException('Method createComponent() did not return Nette\ComponentModel\IComponent.');
134: 
135:                 } elseif (!isset($this->components[$name])) {
136:                     $this->addComponent($component, $name);
137:                 }
138:             }
139:         }
140: 
141:         $component = isset($this->components[$name]) ? $this->components[$name] : null;
142:         if ($component !== null) {
143:             if (!isset($parts[1])) {
144:                 return $component;
145: 
146:             } elseif ($component instanceof IContainer) {
147:                 return $component->getComponent($parts[1], $throw);
148: 
149:             } elseif ($throw) {
150:                 throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$parts[1]' component.");
151:             }
152: 
153:         } elseif ($throw) {
154:             $hint = Nette\Utils\ObjectHelpers::getSuggestion(array_merge(
155:                 array_keys($this->components),
156:                 array_map('lcfirst', preg_filter('#^createComponent([A-Z0-9].*)#', '$1', get_class_methods($this)))
157:             ), $name);
158:             throw new Nette\InvalidArgumentException("Component with name '$name' does not exist" . ($hint ? ", did you mean '$hint'?" : '.'));
159:         }
160:     }
161: 
162: 
163:     /**
164:      * Component factory. Delegates the creation of components to a createComponent<Name> method.
165:      * @param  string  $name
166:      * @return IComponent|null
167:      */
168:     protected function createComponent($name)
169:     {
170:         $ucname = ucfirst($name);
171:         $method = 'createComponent' . $ucname;
172:         if ($ucname !== $name && method_exists($this, $method) && (new \ReflectionMethod($this, $method))->getName() === $method) {
173:             $component = $this->$method($name);
174:             if (!$component instanceof IComponent && !isset($this->components[$name])) {
175:                 $class = get_class($this);
176:                 throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component.");
177:             }
178:             return $component;
179:         }
180:     }
181: 
182: 
183:     /**
184:      * Iterates over descendants components.
185:      * @param  bool  $deep  return all descendant?
186:      * @param  string  $filterType  class type to return
187:      * @return \Iterator
188:      */
189:     public function getComponents($deep = false, $filterType = null)
190:     {
191:         $iterator = new RecursiveComponentIterator($this->components);
192:         if ($deep) {
193:             $deep = $deep > 0 ? \RecursiveIteratorIterator::SELF_FIRST : \RecursiveIteratorIterator::CHILD_FIRST;
194:             $iterator = new \RecursiveIteratorIterator($iterator, $deep);
195:         }
196:         if ($filterType) {
197:             $iterator = new \CallbackFilterIterator($iterator, function ($item) use ($filterType) {
198:                 return $item instanceof $filterType;
199:             });
200:         }
201:         return $iterator;
202:     }
203: 
204: 
205:     /**
206:      * Descendant can override this method to disallow insert a child by throwing an Nette\InvalidStateException.
207:      * @return void
208:      * @throws Nette\InvalidStateException
209:      */
210:     protected function validateChildComponent(IComponent $child)
211:     {
212:     }
213: 
214: 
215:     /********************* cloneable, serializable ****************d*g**/
216: 
217: 
218:     /**
219:      * Object cloning.
220:      */
221:     public function __clone()
222:     {
223:         if ($this->components) {
224:             $oldMyself = reset($this->components)->getParent();
225:             $oldMyself->cloning = $this;
226:             foreach ($this->components as $name => $component) {
227:                 $this->components[$name] = clone $component;
228:             }
229:             $oldMyself->cloning = null;
230:         }
231:         parent::__clone();
232:     }
233: 
234: 
235:     /**
236:      * Is container cloning now?
237:      * @return Container|null
238:      * @internal
239:      */
240:     public function _isCloning()
241:     {
242:         return $this->cloning;
243:     }
244: }
245: 
Nette 2.4-20180918 API API documentation generated by ApiGen 2.8.0