Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
systemson committed Jun 4, 2020
1 parent 406e75d commit 285049e
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 55 deletions.
57 changes: 35 additions & 22 deletions src/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
use Amber\Container\Service\ServiceClass;
use Amber\Container\Service\ServiceClosure;
use Amber\Validator\ValidatorTrait;
use Psr\Container\ContainerInterface;
use Amber\Container\Contracts\ContainerInterface;
use Amber\Container\Contracts\ServiceInterface;
use Closure;

/**
Expand All @@ -33,9 +34,9 @@ public function __construct()
*
* @param string $identifier The entry's identifier.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
* Identifier must be a non empty string.
* @throws Amber\Container\Exception\NotFoundException
* @throws NotFoundException
* No entry was found for [$identifier] identifier.
*
* @return mixed
Expand All @@ -62,7 +63,7 @@ public function locate($identifier)
* @param string $identifier The entry's identifier.
* @param mixed $value Optional. The entry's value.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
* Identifier must be a non empty string.
* Identifier [$identifier] must be a valid class.
* Class [$value] must be a subclass of [$identifier], or the same.
Expand All @@ -84,7 +85,7 @@ final public function bind($identifier, $value = null): bool
* @param string $identifier The entry's identifier.
* @param mixed $value Optional. The entry's value.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
* Identifier must be a non empty string.
* Identifier [$identifier] must be a valid class.
* Class [$value] must be a subclass of [$identifier], or the same.
Expand Down Expand Up @@ -125,11 +126,11 @@ public function put($identifier, $value = null): bool
*
* @param string $identifier The entry's identifier.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
* Identifier must be a non empty string.
* @throws Amber\Container\Exception\NotFoundExceptionInterface
* @throws NotFoundExceptionInterface
* No entry was found for [$identifier] identifier.
* @throws Amber\Container\Exception\ContainerExceptionInterface
* @throws ContainerExceptionInterface
* Error while retrieving the entry.
*
* @return mixed The entry.
Expand All @@ -144,10 +145,10 @@ final public function get($identifier)

if ($service instanceof ServiceClass) {
return $this->instantiate($service);
} elseif ($service instanceof ServiceClosure) {
$arguments = $this->getArguments($service, '__invoke');
}

return call_user_func_array([$service, '__invoke'], $arguments);
if ($service instanceof ServiceClosure) {
return $this->callClosure($service);
}

return $service;
Expand All @@ -165,6 +166,13 @@ protected function instantiate(ServiceClass $service)
return $service->getInstance($this->getArguments($service));
}

public function callClosure(ServiceClosure $closure)
{
$arguments = $this->getArguments($closure, '__invoke');

return call_user_func_array([$closure, '__invoke'], $arguments);
}

/**
* Gets the arguments for a Service's method.
*
Expand Down Expand Up @@ -237,36 +245,41 @@ public function getArguments($service, string $method = '__construct'): array
$key,
$type,
$argumentType,
"{$service->class}::{$method}()"
"{$service->getName()}::{$method}()"
);
}

return $arguments;
}

/**
* Gets the arguments for a Service's method from the it's arguments bag.
* Gets the argument(s) for a Service's method from the service's arguments bag.
*
* @todo $service parameter should typehint to a Service interface.
*
* @param array $service The params needed by the constructor.
* @param array $key The argument's key.
* @param string $method The method from the service to retrieve the arguments.
* @param ServiceInterface $service The service for retriving it's arguments.
* @param array $key The argument's key name.
*
* @return mixed The argument's value.
*/
protected function getArgumentFromService(string $method, $service, string $key)
protected function getArgumentFromService(string $method, ServiceInterface $service, string $key)
{
if (!method_exists($service, 'hasArgument') || !$service->hasArgument($method, $key)) {
return;
}

$subService = $service->getArgument($method, $key);

if (!$subService instanceof ServiceClass) {
return $subService;
if ($subService instanceof ServiceClass) {
return $this->instantiate($subService);
}

if ($subService instanceof ServiceClosure) {
return $this->callClosure($subService);
}

return $this->instantiate($subService);
return $subService;
}

/**
Expand Down Expand Up @@ -321,7 +334,7 @@ public function clear(): void
*
* @param string $class The item's class.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
*
* @return mixed The value of the item.
*/
Expand All @@ -343,7 +356,7 @@ public function make(string $class)
* @param string $class
* @param string $alias
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
*
* @return ServiceClass
*/
Expand All @@ -369,7 +382,7 @@ public function register(string $class, string $alias = null): ServiceClass
* @param string $class The item's class.
* @param string $alias The item's alias.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
*
* @return ServiceClass
*/
Expand Down
32 changes: 32 additions & 0 deletions src/Contracts/ServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Amber\Container\Contracts;

/**
* Describes the interface of a service.
*/
interface ServiceInterface
{
/**
* Gets the full namespace of the service.
*
* @return string The service's name.
*/
public function getName();

/**
* Gets the Service arguments.
*
* @param string $method The service's method.
*
* @return array
*/
public function getParameters(string $method = '__construct'): array;

/**
* Gets an instance of the Reflection for the current class/closure.
*
* @return \Reflector
*/
public function getReflection(): \Reflector;
}
8 changes: 4 additions & 4 deletions src/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@
*/
class InvalidArgumentException extends BaseException implements ContainerExceptionInterface
{
public static function mustBeString()
public static function mustBeString(): self
{
throw new self('Identifier must be a non empty string.');
}

public static function identifierMustBeClass(string $id)
public static function identifierMustBeClass(string $id): self
{
throw new self("Identifier [{$id}] must be a valid class.");
}

public static function mustBeInstanceOf(string $class)
public static function mustBeInstanceOf(string $class): self
{
throw new self("Argument provided is not an instance of [{$class}].");
}
Expand All @@ -30,7 +30,7 @@ public static function wrongArgumentType(
string $paramType,
string $argumentType,
string $requestedOn
) {
): self {
throw new self(
"Argument for paramater [{$paramName}] must be of type [$paramType]" .
", but [{$argumentType}] provided. Requested on [{$requestedOn}]."
Expand Down
2 changes: 1 addition & 1 deletion src/Exception/NotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class NotFoundException extends ContainerException implements NotFoundExceptionInterface
{
public static function throw(string $identifier)
public static function throw(string $identifier): self
{
throw new self("No entry was found for [{$identifier}] identifier.");
}
Expand Down
45 changes: 29 additions & 16 deletions src/Service/ArgumentsHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
use Amber\Validator\Validator;
use Amber\Container\Container;
use Amber\Container\Exception\InvalidArgumentException;
use Opis\Closure\SerializableClosure;
use Amber\Container\Exception\ContainerException;

/**
* @todo Should replace ContainerException for a more specific exception.
*/
trait ArgumentsHandlerTrait
{
/**
Expand Down Expand Up @@ -34,7 +37,7 @@ trait ArgumentsHandlerTrait
*
* @return \ReflectionClass
*/
public function getReflection(): \ReflectionClass
public function getReflection(): \Reflector
{
if ($this->reflection instanceof \ReflectionClass) {
return $this->reflection;
Expand All @@ -43,9 +46,14 @@ public function getReflection(): \ReflectionClass
return $this->reflection = new \ReflectionClass($this->class);
}

public function hasMethod(string $method)
{
return isset($this->methods[$method]);
}

public function getMethod(string $method): ?ServiceMethod
{
if (isset($this->methods[$method])) {
if ($this->hasMethod($method)) {
return $this->methods[$method];
}

Expand Down Expand Up @@ -73,10 +81,9 @@ public function getParameters(string $method = '__construct'): array
/**
* Stores a Service argument by its key.
*
* @todo COULD set the argument for a specified method.
*
* @param string $key The argument key.
* @param mixed $value The argument value.
* @param string $method The service method.
* @param string $key The argument key.
* @param mixed $value The argument value.
*
* @return self The current service.
*/
Expand All @@ -87,12 +94,16 @@ public function setArgument(string $method, string $key, $value = null): self
InvalidArgumentException::identifierMustBeClass($key);
}

if (is_null($serviceMethod = $this->getMethod($method))) {
throw new ContainerException("Method {$this->getName()}::{$method}() does not exists.");
}

if ($this->isClass($value ?? $key)) {
$this->getMethod($method)->setArgument($key, new ServiceClass($value ?? $key));
$serviceMethod->setArgument($key, new ServiceClass($value ?? $key));
} elseif ($value instanceof \Closure) {
$this->getMethod($method)->setArgument($key, new SerializableClosure($value ?? $key));
$serviceMethod->setArgument($key, new ServiceClosure($value));
} else {
$this->getMethod($method)->setArgument($key, $value);
$serviceMethod->setArgument($key, $value);
}

return $this;
Expand All @@ -107,7 +118,11 @@ public function setArgument(string $method, string $key, $value = null): self
*/
public function hasArgument(string $method, string $key): bool
{
return $this->getMethod($method)->hasArgument($key);
if (is_null($serviceMethod = $this->getMethod($method))) {
throw new ContainerException("Method {$this->getName()}::{$method}() does not exists.");
}

return $serviceMethod->hasArgument($key);
}

/**
Expand All @@ -119,13 +134,11 @@ public function hasArgument(string $method, string $key): bool
*/
public function getArgument(string $method, string $key)
{
$value = $this->getMethod($method)->getArgument($key);

if ($value instanceof SerializableClosure) {
return $value();
if (is_null($serviceMethod = $this->getMethod($method))) {
throw new ContainerException("Method {$this->getName()}::{$method}() does not exists.");
}

return $value;
return $serviceMethod->getArgument($key);
}

/**
Expand Down
16 changes: 12 additions & 4 deletions src/Service/ServiceClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
use Amber\Validator\ValidatorTrait;
use Amber\Container\Container;
use Amber\Container\Exception\InvalidArgumentException;
use Amber\Container\Contracts\ServiceInterface;

class ServiceClass
class ServiceClass implements ServiceInterface
{
use ValidatorTrait, ArgumentsHandlerTrait;
use ValidatorTrait,
ArgumentsHandlerTrait
;

/**
* @var string The class name.
Expand Down Expand Up @@ -45,7 +48,7 @@ public function __construct(string $class)
*
* @param object $instance The instance of the service.
*
* @throws Amber\Container\Exception\InvalidArgumentException
* @throws InvalidArgumentException
*
* @return self The current service.
*/
Expand Down Expand Up @@ -146,7 +149,7 @@ public function singleton(bool $singleton = true): self
/**
* Whether the class is singleton.
*
* @return bool.
* @return bool
*/
public function isSingleton(): bool
{
Expand Down Expand Up @@ -177,6 +180,11 @@ public function afterConstruct(string $method, ...$args): self
return $this;
}

/**
* Gets the full namespace of the service.
*
* @return string The service's name.
*/
public function getName()
{
return $this->getReflection()->getName();
Expand Down
Loading

0 comments on commit 285049e

Please sign in to comment.