Completed
Push — master ( 887cf7...2ea773 )
by Emily
02:13
created

ReflectionPropertyFactory::build()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 0
cts 12
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 2
crap 2
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\ReflectionProperty;
19
use Spaark\CompositeUtils\Model\Reflection\ReflectionParameter;
20
use Spaark\CompositeUtils\Model\Reflection\Type\BooleanType;
21
use Spaark\CompositeUtils\Model\Reflection\Type\CollectionType;
22
use Spaark\CompositeUtils\Model\Reflection\Type\IntegerType;
23
use Spaark\CompositeUtils\Model\Reflection\Type\MixedType;
24
use Spaark\CompositeUtils\Model\Reflection\Type\ObjectType;
25
use Spaark\CompositeUtils\Model\Reflection\Type\StringType;
26
use Spaark\CompositeUtils\Service\RawPropertyAccessor;
27
use \ReflectionProperty as PHPNativeReflectionProperty;
28
29
/**
30
 * Builds a ReflectionProperty for a given class and property name
31
 */
32
class ReflectionPropertyFactory extends ReflectorFactory
33
{
34
    const REFLECTION_OBJECT = ReflectionProperty::class;
35
36
    /**
37
     * @var PHPNativeReflectionProperty
38
     */
39
    protected $reflector;
40
41
    /**
42
     * @var ReflectionProperty
43
     */
44
    protected $object;
45
46
    /**
47
     * {@inheritDoc}
48
     */
49
    protected $acceptedParams =
50
    [
51
        'readable' => 'setBool',
52
        'writable' => 'setBool',
53
        'var' => 'setType',
54
        'construct' => 'setConstruct'
55
    ];
56
57
    /**
58
     * Returns a new ReflectionPropertyFactory using the given class and
59
     * property names
60
     *
61
     * @param string $class The classname of the property
62
     * @param string $property The property to reflect
63
     * @return ReflectionPropertyFactory
64
     */
65
    public static function fromName($class, $property)
66
    {
67
        return new static(new PHPNativeReflectionProperty
68
        (
69
            $class, $property
70
        ));
71
    }
72
73
    /**
74
     * Builds the ReflectionProperty from the provided parameters,
75
     * linking to a parent ReflectionComposite
76
     *
77
     * @param ReflectionCompostite $parent The reflector for the class
78
     *     this property belongs to
79
     * @param mixed $default This property's default value
80
     * @return ReflectionProperty
81
     */
82
    public function build(ReflectionComposite $parent, $default)
83
    {
84
        $this->accessor->setRawValue('owner', $parent);
85
        $this->accessor->setRawValue('defaultValue', $default);
86
        $this->accessor->setRawValue
87
        (
88
            'name',
89
            $this->reflector->getName()
90
        );
91
92
        $this->parseDocComment();
93
94
        return $this->object;
95
    }
96
97
    /**
98
     * Sets the property's type by parsing the @type annotation
99
     *
100
     * @param string $name Should be 'var'
101
     * @param string $value The value of the annotation
102
     */
103
    protected function setType($name, $value)
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...
104
    {
105 View Code Duplication
        if ($value{0} !== '?')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
106
        {
107
            $nullable = false;
108
        }
109
        else
110
        {
111
            $nullable = true;
112
            $value = substr($value, 1);
113
        }
114
115 View Code Duplication
        if (substr($value, -2) !== '[]')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
        {
117
            $collection = false;
118
        }
119
        else
120
        {
121
            $collection = true;
122
            $value = substr($value, 0, -2);
123
        }
124
125
        switch ($value)
126
        {
127
            case 'string':
128
                $class = new StringType();
129
                break;
130
            case 'int':
131
            case 'integer':
132
                $class = new IntegerType();
133
                break;
134
            case 'bool':
135
            case 'boolean':
136
                $class = new BooleanType();
137
                break;
138
            case 'mixed':
139
            case '':
140
                $class = new MixedType();
141
                break;
142
            case 'null':
143
                $class = new NullType();
144
                break;
145
            default:
146
                $useStatements =
147
                    $this->object->owner->namespace->useStatements;
148
149
                if ($useStatements->containsKey($value))
0 ignored issues
show
Documentation introduced by
$value is of type string, but the function expects a object<Spaark\CompositeU...del\Collection\KeyType>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
150
                {
151
                    $value = $useStatements[$value]->classname;
152
                }
153
                else
154
                {
155
                    $value = $this->object->owner->namespace->namespace
156
                        . '\\' . $value;
157
                }
158
159
                $class = new ObjectType($value);
160
        }
161
162
        if ($nullable)
163
        {
164
            (new RawPropertyAccessor($class))
165
                ->setRawValue('nullable', true);
166
        }
167
168
        if ($collection)
169
        {
170
            $class = new CollectionType($class);
171
        }
172
173
        $this->accessor->setRawValue('type', $class);
174
    }
175
176
    /**
177
     * Sets the property's constructor options by parsing the @construct
178
     * annotation
179
     *
180
     * @param string $name Should be 'construct'
181
     * @param string $value The value of the annotation
182
     */
183
    protected function setConstruct($name, $value)
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...
184
    {
185
        $value = explode(' ', $value);
186
        $compositeAccessor =
187
            new RawPropertyAccessor($this->object->owner);
188
189
        switch ($value[0])
190
        {
191
            case 'required':
192
                $this->accessor->setRawValue
193
                (
194
                    'passedToConstructor',
195
                    true
196
                );
197
                $this->accessor->setRawValue
198
                (
199
                    'requiredInConstructor',
200
                    true
201
                );
202
                $compositeAccessor->rawAddToValue
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...
203
                (
204
                    'requiredProperties',
205
                    $this->object
206
                );
207
                break;
208
            case 'new':
209
                $this->accessor->setRawValue
210
                (
211
                    'builtInConstructor',
212
                    true
213
                );
214
                $compositeAccessor->rawAddToValue
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...
215
                (
216
                    'builtProperties',
217
                    $this->object
218
                );
219
                break;
220
            case 'optional':
221
                $this->accessor->setRawValue
222
                (
223
                    'passedToConstructor',
224
                    true
225
                );
226
                $compositeAccessor->rawAddToValue
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...
227
                (
228
                    'optionalProperties',
229
                    $this->object
230
                );
231
232
                if (isset($value[1]) && $value[1] === 'new')
233
                {
234
                    $this->accessor->setRawValue
235
                    (
236
                        'builtInConstructor',
237
                        true
238
                    );
239
                }
240
        }
241
    }
242
}
243
244