Completed
Push — master ( d113dd...d83f64 )
by Kirill
03:54 queued 01:36
created

Properties::__set()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 33
rs 8.439
cc 5
eloc 20
nc 5
nop 2
1
<?php
2
/**
3
 * This file is part of Properties package.
4
 *
5
 * @author Serafim <[email protected]>
6
 * @date 14.04.2016 17:07
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Serafim\Properties;
12
13
use Serafim\Properties\Support\Registry;
14
use Serafim\Properties\Support\Strings as Str;
15
use Serafim\Properties\Exception\AccessDeniedException;
16
17
/**
18
 * Class Properties
19
 * @package Serafim\Properties
20
 */
21
trait Properties
22
{
23
    /**
24
     * @param string $name
25
     * @return mixed|null
26
     * @throws AccessDeniedException|\InvalidArgumentException|\LogicException
27
     */
28
    public function __get($name)
29
    {
30
        // Try to call `getProperty` method
31
        $getter = Str::getGetter($name);
32
        if (method_exists($this, $getter)) {
33
            return $this->{$getter}();
34
        }
35
36
        $parser = Registry::get($this);
37
        if ($parser->has($name)) {
38
            $property = $parser->get($name);
39
            $isBoolean = $property->typeOf('bool') || $property->typeOf('boolean');
40
            $getter = Str::getBooleanGetter($name);
41
42
            // If boolean - try to call `isProperty`
43
            if ($isBoolean && method_exists($this, $getter)) {
44
                return $this->{$getter}();
45
            }
46
47
            if ($parser->isReadable($name)) {
48
                // Return declared value
49
                return $this->getPropertyValue($name);
50
            }
51
52
            $exception = sprintf('Can not read write-only property %s::$%s', get_class($this), $name);
53
            throw new AccessDeniedException($exception);
54
        }
55
56
        return null;
57
    }
58
59
    /**
60
     * @param string $name
61
     * @param mixed $value
62
     * @return void
63
     * @throws AccessDeniedException|\InvalidArgumentException|\TypeError
64
     */
65
    public function __set($name, $value)
66
    {
67
        // Try to call `setProperty` method
68
        $setter = Str::getSetter($name);
69
        if (method_exists($this, $setter)) {
70
            $this->{$setter}($value);
71
            return;
72
        }
73
74
75
        $parser = Registry::get($this);
76
        if ($parser->has($name)) {
77
            if (!$parser->isWritable($name)) {
78
                $exception = sprintf('Can not set value to read-only property %s::$%s', get_class($this), $name);
79
                throw new AccessDeniedException($exception);
80
            }
81
82
            if (!$parser->typesAreEqual($name, $value)) {
83
                $exception = sprintf(
84
                    'Value for property %s::%s must be one of the type %s, %s given',
85
                    get_class($this),
86
                    $name,
87
                    implode(' or ', $parser->get($name)->getAvailableTypesArray()),
88
                    gettype($value)
89
                );
90
                throw new \TypeError($exception);
91
            }
92
93
            $this->setPropertyValue($name, $value);
94
        }
95
96
        $this->$name = $value;
97
    }
98
99
    /**
100
     * @param string $name
101
     * @return mixed
102
     */
103
    private function getPropertyValue($name)
104
    {
105
        $reflection = new \ReflectionProperty($this, $name);
106
        $reflection->setAccessible(true);
107
108
        return $reflection->getValue($this);
109
    }
110
111
    /**
112
     * @param string $name
113
     * @param $value
114
     * @return void
115
     */
116
    private function setPropertyValue($name, $value)
117
    {
118
        $reflection = new \ReflectionProperty($this, $name);
119
        $reflection->setAccessible(true);
120
121
        $reflection->setValue($this, $value);
122
    }
123
124
    /**
125
     * @param $name
126
     * @throws \InvalidArgumentException
127
     * @return bool
128
     */
129
    public function __unset($name)
130
    {
131
        $registry = Registry::get($this);
132
133
        $reflection = new \ReflectionClass($this);
134
135
        $isWritableProperty = $registry->has($name) && $registry->isWritable($name) && $reflection->hasProperty($name);
136
137
        if ($isWritableProperty) {
138
            $property = $reflection->getProperty($name);
139
140
            if ($property->isProtected() || $property->isPublic()) {
141
                unset($this->$name);
142
143
                return true;
144
            }
145
146
        }
147
148
        return false;
149
    }
150
151
    /**
152
     * @param $name
153
     * @return bool
154
     */
155
    public function __isset($name)
156
    {
157
        // Try to call `getProperty` method
158
        $getter = Str::getGetter($name);
159
        if (method_exists($this, $getter)) {
160
            return true;
161
        }
162
163
        return Registry::get($this)->has($name);
164
    }
165
}
166