Completed
Push — master ( fb21bc...46b7df )
by Emily
02:00
created

PropertyAccessor::getValue()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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
    private $reflect;
22
23 4
    public function __construct($object, ReflectionComposite $reflect)
24
    {
25 4
        parent::__construct($object);
26
27 4
        $this->reflect = $reflect;
28 4
    }
29
30 3
    public function getValue($property)
31
    {
32 3
        return $this->getRawValue($property);
33
    }
34
35 3
    public function setValue($property, $value)
36
    {
37 3
        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 3
        $type = $this->reflect->properties[$property]->type;
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...
46
47 3
        if (is_null($value))
48
        {
49 2
            $this->setNullValue($property, $type);
50
        }
51
        else
52
        {
53 1
            $this->setNonNullValue($property, $value, $type);
54
        }
55 2
    }
56
57 2
    private function setNullValue($property, $type)
58
    {
59 2
        if ($type->nullable)
60
        {
61 1
            $this->setRawValue($property, null);
62
        }
63
        else
64
        {
65 1
            $this->throwError($property, 'NonNull', null);
66
        }
67 1
    }
68
69 1
    private function setNonNullValue($property, $value, $type)
70
    {
71 1
        switch (get_class($type))
72
        {
73 1
            case MixedType::class:
74
                $this->setRawValue($property, $value);
75
                break;
76 1
            case IntegerType::class:
77
                $this->setScalarValue($property, $value, 'Integer',
78
                    function($value)
79
                    {
80
                        return (integer)$value;
81
                    });
82
                break;
83 1
            case StringType::class:
84
                $this->setScalarValue($property, $value, 'String',
85
                    function($value)
86
                    {
87
                        return (string)$value;
88
                    });
89
                break;
90 1
            case BooleanType::class:
91
                $this->setScalarValue($property, $value, 'Boolean',
92
                    function($value)
93
                    {
94
                        return (boolean)$value;
95
                    });
96
                break;
97 1
            case CollectionType::class:
98
                $this->setCollectionValue($property, $value, $type);
99
                break;
100 1
            case ObjectType::class:
101 1
                $this->setObjectValue($property, $value, $type);
102 1
                break;
103
        }
104 1
    }
105
106
    private function setScalarValue($property, $value, $name, $cast)
107
    {
108
        $method = '__to' . $name;
109
110
        if (is_scalar($value))
111
        {
112
            $this->setRawValue($property, $cast($value));
113
        }
114
        elseif (is_object($value) && method_exists([$value, $method]))
115
        {
116
            $this->setScalarValue
117
            (
118
                $property,
119
                $value->$method(),
120
                $method,
121
                $cast
122
            );
123
        }
124
        else
125
        {
126
            $this->throwError($property, $name, $value);
127
        }
128
    }
129
130 1
    private function setObjectValue($property, $value, $type)
131
    {
132 1
        if (is_a($value, $type->classname))
133
        {
134 1
            $this->setRawValue($property, $value);
135
        }
136
        else
137
        {
138
            $this->throwError($property, $type->classname, $value);
139
        }
140 1
    }
141
142
    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...
143
    {
144
        if (is_a($value, \ArrayAccess::class) || is_array($value))
145
        {
146
            $this->setRawValue($property, $value);
147
        }
148
        else
149
        {
150
            $this->throwError($property, 'Collection', $value);
151
        }
152
    }
153
154 1
    private function throwError($property, $expected, $value)
155
    {
156 1
        throw new IllegalPropertyTypeException
157
        (
158 1
            get_class($this->object),
159
            $property,
160
            $expected,
161 1
            is_object($value) ? get_class($value) : gettype($value)
162
        );
163
    }
164
}
165