Manager::__construct()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace AmaTeam\TreeAccess\Metadata;
4
5
use AmaTeam\TreeAccess\API\Metadata\ManagerInterface;
6
use AmaTeam\TreeAccess\API\Metadata\StorageInterface;
7
use AmaTeam\TreeAccess\Misc\Strings;
8
use ReflectionClass;
9
use ReflectionMethod;
10
use ReflectionProperty;
11
12
class Manager implements ManagerInterface
13
{
14
    const GETTER_PREFIXES = ['get', 'is', 'has'];
15
    const SETTER_PREFIXES = ['set'];
16
17
    /**
18
     * @var StorageInterface
19
     */
20
    private $storage;
21
22
    /**
23
     * @param StorageInterface $storage
24
     */
25 35
    public function __construct(StorageInterface $storage = null)
26
    {
27 35
        $this->storage = $storage ?: new RuntimeStorage();
28 35
    }
29
30
    /**
31
     * @inheritDoc
32
     */
33 20
    public function get($className)
34
    {
35 20
        $properties = $this->storage->get($className);
36 20
        if ($properties === null) {
37 20
            $properties = $this->analyze($className);
38 20
            $this->storage->set($className, $properties);
39
        }
40 20
        return $properties;
41
    }
42
43
    /**
44
     * @param string $className
45
     * @return PropertyMetadata[]
46
     */
47 20
    private function analyze($className)
48
    {
49 20
        $reflection = new ReflectionClass($className);
50 20
        return array_merge(
51 20
            $this->extractVirtualProperties($reflection),
52 20
            $this->extractProperties($reflection)
53
        );
54
    }
55
56
    /**
57
     * @param ReflectionClass $reflection
58
     * @return PropertyMetadata[]
59
     */
60 20
    private function extractProperties(ReflectionClass $reflection)
61
    {
62 20
        $properties = [];
63 20
        $filter = ReflectionProperty::IS_PUBLIC;
64 20
        foreach ($reflection->getProperties($filter) as $property) {
65 4
            $metadata = new PropertyMetadata($property->getName());
66 4
            $properties[$property->getName()] = $metadata;
67
        }
68 20
        return $properties;
69
    }
70
71
    /**
72
     * @param ReflectionClass $reflection
73
     * @return PropertyMetadata[]
74
     */
75 20
    private function extractVirtualProperties(ReflectionClass $reflection)
76
    {
77 20
        $properties = [];
78 20
        $filter = ReflectionMethod::IS_PUBLIC;
79 20
        $defaults = ['getter' => null, 'setter' => null];
80
        $candidates = [
81 20
            'setter' => self::SETTER_PREFIXES,
82 20
            'getter' => self::GETTER_PREFIXES
83
        ];
84 20
        foreach ($reflection->getMethods($filter) as $method) {
85 9
            $name = $method->getName();
86 9
            foreach ($candidates as $key => $prefixes) {
87 9
                foreach ($prefixes as $prefix) {
88 9
                    $property = Strings::stripCamelCasePrefix($name, $prefix);
89 9
                    if (!$property) {
90 9
                        continue;
91
                    }
92 9
                    $metadata = isset($properties[$property]) ? $properties[$property] : $defaults;
93 9
                    $metadata[$key] = $metadata[$key] ?: $name;
94 9
                    $properties[$property] = $metadata;
95
                }
96
            }
97
        }
98 20
        $target = [];
99 20
        foreach ($properties as $property => $metadata) {
100 9
            $target[$property] = new PropertyMetadata(
101 9
                $property,
102 9
                true,
103 9
                $metadata['setter'],
104 9
                $metadata['getter']
105
            );
106
        }
107 20
        return $target;
108
    }
109
}
110