Passed
Pull Request — master (#171)
by Zaahid
06:32 queued 03:18
created

Container::getParameterClass()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 6.5625

Importance

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