AutowiringTrait   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 90
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 28
dl 0
loc 90
rs 10
c 1
b 0
f 1
wmc 14

4 Methods

Rating   Name   Duplication   Size   Complexity  
A isTypeMatched() 0 8 3
A isRequiredClass() 0 7 3
A getObjectByClass() 0 15 4
A matchArguments() 0 13 4
1
<?php
2
3
/**
4
 * Phoole (PHP7.2+)
5
 *
6
 * @category  Library
7
 * @package   Phoole\Di
8
 * @copyright Copyright (c) 2019 Hong Zhang
9
 */
10
declare(strict_types=1);
11
12
namespace Phoole\Di\Util;
13
14
use Phoole\Di\Container;
15
use Phoole\Base\Reflect\ParameterTrait;
16
use Phoole\Di\Exception\UnresolvedClassException;
17
18
/**
19
 * AutowiringTrait
20
 *
21
 * Automatically resolve Dependency::class stuff
22
 *
23
 * @package Phoole\Di
24
 */
25
trait AutowiringTrait
26
{
27
    use ClassmapTrait;
28
    use ParameterTrait;
29
30
    /**
31
     * enable autowiring or not
32
     *
33
     * @var bool
34
     */
35
    protected $autoLoad = FALSE;
36
37
    /**
38
     * match provided arguments with defined parameters
39
     *
40
     * @param  array                  $providedArguments
41
     * @param  \ReflectionParameter[] $reflectionParameters
42
     * @return array
43
     * @throws UnresolvedClassException
44
     */
45
    protected function matchArguments(
46
        array $providedArguments,
47
        array $reflectionParameters
48
    ): array {
49
        $resolvedArguments = [];
50
        foreach ($reflectionParameters as $i => $param) {
51
            if ($this->isTypeMatched($param->getClass(), $providedArguments)) {
52
                $resolvedArguments[$i] = array_shift($providedArguments);
53
            } elseif ($this->isRequiredClass($param, $providedArguments)) {
54
                $resolvedArguments[$i] = $this->getObjectByClass($param->getClass()->name);
55
            }
56
        }
57
        return array_merge($resolvedArguments, $providedArguments);
58
    }
59
60
    /**
61
     * Try best to guess parameter and argument are the same type
62
     *
63
     * @param  null|\ReflectionClass $class
64
     * @param  array                 $arguments
65
     * @return bool
66
     */
67
    protected function isTypeMatched($class, array $arguments): bool
68
    {
69
        if (empty($arguments)) {
70
            return FALSE;
71
        } elseif (NULL !== $class) {
72
            return is_a($arguments[0], $class->name);
73
        } else {
74
            return TRUE;
75
        }
76
    }
77
78
    /**
79
     * Is $param required and is a class/interface
80
     *
81
     * @param  \ReflectionParameter $param
82
     * @param  array                $arguments
83
     * @return bool
84
     */
85
    protected function isRequiredClass(\ReflectionParameter $param, array $arguments): bool
86
    {
87
        $optional = $param->isOptional();
88
        if ($param->getClass()) {
89
            return !$optional || !empty($arguments);
90
        } else {
91
            return FALSE;
92
        }
93
    }
94
95
    /**
96
     * @param  string $classname
97
     * @return object
98
     * @throws UnresolvedClassException
99
     */
100
    protected function getObjectByClass(string $classname): object
101
    {
102
        // try classmap FIRST!
103
        $object = $this->matchClass($classname);
104
        if (is_object($object)) {
105
            return $object;
106
        }
107
108
        // try autowiring IF ENABLED
109
        if ($this->autoLoad && class_exists($classname)) {
110
            return Container::create($classname);
111
        }
112
113
        // not found
114
        throw new UnresolvedClassException($classname);
115
    }
116
}