Passed
Push — master ( f7fc6f...76d32b )
by Fike
05:07 queued 02:23
created

Accessor::isEnumerable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace AmaTeam\TreeAccess;
4
5
use AmaTeam\TreeAccess\API\AccessorInterface;
6
use AmaTeam\TreeAccess\API\ActiveNodeFactoryInterface;
7
use AmaTeam\TreeAccess\API\Exception\IllegalTargetException;
8
use AmaTeam\TreeAccess\API\NodeInterface;
9
use AmaTeam\TreeAccess\API\TypeAccessorInterface;
10
use AmaTeam\TreeAccess\Locator\Context;
11
use AmaTeam\TreeAccess\Type\Registry;
12
13
class Accessor implements AccessorInterface, ActiveNodeFactoryInterface
14
{
15
    /**
16
     * @var Locator
17
     */
18
    private $locator;
19
    /**
20
     * @var Registry
21
     */
22
    private $registry;
23
24
    /**
25
     * @param Registry $registry
26
     */
27 21
    public function __construct(Registry $registry)
28
    {
29 21
        $this->registry = $registry;
30 21
        $this->locator = new Locator($registry);
31 21
    }
32
33
    /**
34
     * @inheritDoc
35
     */
36 14
    public function getNode(&$root, $path)
37
    {
38 14
        return $this->traverse($root, $path, new Context(false, false));
39
    }
40
41
    /**
42
     * @inheritDoc
43
     */
44 5
    public function findNode(&$root, $path)
45
    {
46 5
        return $this->traverse($root, $path, new Context(true, true));
47
    }
48
49
    /**
50
     * @inheritDoc
51
     */
52 5
    public function exists($root, $path)
53
    {
54 5
        $normalizedPath = Paths::normalize($path);
55 5
        return $this->findNode($root, $normalizedPath) !== null;
56
    }
57
58
    /**
59
     * @inheritDoc
60
     */
61
    public function isReadable($root, $path)
62
    {
63
        return $this->getNode($root, $path)->isReadable();
64
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69
    public function isWritable($root, $path)
70
    {
71
        return $this->getNode($root, $path)->isWritable();
72
    }
73
74
    /**
75
     * @inheritDoc
76
     */
77
    public function isEnumerable($root, $path)
78
    {
79
        return $this->getNode($root, $path)->isEnumerable();
80
    }
81
82
    /**
83
     * @param mixed $root
84
     * @param string|string[] $path
85
     * @param Context $context
86
     * @return NodeInterface|null
87
     */
88 19
    private function traverse(&$root, $path, Context $context)
89
    {
90 19
        $node = new Node([], $root);
91 19
        return $this->locator->locate($node, Paths::normalize($path), $context);
92
    }
93
94
    /**
95
     * @inheritDoc
96
     */
97 7
    public function read(&$root, $path)
98
    {
99 7
        $path = Paths::normalize($path);
100 7
        $node = $this->getNode($root, $path);
101 5
        return $node->getValue();
102
    }
103
104
    /**
105
     * @inheritDoc
106
     */
107 3
    public function enumerate(&$root, $path)
108
    {
109 3
        $normalizedPath = Paths::normalize($path);
110 3
        $parent = $this->getNode($root, $normalizedPath);
111 3
        $accessor = $this->getAccessor($parent->getValue(), $normalizedPath);
112 2
        $target = [];
113 2
        foreach ($accessor->enumerate($parent->getValue()) as $name => $node) {
114 2
            $nodePath = array_merge($normalizedPath, $node->getPath());
115 2
            $target[$name] = Node::withPath($node, $nodePath);
116
        }
117 2
        return $target;
118
    }
119
120
    /**
121
     * @inheritDoc
122
     */
123 7
    public function write(&$root, $path, $value)
124
    {
125 7
        $normalizedPath = Paths::normalize($path);
126 7
        if (empty($normalizedPath)) {
127 2
            $root = $value;
128 2
            return new Node([], $root);
129
        }
130 5
        $key = $normalizedPath[sizeof($normalizedPath) - 1];
131 5
        $parentPath = array_slice($normalizedPath, 0, -1);
132 5
        $parent = $this->getNode($root, $parentPath);
133 5
        $accessor = $this->getAccessor($parent->getValue(), $parentPath);
134 4
        $parentValue = &$parent->getValue();
135 4
        $node = $accessor->write($parentValue, $key, $value);
136 4
        return Node::withPath($node, $normalizedPath);
137
    }
138
139
    /**
140
     * @param $value
141
     * @param array $path
142
     *
143
     * @return TypeAccessorInterface
144
     *
145
     * @throws IllegalTargetException
146
     */
147 7
    private function getAccessor($value, array $path)
148
    {
149 7
        $accessor = $this->registry->getAccessor(gettype($value));
150 7
        if (!$accessor) {
151 2
            throw new IllegalTargetException($path);
152
        }
153 5
        return $accessor;
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159 4
    public function wrap(&$structure)
160
    {
161 4
        return new ActiveNode($this, [], $structure);
162
    }
163
}
164