Completed
Push — master ( 1f44ff...9311e4 )
by Emily
02:16
created

PropertyAccessor::constructObject()   C

Complexity

Conditions 7
Paths 17

Size

Total Lines 46
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 7

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 46
ccs 21
cts 21
cp 1
rs 6.7272
cc 7
eloc 22
nc 17
nop 1
crap 7
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 <emily@emilyshepherd>
12
 * @license MIT
13
 */
14
15
namespace Spaark\CompositeUtils\Service;
16
17
use Spaark\CompositeUtils\Model\Reflection\ReflectionComposite;
18
use Spaark\CompositeUtils\Model\Reflection\Type\ObjectType;
19
use Spaark\CompositeUtils\Model\Reflection\Type\MixedType;
20
use Spaark\CompositeUtils\Model\Reflection\Type\StringType;
21
use Spaark\CompositeUtils\Model\Reflection\Type\IntegerType;
22
use Spaark\CompositeUtils\Model\Reflection\Type\BooleanType;
23
use Spaark\CompositeUtils\Model\Reflection\Type\FloatType;
24
use Spaark\CompositeUtils\Model\Reflection\Type\CollectionType;
25
use Spaark\CompositeUtils\Exception\CannotWritePropertyException;
26
use Spaark\CompositeUtils\Exception\IllegalPropertyTypeException;
27
use Spaark\CompositeUtils\Exception\MissingRequiredParameterException;
28
29
class PropertyAccessor extends RawPropertyAccessor
30
{
31
    /**
32
     * @var ReflectionComposite
33
     */
34
    protected $reflect;
35
36 22
    public function __construct($object, ReflectionComposite $reflect)
37
    {
38 22
        parent::__construct($object);
39
40 22
        $this->reflect = $reflect;
41 22
    }
42
43 6
    public function constructObject(...$args)
44
    {
45 6
        $i = 0;
46 6
        foreach ($this->reflect->requiredProperties as $property)
0 ignored issues
show
Documentation introduced by
The property $requiredProperties 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...
47
        {
48 6
            if (!isset($args[$i]))
49
            {
50 2
                throw new MissingRequiredParameterException
51
                (
52 2
                    get_class($this->object),
53 2
                    $property->name
54
                );
55
            }
56
57 4
            $this->setAnyValue($property, $args[$i]);
58
59 4
            $i++;
60
        }
61
62 4
        $building = false;
63 4
        foreach ($this->reflect->optionalProperties as $property)
0 ignored issues
show
Documentation introduced by
The property $optionalProperties 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...
64
        {
65 4
            if ($building)
66
            {
67 2
                $this->buildProperty($property);
68
            }
69
            else
70
            {
71 4
                if (isset($args[$i]))
72
                {
73 2
                    $this->setAnyValue($property, $args[$i]);
74 2
                    $i++;
75
                }
76
                else
77
                {
78 2
                    $building = true;
79 4
                    $this->buildProperty($property);
80
                }
81
            }
82
        }
83
84 4
        foreach ($this->reflect->builtProperties as $property)
0 ignored issues
show
Documentation introduced by
The property $builtProperties 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...
85
        {
86 4
            $this->buildProperty($property);
87
        }
88 4
    }
89
90 4
    protected function buildProperty($property)
91
    {
92 4
        if ($property->type instanceof ObjectType)
93
        {
94 3
            $class = $property->type->classname;
95 3
            $this->setRawValue($property->name, new $class());
96
        }
97
        else
98
        {
99 3
            $this->setAnyValue($property, 0);
100
        }
101 4
    }
102
103 6
    public function getValue($property)
104
    {
105 6
        return $this->getRawValue($property);
106
    }
107
108 9
    public function setValue($property, $value)
109
    {
110 9
        if (!$this->reflect->properties->contains($property))
0 ignored issues
show
Documentation introduced by
The property $properties 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...
111
        {
112
            throw new CannotWritePropertyException
113
            (
114
                get_class($this->object), $property
115
            );
116
        }
117
118 9
        $this->setAnyValue
119
        (
120 9
            $this->reflect->properties[$property],
0 ignored issues
show
Documentation introduced by
The property $properties 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...
121
            $value
122
        );
123 5
    }
124
125 10
    protected function setAnyValue($property, $value)
126
    {
127 10
        if (is_null($value))
128
        {
129 2
            $this->setNullValue($property->name, $property->type);
130
        }
131
        else
132
        {
133 8
            $this->setNonNullValue
134
            (
135 8
                $property->name,
136
                $value,
137 8
                $property->type
138
            );
139
        }
140 9
    }
141
142 2
    private function setNullValue($property, $type)
143
    {
144 2
        if ($type->nullable)
145
        {
146 1
            $this->setRawValue($property, null);
147
        }
148
        else
149
        {
150 1
            $this->throwError($property, 'NonNull', null);
151
        }
152 1
    }
153
154 8
    private function setNonNullValue($property, $value, $type)
155
    {
156 8
        switch (get_class($type))
157
        {
158 8
            case MixedType::class:
159
                $this->setRawValue($property, $value);
160
                break;
161 8
            case IntegerType::class:
162 1
                $this->setScalarValue($property, $value, 'Integer',
163
                    function($value)
164
                    {
165 1
                        return (integer)$value;
166 1
                    });
167 1
                break;
168 8
            case StringType::class:
169 3
                $this->setScalarValue($property, $value, 'String',
170
                    function($value)
171
                    {
172 3
                        return (string)$value;
173 3
                    });
174 3
                break;
175 7
            case BooleanType::class:
176 5
                $this->setScalarValue($property, $value, 'Boolean',
177 5
                    function($value)
178
                    {
179 5
                        return (boolean)$value;
180 5
                    });
181 5
                break;
182 5
            case CollectionType::class:
183
                $this->setCollectionValue($property, $value);
184
                break;
185 5
            case ObjectType::class:
186 5
                $this->setObjectValue($property, $value, $type);
187 5
                break;
188
        }
189 8
    }
190
191 6
    private function setScalarValue($property, $value, $name, $cast)
192
    {
193 6
        $method = '__to' . $name;
194
195 6
        if (is_scalar($value))
196
        {
197 6
            $this->setRawValue($property, $cast($value));
198
        }
199
        elseif (is_object($value) && method_exists([$value, $method]))
200
        {
201
            $this->setScalarValue
202
            (
203
                $property,
204
                $value->$method(),
205
                $method,
206
                $cast
207
            );
208
        }
209
        else
210
        {
211
            $this->throwError($property, $name, $value);
212
        }
213 6
    }
214
215 5
    private function setObjectValue($property, $value, $type)
216
    {
217 5
        if (is_a($value, $type->classname))
218
        {
219 5
            $this->setRawValue($property, $value);
220
        }
221
        else
222
        {
223
            $this->throwError($property, $type->classname, $value);
224
        }
225 5
    }
226
227
    private function setCollectionValue($property, $value)
228
    {
229
        if (is_a($value, \ArrayAccess::class) || is_array($value))
230
        {
231
            $this->setRawValue($property, $value);
232
        }
233
        else
234
        {
235
            $this->throwError($property, 'Collection', $value);
236
        }
237
    }
238
239 1
    private function throwError($property, $expected, $value)
240
    {
241 1
        throw new IllegalPropertyTypeException
242
        (
243 1
            get_class($this->object),
244
            $property,
245
            $expected,
246 1
            is_object($value) ? get_class($value) : gettype($value)
247
        );
248
    }
249
}
250