Skip to content

Commit

Permalink
Merge pull request #2809 from mapogolions/maintenance/duplicate-code
Browse files Browse the repository at this point in the history
4.x - Eliminate a duplicate code via HOF
  • Loading branch information
l0gicgate committed Aug 19, 2019
2 parents a139440 + 772c5ad commit 200e72a
Showing 1 changed file with 77 additions and 64 deletions.
141 changes: 77 additions & 64 deletions Slim/CallableResolver.php
Expand Up @@ -41,89 +41,94 @@ public function __construct(?ContainerInterface $container = null)
*/
public function resolve($toResolve): callable
{
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;

if (!is_callable($toResolve) && is_string($toResolve)) {
$resolved = $this->resolveInstanceAndMethod($toResolve);
if ($resolved[1] === null) {
$resolved[1] = '__invoke';
}
if (is_string($toResolve)) {
$resolved = $this->resolveSlimNotation($toResolve);
$resolved[1] = $resolved[1] ?? '__invoke';
}

return $this->assertCallableAndBindClosureToContainer($resolved, $toResolve);
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}

/**
* {@inheritdoc}
*/
public function resolveRoute($toResolve): callable
{
$resolved = $toResolve;

if (!is_callable($toResolve) && is_string($toResolve)) {
[$instance, $method] = $this->resolveInstanceAndMethod($toResolve);

// For a class that implements RequestHandlerInterface, we will call handle()
// if no method has been specified explicitly
if ($instance instanceof RequestHandlerInterface && $method === null) {
$method = 'handle';
}

$resolved = [$instance, $method ?? '__invoke'];
}

if ($resolved instanceof RequestHandlerInterface) {
$resolved = [$resolved, 'handle'];
}

return $this->assertCallableAndBindClosureToContainer($resolved, $toResolve);
return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle');
}

/**
* {@inheritdoc}
*/
public function resolveMiddleware($toResolve): callable
{
$resolved = $toResolve;

if (!is_callable($toResolve) && is_string($toResolve)) {
[$instance, $method] = $this->resolveInstanceAndMethod($toResolve);
return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process');
}

// For a class that implements MiddlewareInterface, we will call process()
// if no method has been specified explicitly
if ($instance instanceof MiddlewareInterface && $method === null) {
$method = 'process';
/**
* @param string|callable $toResolve
* @param callable $predicate
* @param string $defaultMethod
*
* @throws RuntimeException
*
* @return callable
*/
private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable
{
if (is_callable($toResolve)) {
return $this->bindToContainer($toResolve);
}
$resolved = $toResolve;
if ($predicate($toResolve)) {
$resolved = [$toResolve, $defaultMethod];
}
if (is_string($toResolve)) {
[$instance, $method] = $this->resolveSlimNotation($toResolve);
if ($predicate($instance) && $method === null) {
$method = $defaultMethod;
}

$resolved = [$instance, $method ?? '__invoke'];
}
$callable = $this->assertCallable($resolved, $toResolve);
return $this->bindToContainer($callable);
}

if ($resolved instanceof MiddlewareInterface) {
$resolved = [$resolved, 'process'];
}

return $this->assertCallableAndBindClosureToContainer($resolved, $toResolve);
/**
* @param mixed $toResolve
*
* @return bool
*/
private function isRoute($toResolve): bool
{
return $toResolve instanceof RequestHandlerInterface;
}

/**
* Resolves the given param and if successful returns an instance as well
* as a method name.
* @param mixed $toResolve
*
* @return bool
*/
private function isMiddleware($toResolve): bool
{
return $toResolve instanceof MiddlewareInterface;
}

/**
* @param string $toResolve
*
* @throws RuntimeException
*
* @return array [Instance, Method Name]
*/
private function resolveInstanceAndMethod(string $toResolve): array
private function resolveSlimNotation(string $toResolve): array
{
$class = $toResolve;
$instance = null;
$method = null;

// Check for Slim callable as `class:method`
if (preg_match(CallableResolver::$callablePattern, $toResolve, $matches)) {
$class = $matches[1];
$method = $matches[2];
}
preg_match(CallableResolver::$callablePattern, $toResolve, $matches);
[$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null];

if ($this->container && $this->container->has($class)) {
$instance = $this->container->get($class);
Expand All @@ -133,17 +138,18 @@ private function resolveInstanceAndMethod(string $toResolve): array
}
$instance = new $class($this->container);
}

return [$instance, $method];
}

/**
* @param mixed $resolved
* @param string|object|array|callable $toResolve
* @param mixed $resolved
* @param mixed $toResolve
*
* @throws RuntimeException
*
* @return callable
*/
private function assertCallableAndBindClosureToContainer($resolved, $toResolve): callable
private function assertCallable($resolved, $toResolve): callable
{
if (!is_callable($resolved)) {
throw new RuntimeException(sprintf(
Expand All @@ -152,15 +158,22 @@ private function assertCallableAndBindClosureToContainer($resolved, $toResolve):
json_encode($toResolve) : $toResolve
));
}
return $resolved;
}

if (is_array($resolved) && $resolved[0] instanceof Closure) {
$resolved = $resolved[0];
/**
* @param callable $callable
*
* @return callable
*/
private function bindToContainer(callable $callable): callable
{
if (is_array($callable) && $callable[0] instanceof Closure) {
$callable = $callable[0];
}

if ($this->container && $resolved instanceof Closure) {
$resolved = $resolved->bindTo($this->container);
if ($this->container && $callable instanceof Closure) {
$callable = $callable->bindTo($this->container);
}

return $resolved;
return $callable;
}
}

0 comments on commit 200e72a

Please sign in to comment.