Passed
Push — 2.0 ( df1b1e...20b3e4 )
by Zaahid
08:44 queued 05:27
created

Container   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 88.1%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 19
eloc 40
c 1
b 0
f 0
dl 0
loc 100
ccs 37
cts 42
cp 0.881
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetExists() 0 8 3
A offsetGet() 0 11 3
A extend() 0 4 1
A getParameterClass() 0 11 6
A autoRegister() 0 22 6
1
<?php
2
/**
3
 * This file is part of the ZBateson\MailMimeParser project.
4
 *
5
 * @license http://opensource.org/licenses/bsd-license.php BSD
6
 */
7
8
namespace ZBateson\MailMimeParser;
9
10
use Pimple\Container as PimpleContainer;
11
use Pimple\Exception\UnknownIdentifierException;
12
use ReflectionClass;
13
use ReflectionParameter;
14
15
/**
16
 * Automatically configures classes and dependencies.
17
 *
18
 * Sets up an automatic registration for classes when requested through
19
 * Pimple by looking up the class's constructor and arguments.
20
 *
21
 * @author Zaahid Bateson
22
 */
23
class Container extends PimpleContainer
24
{
25
    /**
26
     * Looks up the type of the passed ReflectionParameter and returns it as a
27
     * fully qualified class name as expected by the class's auto registration.
28
     *
29
     * Null is returned for built-in types.
30
     *
31
     */
32 3
    private function getParameterClass(ReflectionParameter $param) : ?string
33
    {
34 3
        if (\method_exists($param, 'getType')) {
35 3
            $type = $param->getType();
36 3
            if ($type && !$type->isBuiltin()) {
37 2
                return \method_exists($type, 'getName') ? $type->getName() : (string) $type;
38
            }
39
        } elseif ($param->getClass() !== null) {
40
            return $param->getClass()->getName();
41
        }
42 2
        return null;
43
    }
44
45
    /**
46
     * Returns a factory function for the passed class.
47
     *
48
     * The returned factory method looks up arguments and uses pimple to get an
49
     * instance of those types to pass them during construction.
50
     */
51 3
    public function autoRegister($class) : ?string
52
    {
53 3
        $fn = function($c) use ($class) {
0 ignored issues
show
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
54 3
            $ref = new ReflectionClass($class);
55 3
            $cargs = ($ref->getConstructor() !== null) ? $ref->getConstructor()->getParameters() : [];
56 3
            $ap = [];
57 3
            foreach ($cargs as $arg) {
58 3
                $name = $arg->getName();
59 3
                $argClass = $this->getParameterClass($arg);
60 3
                if (!empty($c[$name])) {
61 1
                    $ap[] = $c[$name];
62 3
                } elseif ($argClass !== null && !empty($c[$argClass])) {
63 2
                    $ap[] = $c[$argClass];
64
                } else {
65 2
                    $ap[] = 0;
66
                }
67
            }
68 3
            $ret = $ref->newInstanceArgs($ap);
69 3
            return $ret;
70 3
        };
71 3
        $this[$class] = $fn;
72 3
        return null;
73
    }
74
75
    /**
76
     * Overridden to see if the class can be auto-registered and return true if
77
     * it can.
78
     */
79 3
    public function offsetExists($id) : bool
80
    {
81 3
        $exists = parent::offsetExists($id);
82 3
        if (!$exists && \class_exists($id)) {
83 3
            $this->autoRegister($id);
84 3
            return true;
85
        }
86 3
        return $exists;
87
    }
88
89
    /**
90
     * Overridden to see if the class can be auto-registered and return an
91
     * instance if it can.
92
     *
93
     * @param string | int $id
94
     *
95
     * @throws UnknownIdentifierException
96
     */
97 108
    #[\ReturnTypeWillChange]
98
    public function offsetGet($id)
99
    {
100
        try {
101 108
            return parent::offsetGet($id);
102 3
        } catch (UnknownIdentifierException $e) {
103 3
            if (\class_exists($id)) {
104 3
                $this->autoRegister($id);
105 3
                return parent::offsetGet($id);
106
            }
107 1
            throw $e;
108
        }
109
    }
110
111
    /**
112
     * Overridden to see if the class can be auto-registered first before
113
     * calling Pimple\Container::extend
114
     *
115
     * @param string $id
116
     * @param callable $callable
117
     * @return callable the wrapped $callable
118
     */
119
    public function extend($id, $callable)
120
    {
121
        $this->offsetExists($id);
122
        return parent::extend($id, $callable);
123
    }
124
}
125