Completed
Pull Request — master (#14)
by Pavel
04:42
created

getAccessibleProperty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 0
cts 5
cp 0
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 1
crap 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Bankiru\Api\Doctrine\Utility;
21
22
use Doctrine\Common\Persistence\Mapping\ReflectionService;
23
24
/**
25
 * Utility class to retrieve all reflection instance properties of a given class, including
26
 * private inherited properties and transient properties.
27
 *
28
 * @private This API is for internal use only
29
 *
30
 * @author  Marco Pivetta <[email protected]>
31
 */
32
final class ReflectionPropertiesGetter
33
{
34
    /**
35
     * @var \ReflectionProperty[][] indexed by class name and property internal name
36
     */
37
    private $properties = [];
38
39
    /**
40
     * @var ReflectionService
41
     */
42
    private $reflectionService;
43
44
    /**
45
     * @param ReflectionService $reflectionService
46
     */
47 20
    public function __construct(ReflectionService $reflectionService)
48
    {
49 20
        $this->reflectionService = $reflectionService;
50 20
    }
51
52
    /**
53
     * @param $className
54
     *
55
     * @return \ReflectionProperty[] indexed by property internal name
56
     */
57
    public function getProperties($className)
58
    {
59
        if (isset($this->properties[$className])) {
60
            return $this->properties[$className];
61
        }
62
63
        return $this->properties[$className] = call_user_func_array(
64
            'array_merge',
65
            // first merge because `array_merge` expects >= 1 params
66
            array_merge(
67
                [[]],
68
                array_map(
69
                    [$this, 'getClassProperties'],
70
                    $this->getHierarchyClasses($className)
71
                )
72
            )
73
        );
74
    }
75
76
    /**
77
     * @param string $className
78
     *
79
     * @return \ReflectionClass[]
80
     */
81
    private function getHierarchyClasses($className)
82
    {
83
        $classes         = [];
84
        $parentClassName = $className;
85
86
        while ($parentClassName && $currentClass = $this->reflectionService->getClass($parentClassName)) {
87
            $classes[]       = $currentClass;
88
            $parentClassName = null;
89
90
            if ($parentClass = $currentClass->getParentClass()) {
91
                $parentClassName = $parentClass->getName();
92
            }
93
        }
94
95
        return $classes;
96
    }
97
98
    /**
99
     * @param \ReflectionClass $reflectionClass
100
     *
101
     * @return \ReflectionProperty[]
102
     */
103
    private function getClassProperties(\ReflectionClass $reflectionClass)
104
    {
105
        $properties = $reflectionClass->getProperties();
106
107
        return array_filter(
108
            array_filter(
109
                array_map(
110
                    [$this, 'getAccessibleProperty'],
111
                    array_combine(
112
                        array_map([$this, 'getLogicalName'], $properties),
113
                        $properties
114
                    )
115
                )
116
            ),
117
            [$this, 'isInstanceProperty']
118
        );
119
    }
120
121
    /**
122
     * @param \ReflectionProperty $reflectionProperty
123
     *
124
     * @return bool
125
     */
126
    private function isInstanceProperty(\ReflectionProperty $reflectionProperty)
127
    {
128
        return !$reflectionProperty->isStatic();
129
    }
130
131
    /**
132
     * @param \ReflectionProperty $property
133
     *
134
     * @return null|\ReflectionProperty
135
     */
136
    private function getAccessibleProperty(\ReflectionProperty $property)
137
    {
138
        return $this->reflectionService->getAccessibleProperty(
139
            $property->getDeclaringClass()->getName(),
0 ignored issues
show
introduced by
Consider using $property->class. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
140
            $property->getName()
141
        );
142
    }
143
144
    /**
145
     * @param \ReflectionProperty $property
146
     *
147
     * @return string
148
     */
149
    private function getLogicalName(\ReflectionProperty $property)
150
    {
151
        $propertyName = $property->getName();
152
153
        if ($property->isPublic()) {
154
            return $propertyName;
155
        }
156
157
        if ($property->isProtected()) {
158
            return "\0*\0".$propertyName;
159
        }
160
161
        return "\0".$property->getDeclaringClass()->getName()."\0".$propertyName;
0 ignored issues
show
introduced by
Consider using $property->class. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
162
    }
163
}
164