%PDF- %PDF-
Direktori : /www/varak.net/losik.varak.net/vendor/nette/component-model/src/ComponentModel/ |
Current File : //www/varak.net/losik.varak.net/vendor/nette/component-model/src/ComponentModel/Container.php |
<?php /** * This file is part of the Nette Framework (https://nette.org) * Copyright (c) 2004 David Grudl (https://davidgrudl.com) */ declare(strict_types=1); namespace Nette\ComponentModel; use Nette; /** * ComponentContainer is default implementation of IContainer. * * @property-read \Iterator $components */ class Container extends Component implements IContainer { private const NameRegexp = '#^[a-zA-Z0-9_]+$#D'; /** @var IComponent[] */ private $components = []; /** @var Container|null */ private $cloning; /********************* interface IContainer ****************d*g**/ /** * Adds the component to the container. * @return static * @throws Nette\InvalidStateException */ public function addComponent(IComponent $component, ?string $name, ?string $insertBefore = null) { if ($name === null) { $name = $component->getName(); if ($name === null) { throw new Nette\InvalidStateException("Missing component's name."); } } if (!preg_match(self::NameRegexp, $name)) { throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given."); } if (isset($this->components[$name])) { throw new Nette\InvalidStateException("Component with name '$name' already exists."); } // check circular reference $obj = $this; do { if ($obj === $component) { throw new Nette\InvalidStateException("Circular reference detected while adding component '$name'."); } $obj = $obj->getParent(); } while ($obj !== null); // user checking $this->validateChildComponent($component); if (isset($this->components[$insertBefore])) { $tmp = []; foreach ($this->components as $k => $v) { if ((string) $k === $insertBefore) { $tmp[$name] = $component; } $tmp[$k] = $v; } $this->components = $tmp; } else { $this->components[$name] = $component; } try { $component->setParent($this, $name); } catch (\Throwable $e) { unset($this->components[$name]); // undo throw $e; } return $this; } /** * Removes the component from the container. */ public function removeComponent(IComponent $component): void { $name = $component->getName(); if (($this->components[$name] ?? null) !== $component) { throw new Nette\InvalidArgumentException("Component named '$name' is not located in this container."); } unset($this->components[$name]); $component->setParent(null); } /** * Returns component specified by name or path. * @param bool $throw throw exception if component doesn't exist? */ final public function getComponent(string $name, bool $throw = true): ?IComponent { [$name] = $parts = explode(self::NameSeparator, $name, 2); if (!isset($this->components[$name])) { if (!preg_match(self::NameRegexp, $name)) { if ($throw) { throw new Nette\InvalidArgumentException("Component name must be non-empty alphanumeric string, '$name' given."); } return null; } $component = $this->createComponent($name); if ($component && !isset($this->components[$name])) { $this->addComponent($component, $name); } } $component = $this->components[$name] ?? null; if ($component !== null) { if (!isset($parts[1])) { return $component; } elseif ($component instanceof IContainer) { return $component->getComponent($parts[1], $throw); } elseif ($throw) { throw new Nette\InvalidArgumentException("Component with name '$name' is not container and cannot have '$parts[1]' component."); } } elseif ($throw) { $hint = Nette\Utils\ObjectHelpers::getSuggestion(array_merge( array_map('strval', array_keys($this->components)), array_map('lcfirst', preg_filter('#^createComponent([A-Z0-9].*)#', '$1', get_class_methods($this))) ), $name); throw new Nette\InvalidArgumentException("Component with name '$name' does not exist" . ($hint ? ", did you mean '$hint'?" : '.')); } return null; } /** * Component factory. Delegates the creation of components to a createComponent<Name> method. */ protected function createComponent(string $name): ?IComponent { $ucname = ucfirst($name); $method = 'createComponent' . $ucname; if ( $ucname !== $name && method_exists($this, $method) && (new \ReflectionMethod($this, $method))->getName() === $method ) { $component = $this->$method($name); if (!$component instanceof IComponent && !isset($this->components[$name])) { $class = static::class; throw new Nette\UnexpectedValueException("Method $class::$method() did not return or create the desired component."); } return $component; } return null; } /** * Iterates over descendants components. * @return \Iterator<int|string,IComponent> */ final public function getComponents(bool $deep = false, ?string $filterType = null): \Iterator { $iterator = new RecursiveComponentIterator($this->components); if ($deep) { $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); } if ($filterType) { $iterator = new \CallbackFilterIterator($iterator, function ($item) use ($filterType) { return $item instanceof $filterType; }); } return $iterator; } /** * Descendant can override this method to disallow insert a child by throwing an Nette\InvalidStateException. * @throws Nette\InvalidStateException */ protected function validateChildComponent(IComponent $child): void { } /********************* cloneable, serializable ****************d*g**/ /** * Object cloning. */ public function __clone() { if ($this->components) { $oldMyself = reset($this->components)->getParent(); assert($oldMyself instanceof self); $oldMyself->cloning = $this; foreach ($this->components as $name => $component) { $this->components[$name] = clone $component; } $oldMyself->cloning = null; } parent::__clone(); } /** * Is container cloning now? * @internal */ final public function _isCloning(): ?self { return $this->cloning; } }