Passed
Push — master ( ade161...a5ce50 )
by Divine Niiquaye
02:26
created

Invoker   A

Complexity

Total Complexity 6

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 27
c 1
b 0
f 0
dl 0
loc 87
ccs 30
cts 30
cp 1
rs 10
wmc 6

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getParameterResolver() 0 3 1
A createParameterResolver() 0 11 1
A call() 0 24 2
A __construct() 0 6 1
A getCallableResolver() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of PHP Invoker.
7
 *
8
 * PHP version 7.1 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace DivineNii\Invoker;
19
20
use DivineNii\Invoker\Exceptions\NotEnoughParametersException;
21
use DivineNii\Invoker\Interfaces\ParameterResolverInterface;
22
use Psr\Container\ContainerInterface;
23
use ReflectionParameter;
24
25
/**
26
 * Invoke a callable.
27
 *
28
 * @author Matthieu Napoli <[email protected]>
29
 */
30
class Invoker extends ResolverChain implements Interfaces\InvokerInterface
31
{
32
    /**
33
     * @var CallableResolver
34
     */
35
    private $callableResolver;
36
37
    /**
38
     * @var ParameterResolverInterface
39
     */
40
    private $parameterResolver;
41
42
    /**
43
     * @param callable[]         $resolvers
44
     * @param ContainerInterface $container
45
     */
46 47
    public function __construct(array $resolvers = [], ContainerInterface $container = null)
47
    {
48 47
        parent::__construct($container);
49
50 47
        $this->callableResolver  = new CallableResolver($container);
51 47
        $this->parameterResolver = new ParameterResolver($this->createParameterResolver($resolvers));
52 47
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57 28
    public function call($callable, array $parameters = [])
58
    {
59 28
        $callable           = $this->callableResolver->resolve($callable);
60 22
        $callableReflection = CallableReflection::create($callable);
61 21
        $args               = $this->parameterResolver->getParameters($callableReflection, $parameters);
62
63
        // Sort by array key because call_user_func_array ignores numeric keys
64 21
        \ksort($args);
65
66
        // Check all parameters are resolved
67 21
        $diff = \array_diff_key($callableReflection->getParameters(), $args);
68
69 21
        if (!empty($diff)) {
70
            /** @var ReflectionParameter $parameter */
71 2
            $parameter = \reset($diff);
72
73 2
            throw new NotEnoughParametersException(\sprintf(
74 2
                'Unable to invoke the callable because no value was given for parameter %d ($%s)',
75 2
                $parameter->getPosition() + 1,
76 2
                $parameter->name
77
            ));
78
        }
79
80 19
        return \call_user_func_array($callable, $args);
81
    }
82
83
    /**
84
     * @return ParameterResolverInterface By default it's a ResolverChain
85
     */
86 19
    public function getParameterResolver(): ParameterResolverInterface
87
    {
88 19
        return $this->parameterResolver;
89
    }
90
91
    /**
92
     * @return CallableResolver
93
     */
94 1
    public function getCallableResolver(): CallableResolver
95
    {
96 1
        return $this->callableResolver;
97
    }
98
99
    /**
100
     * Create the parameter resolvers.
101
     *
102
     * @param callable[] $resolvers
103
     *
104
     * @return array<int|string,mixed>
105
     */
106 47
    private function createParameterResolver(array $resolvers): array
107
    {
108 47
        return \array_merge(
109
            [
110 47
                [$this, 'resolveNumericArray'],
111 47
                [$this, 'resolveTypeHint'],
112 47
                [$this, 'resolveAssociativeArray'],
113 47
                [$this, 'resolveDefaultValue'],
114 47
                [$this, 'resolveParameterContainer'],
115
            ],
116 47
            $resolvers
117
        );
118
    }
119
}
120