Completed
Push — master ( 67167b...b0bc39 )
by Emily
02:46
created

ReflectionMethodFactory::build()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 6.0045

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 19
cts 20
cp 0.95
rs 8.439
c 0
b 0
f 0
cc 6
eloc 20
nc 2
nop 1
crap 6.0045
1
<?php
2
/**
3
 * This file is part of the Composite Utils package.
4
 *
5
 * (c) Emily Shepherd <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the
8
 * LICENSE.md file that was distributed with this source code.
9
 *
10
 * @package spaark/composite-utils
11
 * @author Emily Shepherd <[email protected]>
12
 * @license MIT
13
 */
14
15
namespace Spaark\CompositeUtils\Factory\Reflection;
16
17
use Spaark\CompositeUtils\Model\Reflection\ReflectionComposite;
18
use Spaark\CompositeUtils\Model\Reflection\ReflectionMethod;
19
use Spaark\CompositeUtils\Model\Reflection\ReflectionParameter;
20
use Spaark\CompositeUtils\Service\RawPropertyAccessor;
21
use Spaark\CompositeUtils\Service\TypeComparator;
22
use Spaark\CompositeUtils\Model\Collection\FixedList;
23
use Spaark\CompositeUtils\Model\Collection\HashMap;
24
use \ReflectionMethod as PHPNativeReflectionMethod;
25
use \ReflectionParameter as PHPNativeReflectionParameter;
26
use \Reflector as PHPNativeReflector;
27
28
/**
29
 * Builds a ReflectionMethod for a given method and optionally links
30
 * this to a parent ReflectionComposite
31
 */
