Completed
Push — master ( ac3e84...79ab0f )
by
unknown
02:02
created

MagicMethodsTrait::handlePropertyMagicMethod()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 19
rs 9.2
cc 4
eloc 13
nc 4
nop 3
1
<?php
2
/*
3
 * 2016 Romain CANON <[email protected]>
4
 *
5
 * This file is part of the TYPO3 Configuration Object project.
6
 * It is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License, either
8
 * version 3 of the License, or any later version.
9
 *
10
 * For the full copyright and license information, see:
11
 * http://www.gnu.org/licenses/gpl-3.0.html
12
 */
13
14
namespace Romm\ConfigurationObject\Traits\ConfigurationObject;
15
16
use Romm\ConfigurationObject\Exceptions\MethodNotFoundException;
17
use Romm\ConfigurationObject\Exceptions\PropertyNotAccessibleException;
18
19
/**
20
 * This trait will implement magic setters and getters for accessible properties
21
 * of the class.
22
 *
23
 * /!\ This class uses the method `__call()`, if you need to override this
24
 * function in your own class, you must call the function `handleMagicMethods()`
25
 * and handle the result correctly. This is the only way to keep this trait
26
 * features running correctly.
27
 */
28
trait MagicMethodsTrait
29
{
30
31
    /**
32
     * Contains the list of the accessible properties for the instances of this
33
     * class.
34
     *
35
     * @var array
36
     */
37
    private static $_accessibleProperties = [];
38
39
    /**
40
     * See class description.
41
     *
42
     * @param string $name      Name of the called function.
43
     * @param array  $arguments Arguments passed to the function
44
     * @return mixed
45
     */
46
    public function __call($name, $arguments)
47
    {
48
        return $this->handleMagicMethods($name, $arguments);
49
    }
50
51
    /**
52
     * See class description.
53
     *
54
     * @param string $name      Name of the called function.
55
     * @param array  $arguments Arguments passed to the function.
56
     * @return mixed
57
     * @throws MethodNotFoundException
58
     */
59
    public function handleMagicMethods($name, array $arguments)
60
    {
61
        $flag = false;
62
        $result = null;
63
64
        if (in_array($type = substr($name, 0, 3), ['set', 'get'])) {
65
            /*
66
             * We will first try to access the property written with
67
             * lowerCamelCase, which is the convention for many people. If this
68
             * property is not found, we try the real name of the property given
69
             * in the magic method.
70
             */
71
            $propertyLowerCase = lcfirst(substr($name, 3));
72
            $property = substr($name, 3);
73
74
            foreach ([$propertyLowerCase, $property] as $prop) {
75
                try {
76
                    $result = $this->handlePropertyMagicMethod($prop, $type, $arguments);
77
                    $flag = true;
78
                    break;
79
                } catch (PropertyNotAccessibleException $e) {
80
                    continue;
81
                }
82
            }
83
        }
84
85
        if (false === $flag) {
86
            throw new MethodNotFoundException(
87
                'The method "' . $name . '" does not exist in the class "' . get_class($this) . '".',
88
                1471043854
89
            );
90
        }
91
92
        return $result;
93
    }
94
95
    /**
96
     * Will try to set/get the wanted property.
97
     *
98
     * @param string $property Name of the property to be set/get.
99
     * @param string $type     Must be `set` or `get`.
100
     * @param array  $arguments
101
     * @return mixed
102
     * @throws PropertyNotAccessibleException
103
     */
104
    protected function handlePropertyMagicMethod($property, $type, array $arguments)
105
    {
106
        if ($this->isPropertyAccessible($property)) {
107
            switch ($type) {
108
                case 'set':
109
                    $this->{$property} = current($arguments);
110
                    return null;
111
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
112
                case 'get':
113
                    return $this->{$property};
114
                    break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
115
            }
116
        }
117
118
        throw new PropertyNotAccessibleException(
119
            'The property "' . $property . '" is not accessible in the class "' . get_class($this) . '".',
120
            1473260999
121
        );
122
    }
123
124
    /**
125
     * Returns true if the given property name is accessible for the current
126
     * instance of this class.
127
     *
128
     * Note that the list of accessible properties for this class is stored in
129
     * cache to improve performances.
130
     *
131
     * @param string $propertyName
132
     * @return bool
133
     */
134
    private function isPropertyAccessible($propertyName)
135
    {
136
        if (false === isset(self::$_accessibleProperties[get_class($this)])) {
137
            self::$_accessibleProperties[get_class($this)] = [];
138
139
            $reflect = new \ReflectionObject($this);
140
            $properties = $reflect->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED);
141
142
            foreach ($properties as $property) {
143
                self::$_accessibleProperties[get_class($this)][$property->getName()] = true;
144
            }
145
        }
146
147
        return (isset(self::$_accessibleProperties[get_class($this)][$propertyName]));
148
    }
149
}
150