Completed
Push — master ( 46b7df...4cf19c )
by Emily
02:25
created

PropertyAccessor::setNullValue()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
crap 2
1
<?php
2
3
namespace Spaark\CompositeUtils\Service;
4
5
use Spaark\CompositeUtils\Model\Reflection\ReflectionComposite;
6
use Spaark\CompositeUtils\Model\Reflection\Type\ObjectType;
7
use Spaark\CompositeUtils\Model\Reflection\Type\MixedType;
8
use Spaark\CompositeUtils\Model\Reflection\Type\StringType;
9
use Spaark\CompositeUtils\Model\Reflection\Type\IntegerType;
10
use Spaark\CompositeUtils\Model\Reflection\Type\BooleanType;
11
use Spaark\CompositeUtils\Model\Reflection\Type\FloatType;
12
use Spaark\CompositeUtils\Model\Reflection\Type\CollectionType;
13
use Spaark\CompositeUtils\Exception\CannotWritePropertyException;
14
use Spaark\CompositeUtils\Exception\IllegalPropertyTypeException;
15
16
class PropertyAccessor extends RawPropertyAccessor
17
{
18
    /**
19
     * @var ReflectionComposite
20
     */
21
    protected $reflect;
22
23 8
    public function __construct($object, ReflectionComposite $reflect)
24
    {
25 8
        parent::__construct($object);
26
27 8
        $this->reflect = $reflect;
28 8
    }
29
30 4
    public function getValue($property)
31
    {
32 4
        return $this->getRawValue($property);
33
    }
34
35 5
    public function setValue($property, $value)
36
    {
37 5
        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...
38
        {
39
            throw new CannotWritePropertyException
40
            (
41
                get_class($this->object), $property
42
            );
43
        }
44
45 5
        $this->setAnyValue
46
        (
47 5
            $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...
48
            $value
49
        );
50 3
    }
51
52 4
    protected function setAnyValue($property, $value)
53
    {
54 4
        if (is_null($value))
55
        {
56 2
            $this->setNullValue($property->name, $property->type);
57
        }
58
        else
59
        {
60 2
            $this->setNonNullValue
61
            (
62 2
                $property->name,
63
                $value,
64 2
                $property->type
65
            );
66
        }
67 3
    }
68
69 2
    private function setNullValue($property, $type)
70
    {
71 2
        if ($type->nullable)
72
        {
73 1
            $this->setRawValue($property, null);
74
        }
75
        else
76
        {
77 1
            $this->throwError($property, 'NonNull', null);
78
        }
79 1
    }
80
81 2
    private function setNonNullValue($property, $value, $type)
82
    {
83 2
        switch (get_class($type))
84
        {
85 2
            case MixedType::class:
86
                $this->setRawValue($property, $value);
87
                break;
88 2
            case IntegerType::class:
89
                $this->setScalarValue($property, $value, 'Integer',
90
                    function($value)
91
                    {
92
                        return (integer)$value;
93
                    });
94
                break;
95 2
            case StringType::class:
96 1
                $this->setScalarValue($property, $value, 'String',
97
                    function($value)
98
                    {
99 1
                        return (string)$value;
100 1
                    });
101 1
                break;
102 1
            case BooleanType::class:
103
                $this->setScalarValue($property, $value, 'Boolean',
104
                    function($value)
105
                    {
106
                        return (boolean)$value;
107
                    });
108
                break;
109 1
            case CollectionType::class:
110
                $this->setCollectionValue($property, $value, $type);
111
                break;
112 1
            case ObjectType::class:
113 1
                $this->setObjectValue($property, $value, $type);
114 1
                break;
115
        }
116 2
    }
117
118 1
    private function setScalarValue($property, $value, $name, $cast)
119
    {
120 1
        $method = '__to' . $name;
121
122 1
        if (is_scalar($value))
123
        {
124 1
            $this->setRawValue($property, $cast($value));
125
        }
126
        elseif (is_object($value) && method_exists([$value, $method]))
127
        {
128
            $this->setScalarValue
129
            (
130
                $property,
131
                $value->$method(),
132
                $method,
133
                $cast
134
            );
135
        }
136
        else
137
        {
138
            $this->throwError($property, $name, $value);
139
        }
140 1
    }
141
142 1
    private function setObjectValue($property, $value, $type)
143
    {
144 1
        if (is_a($value, $type->classname))
145
        {
146 1
            $this->setRawValue($property, $value);
147
        }
148
        else
149
        {
150
            $this->throwError($property, $type->classname, $value);
151
        }
152 1
    }
153
154
    private function setCollectionValue($property, $value, $type)
0 ignored issues
show
Unused Code introduced by
The parameter $type 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...
155
    {
156
        if (is_a($value, \ArrayAccess::class) || is_array($value))
157
        {
158
            $this->setRawValue($property, $value);
159
        }
160
        else
161
        {
162
            $this->throwError($property, 'Collection', $value);
163
        }
164
    }
165
166 1
    private function throwError($property, $expected, $value)
167
    {
168 1
        throw new IllegalPropertyTypeException
169
        (
170 1
            get_class($this->object),
171
            $property,
172
            $expected,
173 1
            is_object($value) ? get_class($value) : gettype($value)
174
        );
175
    }
176
}
177