<?php namespace IO4\Container; use Psr\Container\ContainerInterface; use Webfan\Webfat\App\ContainerCollection; /** * A composite container that acts as a normal container, but delegates method calls to one or more internal containers * inspired by https://github.com/AcclimateContainer/acclimate-container */ class Collection extends ContainerCollection implements ContainerInterface, ContainerCollectionInterface { public const CONTAINER_SPLIT = '.'; public const THROW_ONERRROR = 0; public const NULL_ONERROR = 1; public const CALL_ID = 'call'; protected $invoker = null; public function getCallId(): string { return false; } public function set(string $id, $entry) { if(isset($this->container[$id]) && (\is_callable($entry) || (is_object($entry) && $entry instanceof \Closure )) && $this->factories->contains($entry) ) { throw new \Exception(sprintf('The container entry #id: %1$s is defined allready in %2$s!', $id, __METHOD__)); //return $this->extend($id, $entry); }elseif(isset($this->container[$id])){ throw new \Exception(sprintf('The container entry #id: %1$s is defined allready in %2$s!', $id, __METHOD__)); } $this->container[$id] = $entry; return $this; } public function extend($id, \Closure|\callable $callable): ContainerCollectionInterface { if (!isset($this->container[$id])) { throw new \frdl\NotFoundException($id); // return $this->factory($id, $callable); } $factory = $this->container[$id]; $extended = function (ContainerInterface $container, $previous = null) use ($id, $callable, $factory) { return \call_user_func_array($callable,[$container, $factory($container, $previous)]); }; if ($this->factories->contains($this->container[$id])) { $this->factories->detach($this->container[$id]); $this->factories->attach($extended); } $this->container[$id] = $extended; return $this; } public function factory($id, \Closure|\callable $callable): ContainerCollectionInterface { if(isset($this->container[$id]) && (\is_callable($callable) || (is_object($callable) && $callable instanceof \Closure )) && $this->factories->contains($callable) ) { return $this->extend($id, $callable); }elseif(isset($this->container[$id])){ throw new \Exception(sprintf('The container entry #id: %1$s is defined allready in %2$s!', $id, __METHOD__)); } $this->set($id, $callable); $this->factories->attach($callable); return $this; } public function createInvoker() { $invoker = (new \Invoker\Invoker(null, $this)); $invoker->getParameterResolver()->prependResolver( new \Invoker\ParameterResolver\Container\ParameterNameContainerResolver($this) ); $invoker->getParameterResolver()->prependResolver( new \Invoker\ParameterResolver\Container\TypeHintContainerResolver($this) ); return $invoker; } public function getInvoker() { if(null === $this->invoker){ $this->invoker = $this->createInvoker( ); } return $this->invoker; } public function get($id) { $name = $id; if(isset($this->resolved[$id])){ $this->r($name); return $this->resolved[$id]; } if(isset($this->resolvedIds[$name])){ $this->r($name); return $this->getContainer( $this->resolvedIds[$name][0] )->get( $this->resolvedIds[$name][1] ); } if (isset($this->container[$id]) && (\is_callable($this->container[$id]) && (is_object($this->container[$id]) && $this->container[$id] instanceof \Closure ) ) && $this->factories->contains($this->container[$id]) ) { return \call_user_func_array($this->container[$id],[$this,isset($this->container[$id]) ? $this->container[$id] : null]); } if ( isset($this->container[$id]) && (\is_callable($this->container[$id]) && $this->container[$id] instanceof \Closure) ) { $this->resolved[$id] = $this->getInvoker( )->call($this->container[$id]); return $this->resolved[$id]; } if(isset($this->container[$id])){ $this->r($name); return $this->container[$id]; } $parts = $this->_splitId($name); $current = ''; while(0<count($parts) ){ $current .= self::CONTAINER_SPLIT.array_shift($parts); $current = ltrim($current, self::CONTAINER_SPLIT); if($this->hasContainer($current)){ $id = substr($name, strlen($current), strlen($name) ); if ($this->getContainer($current)->has($id)) { $this->resolvedIds[$name] = [$current, $id]; $this->r($name); return $this->getContainer($current)->get($id); } } } foreach ($this->containers as $containerId => $container) { if ($container->has($name)) { /* $this->resolved[$name] = &$container->get($name); $this->container[$name] = &$this->resolved[$name]; return $this->container[$name]; */ $this->resolvedIds[$name] = [$containerId, $name]; $this->r($name); return $container->get($name); } } if(null !== $this->finalFallbackContainer){ if ($this->finalFallbackContainer->has($name)) { //$this->resolvedIds[$name] = [$containerId, $name]; $this->r($name); $this->resolved[$name] = $this->finalFallbackContainer->get($name); return $this->resolved[$name]; //// return $this->finalFallbackContainer->get($name); } } $this->un($name, true); switch($this->onFalseGet){ case self::NULL_ONERROR : return null; break; case self::THROW_ONERRROR : default: throw new \Exception(sprintf('Cannot resolve container-entry #id: %s|%s in %s', $id, $name, __METHOD__)); break; } } public function &getContainer(string|int $containerId = null) { if(isset($this->containers[$containerId])){ return $this->containers[$containerId]; } switch($this->onFalseGet){ case self::NULL_ONERROR : return null; break; case self::THROW_ONERRROR : default: throw new \Exception(sprintf('Cannot resolve container #id: %s in %s2', $containerId, __METHOD__)); break; } } public function hasContainer(string|int $containerId = null): bool { return isset($this->containers[$containerId]) ? true : false; } protected function _splitId($id) { return preg_split("/(\@)/", $id); } public function has($id) { $name = $id; if(isset($this->resolved[$name])){ $this->r($name); return true; } if(isset($this->container[$name])){ $this->r($name); return true; } if(isset($this->resolvedIds[$name])){ $this->r($name); return true; } foreach ($this->containers as $containerId => $container) { if ($container->has($name)) { $this->resolvedIds[$name] = [$containerId, $name]; $this->r($name); return true; } } if(null !== $this->finalFallbackContainer){ if ($this->finalFallbackContainer->has($name)) { //$this->resolvedIds[$name] = [$containerId, $name]; $this->r($name); return true; } } $parts = $this->_splitId($name); $current = ''; while(0<count($parts) ){ $current .= self::CONTAINER_SPLIT.array_shift($parts); $current = ltrim($current, self::CONTAINER_SPLIT); $id = substr($name, strlen($current), strlen($name) ); $id = rtrim($id, self::CONTAINER_SPLIT); if($this->hasContainer($current)){ if ($this->getContainer($current)->has($id)) { $this->resolvedIds[$name] = [$current, $id]; $this->r($name); return true; } } } $this->un($name, false); return false; } public function unregister($id, bool $deleteDefinitions = true) { $name = $id; if(isset($this->container[$name]) ){ $entry = &$this->container[$name]; if ($this->factories->contains($entry)) { $this->factories->detach($entry); } } if(isset($this->resolved[$name])){ unset($this->resolved[$name]); } if(isset($this->container[$name]) && true === $deleteDefinitions){ unset($this->container[$name]); } if(isset($this->resolvedIds[$name])){ unset($this->resolvedIds[$name]); } foreach ($this->containers as $containerId => $container) { $class = \get_class($container); try{ $ref = new \ReflectionClass($class); $constants = $ref->getConstants(); $containerEntries = (isset($constants['METHOD_MAPPING'])) ? array_keys($constants['METHOD_MAPPING']) : []; if(isset($containerEntries[$name])){ unset($containerEntries[$name]); if(isset($constants['METHOD_MAPPING']) && isset($class::METHOD_MAPPING[$name]) ){ // ERROR : !!! unset($class::METHOD_MAPPING[$name]); } } }catch(\Exception $e){ // ... fix this! if($this->has('kernel')){ $this->get('kernel')->warning($e->getMessage()); } } if(\is_callable([$container, 'delete'])){ \call_user_func_array([$container, 'delete'], [$name]); }elseif(\is_callable([$container, 'remove'])){ \call_user_func_array([$container, 'remove'], [$name]); }elseif(\is_callable([$container, 'unregister'])){ \call_user_func_array([$container, 'unregister'], [$name]); }else{ //.... ? no delete method? } } } public function clearContainerCaches() { foreach ($this->containers as $containerId => $container) { if(\is_callable([$container, 'getCompiledContainerDirectory'])){ $dir = \call_user_func([$container, 'getCompiledContainerDirectory']); $files = array_merge(glob(rtrim($dir, '\\/ ')."/*.php"), glob(rtrim($dir, '\\/ ')."/*/*.php"), glob(rtrim($dir, '\\/ ')."/**/*.php") ); foreach($files as $file){ if(file_exists($file)){ unlink($file); } } } } } public function getKnownEntryNames(): array { $entries = array_merge([], parent::getKnownEntryNames()); $entries = array_merge($entries, array_keys($this->container)); foreach ($this->containers as $containerId => $container) { $ref = new \ReflectionClass(\get_class($container)); $constants = $ref->getConstants(); $containerEntries = (isset($constants['METHOD_MAPPING'])) ? array_keys($constants['METHOD_MAPPING']) : []; if(\is_callable([$container, 'getKnownEntryNames'])){ $containerEntries = array_merge($containerEntries, \call_user_func([$container, 'getKnownEntryNames'])); }elseif(\is_callable([$container, 'flatten'])){ $containerEntries = array_merge($containerEntries, array_keys(\call_user_func([$container, 'flatten']))); }elseif(is_callable([$container, 'getIterator'])){ $containerEntries = array_merge($containerEntries, //array_keys(\iterator_to_array(\call_user_func([$container, 'getIterator']), true)) array_keys(\iterator_to_array($container->getIterator(), true)) ); }elseif(\is_callable([$container, 'all'])){ $containerEntries = array_merge($containerEntries, array_keys(\call_user_func([$container, 'all']))); }else{ foreach($this->resolvedIds as $name => $hash){ if($containerId === $hash[0]){ //$containerEntries[]=$hash[1]; $containerEntries[]=$name; } } } foreach($containerEntries as $itemId){ $containerEntries[]=$containerId.static::CONTAINER_SPLIT.$itemId; } $entries = array_merge($entries, $containerEntries); } sort($entries); return array_unique($entries); } } __halt_compiler();----SIGNATURE:----WHD/aqBWBQVEpVQmHDA4xc36m6QHKQkaDFhxKUkXes04mxIN6JjfXcigRzTxVbtceiVg4YOWNnqIqBbUHqubAjMX+InBjn80zWuVz8VRx5cBekd3Vxt+Xw8KqmtTBy/c0pRDO9fC1sBg98yh5OMVvOO/3Xzh2JHXDhtBY8I+o72/QXDQkYHT5Co9hc+FTP/uPcu7QpUw8k0ClNreYuxZUF2rbkM481fyDlr5+hevd83yzYzJQ5FhSAenygSeO6+SqYJKZAgMFEwak5kdwfWV2ApX1TbBR73el+bk3KA1HAyqYYFKj+6RMy5Iru5/JS+7SR96euUyHeYSWs2yvHiVYKnsS+fl2Qjn6swAG0VgRjpTuFmhbOljimcFYeWizzAphH4VVhc3K2nZ3FNXkKcuD7osj8rS1seLBDP6hM6Mk9+CX/ubsmkSSz4SYaJvUzLf6S1Fh4eEQfjhJ/iLnMqkKwEwMMfRa9AhIwscz4QKn5goohhkdQRA5yN/dWDjVNvsnHBFQqRPhtLMA5WEy9TaoFc50jjtsgJ3D6y7zVREtY76r3XCx83onz68tMukobHOa3EbXZIh8i/dtJzQrpDATWQdcMg5FlgE9OztnxeqO1JzPqgxF1/RZSrUr1yJiYVqi379L1fDdgqWN/3Y3UXi9se7IMAFS6f28eew+1JXWmY=----ATTACHMENT:----ODY4OTA1NjkyOTE1NTgzNCAzNTYzMzQxNzY5ODU5ODQ1IDY2NzQ1MzkzODA4OTMwMTE=