Container/Definition/DefinitionInterface.php000064400000004765150732344720015223 0ustar00definitions = array_filter($definitions, function ($definition) { return ($definition instanceof DefinitionInterface); }); } /** * {@inheritdoc} */ public function add(string $id, $definition, bool $shared = false) : DefinitionInterface { if (!$definition instanceof DefinitionInterface) { $definition = new Definition($id, $definition); } $this->definitions[] = $definition ->setAlias($id) ->setShared($shared) ; return $definition; } /** * {@inheritdoc} */ public function has(string $id) : bool { foreach ($this->getIterator() as $definition) { if ($id === $definition->getAlias()) { return true; } } return false; } /** * {@inheritdoc} */ public function hasTag(string $tag) : bool { foreach ($this->getIterator() as $definition) { if ($definition->hasTag($tag)) { return true; } } return false; } /** * {@inheritdoc} */ public function getDefinition(string $id) : DefinitionInterface { foreach ($this->getIterator() as $definition) { if ($id === $definition->getAlias()) { return $definition->setLeagueContainer($this->getLeagueContainer()); } } throw new NotFoundException(sprintf('Alias (%s) is not being handled as a definition.', $id)); } /** * {@inheritdoc} */ public function resolve(string $id, bool $new = false) { return $this->getDefinition($id)->resolve($new); } /** * {@inheritdoc} */ public function resolveTagged(string $tag, bool $new = false) : array { $arrayOf = []; foreach ($this->getIterator() as $definition) { if ($definition->hasTag($tag)) { $arrayOf[] = $definition->setLeagueContainer($this->getLeagueContainer())->resolve($new); } } return $arrayOf; } /** * {@inheritdoc} */ public function getIterator() : Generator { $count = count($this->definitions); for ($i = 0; $i < $count; $i++) { yield $this->definitions[$i]; } } } Container/Definition/DefinitionAggregateInterface.php000064400000003101150732344720017011 0ustar00alias = $id; $this->concrete = $concrete; } /** * {@inheritdoc} */ public function addTag(string $tag) : DefinitionInterface { $this->tags[$tag] = true; return $this; } /** * {@inheritdoc} */ public function hasTag(string $tag) : bool { return isset($this->tags[$tag]); } /** * {@inheritdoc} */ public function setAlias(string $id) : DefinitionInterface { $this->alias = $id; return $this; } /** * {@inheritdoc} */ public function getAlias() : string { return $this->alias; } /** * {@inheritdoc} */ public function setShared(bool $shared = true) : DefinitionInterface { $this->shared = $shared; return $this; } /** * {@inheritdoc} */ public function isShared() : bool { return $this->shared; } /** * {@inheritdoc} */ public function getConcrete() { return $this->concrete; } /** * {@inheritdoc} */ public function setConcrete($concrete) : DefinitionInterface { $this->concrete = $concrete; $this->resolved = null; return $this; } /** * {@inheritdoc} */ public function addArgument($arg) : DefinitionInterface { $this->arguments[] = $arg; return $this; } /** * {@inheritdoc} */ public function addArguments(array $args) : DefinitionInterface { foreach ($args as $arg) { $this->addArgument($arg); } return $this; } /** * {@inheritdoc} */ public function addMethodCall(string $method, array $args = []) : DefinitionInterface { $this->methods[] = [ 'method' => $method, 'arguments' => $args ]; return $this; } /** * {@inheritdoc} */ public function addMethodCalls(array $methods = []) : DefinitionInterface { foreach ($methods as $method => $args) { $this->addMethodCall($method, $args); } return $this; } /** * {@inheritdoc} */ public function resolve(bool $new = false) { $concrete = $this->concrete; if ($this->isShared() && $this->resolved !== null && $new === false) { return $this->resolved; } if (is_callable($concrete)) { $concrete = $this->resolveCallable($concrete); } if ($concrete instanceof RawArgumentInterface) { $this->resolved = $concrete->getValue(); return $concrete->getValue(); } if ($concrete instanceof ClassNameInterface) { $concrete = $concrete->getClassName(); } if (is_string($concrete) && class_exists($concrete)) { $concrete = $this->resolveClass($concrete); } if (is_object($concrete)) { $concrete = $this->invokeMethods($concrete); } if (is_string($concrete) && $this->getContainer()->has($concrete)) { $concrete = $this->getContainer()->get($concrete); } $this->resolved = $concrete; return $concrete; } /** * Resolve a callable. * * @param callable $concrete * * @return mixed */ protected function resolveCallable(callable $concrete) { $resolved = $this->resolveArguments($this->arguments); return call_user_func_array($concrete, $resolved); } /** * Resolve a class. * * @param string $concrete * * @return object * * @throws ReflectionException */ protected function resolveClass(string $concrete) { $resolved = $this->resolveArguments($this->arguments); $reflection = new ReflectionClass($concrete); return $reflection->newInstanceArgs($resolved); } /** * Invoke methods on resolved instance. * * @param object $instance * * @return object */ protected function invokeMethods($instance) { foreach ($this->methods as $method) { $args = $this->resolveArguments($method['arguments']); /** @var callable $callable */ $callable = [$instance, $method['method']]; call_user_func_array($callable, $args); } return $instance; } } Container/ContainerAwareTrait.php000064400000003262150732344720013117 0ustar00container = $container; return $this; } /** * Get the container. * * @return ContainerInterface */ public function getContainer() : ContainerInterface { if ($this->container instanceof ContainerInterface) { return $this->container; } throw new ContainerException('No container implementation has been set.'); } /** * Set a container. * * @param Container $container * * @return self */ public function setLeagueContainer(Container $container) : ContainerAwareInterface { $this->container = $container; $this->leagueContainer = $container; return $this; } /** * Get the container. * * @return Container */ public function getLeagueContainer() : Container { if ($this->leagueContainer instanceof Container) { return $this->leagueContainer; } throw new ContainerException('No container implementation has been set.'); } } Container/Exception/NotFoundException.php000064400000000432150732344720014556 0ustar00getValue(); } elseif ($argument instanceof ClassNameInterface) { $id = $argument->getClassName(); } elseif (!is_string($argument)) { return $argument; } else { $justStringValue = true; $id = $argument; } $container = null; try { $container = $this->getLeagueContainer(); } catch (ContainerException $e) { if ($this instanceof ReflectionContainer) { $container = $this; } } if ($container !== null) { try { return $container->get($id); } catch (NotFoundException $exception) { if ($argument instanceof ClassNameWithOptionalValue) { return $argument->getOptionalValue(); } if ($justStringValue) { return $id; } throw $exception; } } if ($argument instanceof ClassNameWithOptionalValue) { return $argument->getOptionalValue(); } // Just a string value. return $id; }, $arguments); } /** * {@inheritdoc} */ public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []) : array { $arguments = array_map(function (ReflectionParameter $param) use ($method, $args) { $name = $param->getName(); $type = $param->getType(); if (array_key_exists($name, $args)) { return new RawArgument($args[$name]); } if ($type) { if (PHP_VERSION_ID >= 70100) { $typeName = $type->getName(); } else { $typeName = (string) $type; } $typeName = ltrim($typeName, '?'); if ($param->isDefaultValueAvailable()) { return new ClassNameWithOptionalValue($typeName, $param->getDefaultValue()); } return new ClassName($typeName); } if ($param->isDefaultValueAvailable()) { return new RawArgument($param->getDefaultValue()); } throw new NotFoundException(sprintf( 'Unable to resolve a value for parameter (%s) in the function/method (%s)', $name, $method->getName() )); }, $method->getParameters()); return $this->resolveArguments($arguments); } /** * @return ContainerInterface */ abstract public function getContainer() : ContainerInterface; /** * @return Container */ abstract public function getLeagueContainer() : Container; } Container/Argument/ClassNameWithOptionalValue.php000064400000001326150732344720016177 0ustar00className = $className; $this->optionalValue = $optionalValue; } /** * @inheritDoc */ public function getClassName(): string { return $this->className; } public function getOptionalValue() { return $this->optionalValue; } } Container/Argument/RawArgument.php000064400000000730150732344720013224 0ustar00value = $value; } /** * {@inheritdoc} */ public function getValue() { return $this->value; } } Container/Argument/ClassName.php000064400000000752150732344720012642 0ustar00value = $value; } /** * {@inheritdoc} */ public function getClassName() : string { return $this->value; } } Container/Argument/ArgumentResolverInterface.php000064400000001453150732344720016120 0ustar00inflectors[] = $inflector; return $inflector; } /** * {@inheritdoc} */ public function getIterator() : Generator { $count = count($this->inflectors); for ($i = 0; $i < $count; $i++) { yield $this->inflectors[$i]; } } /** * {@inheritdoc} */ public function inflect($object) { foreach ($this->getIterator() as $inflector) { $type = $inflector->getType(); if (! $object instanceof $type) { continue; } $inflector->setLeagueContainer($this->getLeagueContainer()); $inflector->inflect($object); } return $object; } } Container/Inflector/InflectorInterface.php000064400000002475150732344720014711 0ustar00type = $type; $this->callback = $callback; } /** * {@inheritdoc} */ public function getType() : string { return $this->type; } /** * {@inheritdoc} */ public function invokeMethod(string $name, array $args) : InflectorInterface { $this->methods[$name] = $args; return $this; } /** * {@inheritdoc} */ public function invokeMethods(array $methods) : InflectorInterface { foreach ($methods as $name => $args) { $this->invokeMethod($name, $args); } return $this; } /** * {@inheritdoc} */ public function setProperty(string $property, $value) : InflectorInterface { $this->properties[$property] = $this->resolveArguments([$value])[0]; return $this; } /** * {@inheritdoc} */ public function setProperties(array $properties) : InflectorInterface { foreach ($properties as $property => $value) { $this->setProperty($property, $value); } return $this; } /** * {@inheritdoc} */ public function inflect($object) { $properties = $this->resolveArguments(array_values($this->properties)); $properties = array_combine(array_keys($this->properties), $properties); // array_combine() can technically return false foreach ($properties ?: [] as $property => $value) { $object->{$property} = $value; } foreach ($this->methods as $method => $args) { $args = $this->resolveArguments($args); /** @var callable $callable */ $callable = [$object, $method]; call_user_func_array($callable, $args); } if ($this->callback !== null) { call_user_func($this->callback, $object); } } } Container/ServiceProvider/ServiceProviderInterface.php000064400000002526150732344720017262 0ustar00leagueContainer property or the `getLeagueContainer` method * from the ContainerAwareTrait. * * @return void */ public function register(); /** * Set a custom id for the service provider. This enables * registering the same service provider multiple times. * * @param string $id * * @return self */ public function setIdentifier(string $id) : ServiceProviderInterface; /** * The id of the service provider uniquely identifies it, so * that we can quickly determine if it has already been registered. * Defaults to get_class($provider). * * @return string */ public function getIdentifier() : string; } Container/ServiceProvider/BootableServiceProviderInterface.php000064400000000643150732344720020730 0ustar00provides, true); } /** * {@inheritdoc} */ public function setIdentifier(string $id) : ServiceProviderInterface { $this->identifier = $id; return $this; } /** * {@inheritdoc} */ public function getIdentifier() : string { return $this->identifier ?? get_class($this); } } Container/ServiceProvider/ServiceProviderAggregate.php000064400000005433150732344720017250 0ustar00getContainer()->has($provider)) { $provider = $this->getContainer()->get($provider); } elseif (is_string($provider) && class_exists($provider)) { $provider = new $provider; } if (in_array($provider, $this->providers, true)) { return $this; } if ($provider instanceof ContainerAwareInterface) { $provider->setLeagueContainer($this->getLeagueContainer()); } if ($provider instanceof BootableServiceProviderInterface) { $provider->boot(); } if ($provider instanceof ServiceProviderInterface) { $this->providers[] = $provider; return $this; } throw new ContainerException( 'A service provider must be a fully qualified class name or instance ' . 'of (\Automattic\WooCommerce\Vendor\League\Container\ServiceProvider\ServiceProviderInterface)' ); } /** * {@inheritdoc} */ public function provides(string $service) : bool { foreach ($this->getIterator() as $provider) { if ($provider->provides($service)) { return true; } } return false; } /** * {@inheritdoc} */ public function getIterator() : Generator { $count = count($this->providers); for ($i = 0; $i < $count; $i++) { yield $this->providers[$i]; } } /** * {@inheritdoc} */ public function register(string $service) { if (false === $this->provides($service)) { throw new ContainerException( sprintf('(%s) is not provided by a service provider', $service) ); } foreach ($this->getIterator() as $provider) { if (in_array($provider->getIdentifier(), $this->registered, true)) { continue; } if ($provider->provides($service)) { $this->registered[] = $provider->getIdentifier(); $provider->register(); } } } } Container/ServiceProvider/ServiceProviderAggregateInterface.php000064400000001663150732344720021072 0ustar00cacheResolutions === true && array_key_exists($id, $this->cache)) { return $this->cache[$id]; } if (! $this->has($id)) { throw new NotFoundException( sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id) ); } $reflector = new ReflectionClass($id); $construct = $reflector->getConstructor(); $resolution = $construct === null ? new $id : $resolution = $reflector->newInstanceArgs($this->reflectArguments($construct, $args)) ; if ($this->cacheResolutions === true) { $this->cache[$id] = $resolution; } return $resolution; } /** * {@inheritdoc} */ public function has($id) : bool { return class_exists($id); } /** * Invoke a callable via the container. * * @param callable $callable * @param array $args * * @return mixed * * @throws ReflectionException */ public function call(callable $callable, array $args = []) { if (is_string($callable) && strpos($callable, '::') !== false) { $callable = explode('::', $callable); } if (is_array($callable)) { if (is_string($callable[0])) { $callable[0] = $this->getContainer()->get($callable[0]); } $reflection = new ReflectionMethod($callable[0], $callable[1]); if ($reflection->isStatic()) { $callable[0] = null; } return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args)); } if (is_object($callable)) { $reflection = new ReflectionMethod($callable, '__invoke'); return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args)); } $reflection = new ReflectionFunction(\Closure::fromCallable($callable)); return $reflection->invokeArgs($this->reflectArguments($reflection, $args)); } /** * Whether the container should default to caching resolutions and returning * the cache on following calls. * * @param boolean $option * * @return self */ public function cacheResolutions(bool $option = true) : ContainerInterface { $this->cacheResolutions = $option; return $this; } } Container/Container.php000064400000015204150732344720011132 0ustar00definitions = $definitions ?? new DefinitionAggregate; $this->providers = $providers ?? new ServiceProviderAggregate; $this->inflectors = $inflectors ?? new InflectorAggregate; if ($this->definitions instanceof ContainerAwareInterface) { $this->definitions->setLeagueContainer($this); } if ($this->providers instanceof ContainerAwareInterface) { $this->providers->setLeagueContainer($this); } if ($this->inflectors instanceof ContainerAwareInterface) { $this->inflectors->setLeagueContainer($this); } } /** * Add an item to the container. * * @param string $id * @param mixed $concrete * @param boolean $shared * * @return DefinitionInterface */ public function add(string $id, $concrete = null, bool $shared = null) : DefinitionInterface { $concrete = $concrete ?? $id; $shared = $shared ?? $this->defaultToShared; return $this->definitions->add($id, $concrete, $shared); } /** * Proxy to add with shared as true. * * @param string $id * @param mixed $concrete * * @return DefinitionInterface */ public function share(string $id, $concrete = null) : DefinitionInterface { return $this->add($id, $concrete, true); } /** * Whether the container should default to defining shared definitions. * * @param boolean $shared * * @return self */ public function defaultToShared(bool $shared = true) : ContainerInterface { $this->defaultToShared = $shared; return $this; } /** * Get a definition to extend. * * @param string $id [description] * * @return DefinitionInterface */ public function extend(string $id) : DefinitionInterface { if ($this->providers->provides($id)) { $this->providers->register($id); } if ($this->definitions->has($id)) { return $this->definitions->getDefinition($id); } throw new NotFoundException( sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $id) ); } /** * Add a service provider. * * @param ServiceProviderInterface|string $provider * * @return self */ public function addServiceProvider($provider) : self { $this->providers->add($provider); return $this; } /** * {@inheritdoc} */ public function get($id, bool $new = false) { if ($this->definitions->has($id)) { $resolved = $this->definitions->resolve($id, $new); return $this->inflectors->inflect($resolved); } if ($this->definitions->hasTag($id)) { $arrayOf = $this->definitions->resolveTagged($id, $new); array_walk($arrayOf, function (&$resolved) { $resolved = $this->inflectors->inflect($resolved); }); return $arrayOf; } if ($this->providers->provides($id)) { $this->providers->register($id); if (!$this->definitions->has($id) && !$this->definitions->hasTag($id)) { throw new ContainerException(sprintf('Service provider lied about providing (%s) service', $id)); } return $this->get($id, $new); } foreach ($this->delegates as $delegate) { if ($delegate->has($id)) { $resolved = $delegate->get($id); return $this->inflectors->inflect($resolved); } } throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id)); } /** * {@inheritdoc} */ public function has($id) : bool { if ($this->definitions->has($id)) { return true; } if ($this->definitions->hasTag($id)) { return true; } if ($this->providers->provides($id)) { return true; } foreach ($this->delegates as $delegate) { if ($delegate->has($id)) { return true; } } return false; } /** * Allows for manipulation of specific types on resolution. * * @param string $type * @param callable|null $callback * * @return InflectorInterface */ public function inflector(string $type, callable $callback = null) : InflectorInterface { return $this->inflectors->add($type, $callback); } /** * Delegate a backup container to be checked for services if it * cannot be resolved via this container. * * @param ContainerInterface $container * * @return self */ public function delegate(ContainerInterface $container) : self { $this->delegates[] = $container; if ($container instanceof ContainerAwareInterface) { $container->setLeagueContainer($this); } return $this; } }