Completed
Pull Request — master (#3)
by Emily
01:57
created

ReflectionCompositeFactory::initObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 9
cts 9
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
nc 1
nop 0
crap 1
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\Factory\BaseFactory;
18
use Spaark\CompositeUtils\Model\Reflection\ReflectionComposite;
19
use Spaark\CompositeUtils\Model\Reflection\ReflectionProperty;
20
use Spaark\CompositeUtils\Model\Reflection\ReflectionMethod;
21
use Spaark\CompositeUtils\Model\Collection\FixedList;
22
use Spaark\CompositeUtils\Service\ReflectionCompositeProviderInterface;
23
use Spaark\CompositeUtils\Service\ReflectionCompositeProvider;
24
use \ReflectionClass as PHPNativeReflectionClass;
25
use \ReflectionProperty as PHPNativeReflectionProperty;
26
use \ReflectionMethod as PHPNativeReflectionMethod;
27
use \Reflector;
28
29
/**
30
 * Builds a ReflectionComposite for a given class
31
 */
32
class ReflectionCompositeFactory extends ReflectorFactory
33
{
34
    const REFLECTION_OBJECT = ReflectionComposite::class;
35
36
    /**
37
     * @var PHPNativeReflector
38
     */
39
    protected $reflector;
40
41
    /**
42
     * @var ReflectionComposite
43
     */
44
    protected $object;
45
46
    /**
47
     * @var ReflectionCompositeProviderInterface
48
     */
49
    protected $provider;
50
51
    /**
52
     * Creates a new ReflectionCompositeFactory from the given
53
     * classname
54
     *
55
     * @param string $classname The class to build a reflect upon
56
     * @return ReflectionCompositeFactory
57
     */
58 20
    public static function fromClassName(string $classname)
59
    {
60 20
        return new static
61
        (
62 20
            new PHPNativeReflectionClass($classname),
63 20
            ReflectionCompositeProvider::getDefault()
64
        );
65
    }
66
67
    /**
68
     * Constructs the Factory with the given reflector and Composite
69
     * provider
70
     *
71
     * @param PHPNativeReflectionClass $reflect
72
     * @param ReflectionCompositeProviderInterface $provider
73
     */
74 20
    public function __construct
75
    (
76
        PHPNativeReflectionClass $reflect,
77
        ReflectionCompositeProviderInterface $provider
78
    )
79
    {
80 20
        parent::__construct($reflect);
81 20
        $this->provider = $provider;
82 20
    }
83
84
    /**
85
     * Builds the ReflectionComposite from the provided parameters
86
     *
87
     * @return ReflectionComposite
88
     */
89 20
    public function build()
90
    {
91 20
        $this->initObject();
92
93 20
        foreach ($this->reflector->getTraits() as $trait)
94
        {
95 3
            $this->addInheritance('traits', $trait);
96
        }
97
98 20
        if ($parent = $this->reflector->getParentClass())
99
        {
100 2
            $this->addInheritance('parent', $parent, 'setRawValue');
101
        }
102
103 20
        foreach ($this->reflector->getInterfaces() as $interface)
104
        {
105 1
            $this->addInheritance('interfaces', $interface);
106
        }
107
108 20
        $fileName = $this->reflector->getFileName();
109
110 20
        $file = (new ReflectionFileFactory($fileName))->build();
111 20
        $this->accessor->setRawValue('file', $file);
112
113 20
        $this->accessor->setRawValue
114
        (
115 20
            'classname',
116 20
            $this->reflector->name
117
        );
118 20
        $this->accessor->setRawValue
119
        (
120 20
            'namespace',
121 20
            $file->namespaces[$this->reflector->getNamespaceName()]
122
        );
123
124 20
        $this->addItems('properties', false, 'Property');
125 20
        $this->addItems('methods', true, 'Method');
126
127 20
        $this->object->traits->resizeToFull();
0 ignored issues
show
Documentation introduced by
The property $traits is declared protected in Spaark\CompositeUtils\Mo...ion\ReflectionComposite. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
128 20
        $this->object->interfaces->resizeToFull();
0 ignored issues
show
Documentation introduced by
The property $interfaces is declared protected in Spaark\CompositeUtils\Mo...ion\ReflectionComposite. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
129 20
        $this->object->localProperties->resizeToFull();
0 ignored issues
show
Documentation introduced by
The property $localProperties is declared protected in Spaark\CompositeUtils\Mo...ion\ReflectionComposite. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
130 20
        $this->object->requiredProperties->resizeToFull();
131 20
        $this->object->optionalProperties->resizeToFull();
132 20
        $this->object->builtProperties->resizeToFull();
133 20
        $this->object->localMethods->resizeToFull();
0 ignored issues
show
Documentation introduced by
The property $localMethods is declared protected in Spaark\CompositeUtils\Mo...ion\ReflectionComposite. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
134
135 20
        return $this->object;
136
    }
137
138 20
    protected function initObject()
139
    {
140 20
        $this->initFixedList('traits');
141 20
        $this->initFixedList('interfaces');
142 20
        $this->initFixedList('Properties', 'local');
143 20
        $this->initFixedList('Properties', 'required');
144 20
        $this->initFixedList('Properties', 'optional');
145 20
        $this->initFixedList('Properties', 'built');
146 20
        $this->initFixedList('Methods', 'local');
147 20
    }
148
149 20
    protected function initFixedList(string $name, string $prefix = '')
150
    {
151 20
        $this->accessor->setRawValue
152
        (
153 20
            $prefix . $name,
154 20
            new FixedList(count($this->reflector->{'get' . $name}()))
155
        );
156 20
    }
157
158
    /**
159
     * Loops through the list methods or properties adding them to the
160
     * Composite
161
     *
162
     * @param string $name
163
     * @param bool $checkFile
164
     * @param string $singular
0 ignored issues
show
Bug introduced by
There is no parameter named $singular. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
165
     */
166 20
    protected function addItems
167
    (
168
        string $name,
169
        bool $checkFile,
170
        string $signular
171
    )
172
    {
173 20
        foreach ($this->reflector->{'get' . $name}() as $item)
174
        {
175
            // We only reflect on methods in userspace
176 20
            if ($checkFile && !$item->getFileName())
177
            {
178 1
                continue;
179
            }
180
            // This belongs to a super class, use that definition
181
            // instead
182 20
            elseif ($item->class !== $this->reflector->getName())
183
            {
184 2
                $item = $this->provider->get($item->class)
185 2
                    ->$name[$item->getName()];
186
            }
187
            // Parse this method
188
            else
189
            {
190
                $factory =
191
                      '\Spaark\CompositeUtils\Factory\Reflection'
192 20
                    . '\Reflection' . $signular . 'Factory';
193 20
                $item = $this->{'build' . $signular}
194
                (
195 20
                    new $factory($item),
196
                    $item
197
                );
198 20
                $this->accessor->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...
199
                (
200 20
                    'local' . ucfirst($name),
201
                    $item
202
                );
203
            }
204
205 20
            $this->accessor->getRawValue($name)[$item->name] = $item;
206
        }
207 20
    }
208
209
    /**
210
     * Adds a super class / interface / trait to this Composite
211
     *
212
     * @param string $group The type of superclass (parent, etc...)
213
     * @param PHPNativeReflectionClass $reflect
214
     * @param string $method
215
     */
216 4
    protected function addInheritance
217
    (
218
        string $group,
219
        PHPNativeReflectionClass $reflect,
220
        string $method = 'rawAddToValue'
221
    )
222
    {
223
        // We only reflect on classes within userspace
224 4
        if ($reflect->getFileName())
225
        {
226 4
            $item = $this->provider->get($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...
227 4
            $this->accessor->$method($group, $item);
228
        }
229 4
    }
230
231
    /**
232
     * Uses a ReflectionPropertyFactory to build a ReflectionProperty
233
     *
234
     * @param ReflectionPropertyFactory $factory
235
     * @return ReflectionProperty
236
     */
237 20
    protected function buildProperty
238
    (
239
        ReflectionPropertyFactory $factory,
240
        PHPNativeReflectionProperty $reflect
241
    )
242
    : ReflectionProperty
243
    {
244 20
        return $factory->build
245
        (
246 20
            $this->object,
247 20
            $this->reflector
248 20
                ->getDefaultProperties()[$reflect->getName()]
249
        );
250
    }
251
252
    /**
253
     * Uses a ReflectionMethodFactory to build a ReflectionMethod
254
     *
255
     * @param ReflectionMethodFactory $factory
256
     * @return ReflectionMethod
257
     */
258 20
    protected function buildMethod(ReflectionMethodFactory $factory)
259
        : ReflectionMethod
260
    {
261 20
        return $factory->build($this->object);
262
    }
263
}
264
265