32
class ReflectionMethodFactory extends ReflectorFactory
33
{
34
    const REFLECTION_OBJECT = ReflectionMethod::class;
35
36
    /**
37
     * @var PHPNativeReflectionMethod
38
     */
39
    protected $reflector;
40
41
    /**
42
     * @var ReflectionMethod
43
     */
44
    protected $object;
45
46
    /**
47
     * @var Hashmap
48
     */
49
    protected $parameters;
50
51
    /**
52
     * @var TypeParser
53
     */
54
    protected $typeParser;
55
56
    /**
57
     * Returns a new ReflectionMethodFactory using the given class and
58
     * method names
59
     *
60
     * @param string $class The classname of the method
61
     * @param string $method The method to reflect
62
     * @return ReflectionMethodFactory
63
     */
64
    public static function fromName(string $class, string $method)
65
    {
66
        return new static(new PHPNativeReflectionMethod
67
        (
68
            $class, $method
69
        ));
70
    }
71
72 21
    public function __construct(PHPNativeReflector $reflector)
73
    {
74 21
        parent::__construct($reflector);
75
76 21
        $this->parameters = new HashMap();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Spaark\CompositeUti...el\Collection\HashMap() of type object<Spaark\CompositeU...del\Collection\HashMap> is incompatible with the declared type object<Spaark\CompositeU...ory\Reflection\Hashmap> of property $parameters.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
77 21
    }
78
79
    /**
80
     * Builds the ReflectionMethod from the provided parameters,
81
     * optionally linking to a parent ReflectionComposite
82
     *
83
     * @param ReflectionComposite $parent The reflector for the class
84
     *     this method belongs to
85
     * @return ReflectionMethod
86
     */
87 21
    public function build(?ReflectionComposite $parent = null)
88
    {
89 21
        $this->typeParser = new TypeParser($parent);
90 21
        $this->accessor->setRawValue('owner', $parent);
91 21
        $this->accessor->setRawValue
92
        (
93 21
            'name',
94 21
            $this->reflector->getName()
0 ignored issues
show
Bug introduced by
Consider using $this->reflector->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
95
        );
96
97 21
        $this->initParams();
98
99 21
        $this->accessor->setRawValue('visibility',
100 21
              ($this->reflector->isPublic() ? 'public'
101 2
            : ($this->reflector->isProtected() ? 'protected'
102
            : ($this->reflector->isPrivate() ? 'private'
103 21
            : (''))))
104
        );
105 21
        $this->accessor->setRawValue('scope',
106 21
            ($this->reflector->isStatic() ? 'static' : 'dynamic')
107
        );
108 21
        $this->accessor->setRawValue('final',
109 21
            $this->reflector->isFinal()
110
        );
111
112 21
        foreach ($this->reflector->getParameters() as $parameter)
113
        {
114 21
            $this->addParameter($parameter);
115
        }
116
117 21
        $this->parseDocComment(['param' => 'addParamAnnotation']);
118
119 21
        return $this->object;
120
    }
121
122
    /**
123
     * Creates the Method's parameter's property with a fixd list of
124
     * the appropriate size
125
     */
126 21
    protected function initParams()
127
    {
128 21
        $this->accessor->setRawValue
129
        (
130 21
            'parameters',
131 21
            new FixedList(count($this->reflector->getParameters()))
132
        );
133 21
        $this->accessor->setRawValue
134
        (
135 21
            'nativeParameters',
136 21
            new FixedList(count($this->reflector->getParameters()))
137
        );
138 21
    }
139
140
    /**
141
     * Processes a param docblock annotation and uses it to decorate
142
     * a method parameter
143
     *
144
     * @param string $name Unused. Should be 'param'
145
     * @param string $value The annotation value
146
     */
147 21
    protected function addParamAnnotation($name, $value) : void
0 ignored issues
show
Unused Code introduced by
The parameter $name is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
148
    {
149 21
        $items = explode(' ', $value);
150 21
        $type = $items[0];
151 21
        $param = $items[1];
152
153 21
        if (!$this->parameters->containsKey($param))
154
        {
155
            throw new \Exception
156
            (
157
                  'Tried to set param annotation for non existant '
158
                . 'parameter: ' . $param
159
            );
160
        }
161
162 21
        $comparator = new TypeComparator();
163 21
        $type = $this->typeParser->parse($type);
164 21
        $param = $this->parameters[$param];
165 21
        $nativeType = $param->getRawValue('type');
166
167 21
        if (!$comparator->compatible($nativeType, $type))
168
        {
169
            throw new \Exception('Types are incompatible');
170
        }
171
172 21
        $param->setRawValue('type', $type);
173 21
    }
174
175
    /**
176
     * Adds a parameter to the method, based on it's native
177
     * ReflectionParameter
178
     *
179
     * @param PHPNativeReflectionParameter $reflect
180
     */
181 21
    protected function addParameter
182
    (
183
        PHPNativeReflectionParameter $reflect
184
    )
185
    : void
186
    {
187 21
        $parameter = new ReflectionParameter();
188 21
        $accessor = new RawPropertyAccessor($parameter);
189 21
        $type = (new TypeParser())->parse((string)$reflect->getType());
190
191 21
        $this->parameters['$' . $reflect->getName()] = $accessor;
0 ignored issues
show
Bug introduced by
Consider using $reflect->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
192 21
        $this->accessor->rawAddToValue('parameters', $parameter);
0 ignored issues
show
Deprecated Code introduced by
The method Spaark\CompositeUtils\Se...cessor::rawAddToValue() has been deprecated.

This method has been deprecated.

Loading history...
193 21
        $this->accessor->rawAddToValue('nativeParameters',
0 ignored issues
show
Deprecated Code introduced by
The method Spaark\CompositeUtils\Se...cessor::rawAddToValue() has been deprecated.

This method has been deprecated.

Loading history...
194 21
            (string)$reflect->getType()
195
        );
196
197 21
        $accessor->setRawValue('owner', $this->object);
198 21
        $accessor->setRawValue('name', $reflect->getName());
0 ignored issues
show
Bug introduced by
Consider using $reflect->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
199 21
        $accessor->setRawValue('type', $type);
200 21
    }
201
}
202
203