Skip to content

Commit 3fd3392

Browse files
committed
Use a dedicated Storage class.
1 parent 953412a commit 3fd3392

12 files changed

+294
-64
lines changed

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"leanphp/phpspec-code-coverage": "^4",
2727
"phpbench/phpbench": "^0.16",
2828
"phpspec/phpspec": "^4",
29+
"phptaskman/changelog": "^1.0",
2930
"scrutinizer/ocular": "^1"
3031
},
3132
"config": {

spec/drupol/phptree/Modifier/ReverseSpec.php

+1-5
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,7 @@ public function it_can_reverse_a_tree()
2828
->count()
2929
->shouldReturn(5);
3030

31-
// @todo write better test here and test all children and recursively.
32-
$this
33-
->modify($tree1)
34-
->children()->current()->getValue()
35-
->shouldReturn('E');
31+
$this->modify($tree1)->shouldNotBeEqualTo($tree2);
3632
}
3733

3834
public function it_is_initializable()

spec/drupol/phptree/Node/NodeObjectBehavior.php

+8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*
1414
* @method shouldHaveSameGraph(NodeInterface $node)
1515
* @method shouldHaveSameTextExport(string $export)
16+
* @method shouldNotHaveSameTextExport(string $export)
1617
*/
1718
abstract class NodeObjectBehavior extends ObjectBehavior
1819
{
@@ -37,6 +38,13 @@ public function getMatchers(): array
3738

3839
return $left === $key;
3940
},
41+
'notHaveSameTextExport' => function ($subject, $key) {
42+
$exporterText = new Text();
43+
44+
$left = $exporterText->export($subject);
45+
46+
return $left !== $key;
47+
},
4048
];
4149
}
4250
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace spec\drupol\phptree\Storage;
6+
7+
use drupol\phptree\Storage\NodeStorage;
8+
use PhpSpec\ObjectBehavior;
9+
10+
class NodeStorageSpec extends ObjectBehavior
11+
{
12+
public function it_can_offsetUnset()
13+
{
14+
$this->set('foo', 'bar');
15+
16+
$this->get('foo')->shouldBe('bar');
17+
18+
$this->offsetUnset('foo');
19+
20+
$this->shouldThrow(\InvalidArgumentException::class)
21+
->during('get', ['foo']);
22+
}
23+
public function it_is_initializable()
24+
{
25+
$this->shouldHaveType(NodeStorage::class);
26+
}
27+
}

src/Node/KeyValueNode.php

+2-9
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@
99
*/
1010
class KeyValueNode extends ValueNode implements KeyValueNodeInterface
1111
{
12-
/**
13-
* The key property.
14-
*
15-
* @var null|int|mixed|string
16-
*/
17-
private $key;
18-
1912
/**
2013
* KeyValueNode constructor.
2114
*
@@ -28,14 +21,14 @@ public function __construct($key = null, $value = null, int $capacity = 0, NodeI
2821
{
2922
parent::__construct($value, $capacity, $parent);
3023

31-
$this->key = $key;
24+
$this->storage()->set('key', $key);
3225
}
3326

3427
/**
3528
* {@inheritdoc}
3629
*/
3730
public function getKey()
3831
{
39-
return $this->key;
32+
return $this->storage()->get('key');
4033
}
4134
}

src/Node/NaryNode.php

+10-19
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,6 @@
1212
*/
1313
class NaryNode extends Node implements NaryNodeInterface
1414
{
15-
/**
16-
* The capacity of a node, the maximum children a node can have.
17-
*
18-
* @var int
19-
*/
20-
private $capacity;
21-
22-
/**
23-
* The traverser.
24-
*
25-
* @var TraverserInterface
26-
*/
27-
private $traverser;
28-
2915
/**
3016
* NaryNode constructor.
3117
*
@@ -40,11 +26,16 @@ public function __construct(int $capacity = 0, NodeInterface $parent = null, Tra
4026
{
4127
parent::__construct($parent);
4228

43-
$this->capacity = 0 > $capacity ?
29+
$capacity = 0 > $capacity ?
4430
0 :
4531
$capacity;
4632

47-
$this->traverser = $traverser ?? new BreadthFirst();
33+
$this->storage()->set(
34+
'capacity',
35+
$capacity
36+
);
37+
38+
$this->storage()->set('traverser', $traverser ?? new BreadthFirst());
4839
}
4940

5041
/**
@@ -61,7 +52,7 @@ public function add(NodeInterface ...$nodes): NodeInterface
6152
continue;
6253
}
6354

64-
foreach ($this->traverser->traverse($this) as $candidate) {
55+
foreach ($this->getTraverser()->traverse($this) as $candidate) {
6556
if (!($candidate instanceof NaryNodeInterface)) {
6657
continue;
6758
}
@@ -84,15 +75,15 @@ public function add(NodeInterface ...$nodes): NodeInterface
8475
*/
8576
public function capacity(): int
8677
{
87-
return $this->capacity;
78+
return $this->storage()->get('capacity');
8879
}
8980

9081
/**
9182
* {@inheritdoc}
9283
*/
9384
public function getTraverser(): TraverserInterface
9485
{
95-
return $this->traverser;
86+
return $this->storage()->get('traverser');
9687
}
9788

9889
/**

src/Node/Node.php

+35-22
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace drupol\phptree\Node;
66

7+
use drupol\phptree\Storage\NodeStorage;
8+
use drupol\phptree\Storage\StorageInterface;
9+
710
/**
811
* Class Node.
912
*/
@@ -12,9 +15,9 @@ class Node implements NodeInterface
1215
/**
1316
* The storage property.
1417
*
15-
* @var array
18+
* @var \drupol\phptree\Storage\NodeStorageInterface
1619
*/
17-
protected $storage;
20+
private $storage;
1821

1922
/**
2023
* Node constructor.
@@ -23,10 +26,8 @@ class Node implements NodeInterface
2326
*/
2427
public function __construct(NodeInterface $parent = null)
2528
{
26-
$this->storage = [
27-
'parent' => $parent,
28-
'children' => new \ArrayObject(),
29-
];
29+
$this->storage = new NodeStorage();
30+
$this->storage()->setParent($parent);
3031
}
3132

3233
/**
@@ -35,7 +36,7 @@ public function __construct(NodeInterface $parent = null)
3536
public function add(NodeInterface ...$nodes): NodeInterface
3637
{
3738
foreach ($nodes as $node) {
38-
$this->storage['children']->append(
39+
$this->storage()->getChildren()->append(
3940
$node->setParent($this)
4041
);
4142
}
@@ -45,10 +46,12 @@ public function add(NodeInterface ...$nodes): NodeInterface
4546

4647
/**
4748
* {@inheritdoc}
49+
*
50+
* @return \drupol\phptree\Node\NodeInterface|\Traversable
4851
*/
4952
public function children(): \Traversable
5053
{
51-
yield from $this->storage['children'];
54+
yield from $this->storage()->getChildren();
5255
}
5356

5457
/**
@@ -71,7 +74,7 @@ public function count(): int
7174
*/
7275
public function degree(): int
7376
{
74-
return $this->storage['children']->count();
77+
return $this->storage()->getChildren()->count();
7578
}
7679

7780
/**
@@ -107,18 +110,18 @@ public function getIterator()
107110
*/
108111
public function getParent(): ?NodeInterface
109112
{
110-
return $this->storage['parent'];
113+
return $this->storage()->getParent();
111114
}
112115

113116
/**
114117
* {@inheritdoc}
115118
*/
116119
public function getSibblings(): \Traversable
117120
{
118-
$parent = $this->storage['parent'];
121+
$parent = $this->storage()->getParent();
119122

120123
if (null === $parent) {
121-
return new \ArrayIterator([]);
124+
return $this->storage()->getChildren()->exchangeArray([]);
122125
}
123126

124127
foreach ($parent->children() as $child) {
@@ -149,31 +152,31 @@ public function height(): int
149152
*/
150153
public function isLeaf(): bool
151154
{
152-
return 0 === $this->storage['children']->count();
155+
return 0 === $this->degree();
153156
}
154157

155158
/**
156159
* {@inheritdoc}
157160
*/
158161
public function isRoot(): bool
159162
{
160-
return null === $this->storage['parent'];
163+
return null === $this->storage()->getParent();
161164
}
162165

163166
/**
164167
* {@inheritdoc}
165168
*/
166169
public function offsetExists($offset)
167170
{
168-
return $this->storage['children']->offsetExists($offset);
171+
return $this->storage()->getChildren()->offsetExists($offset);
169172
}
170173

171174
/**
172175
* {@inheritdoc}
173176
*/
174177
public function offsetGet($offset)
175178
{
176-
return $this->storage['children']->offsetGet($offset);
179+
return $this->storage()->getChildren()->offsetGet($offset);
177180
}
178181

179182
/**
@@ -185,7 +188,7 @@ public function offsetSet($offset, $value)
185188
throw new \InvalidArgumentException('The value must implements NodeInterface.');
186189
}
187190

188-
$this->storage['children']
191+
$this->storage()->getChildren()
189192
->offsetSet($offset, $value->setParent($this));
190193
}
191194

@@ -194,17 +197,17 @@ public function offsetSet($offset, $value)
194197
*/
195198
public function offsetUnset($offset)
196199
{
197-
$this->storage['children']->offsetUnset($offset);
200+
$this->storage()->getChildren()->offsetUnset($offset);
198201
}
199202

200203
/**
201204
* {@inheritdoc}
202205
*/
203206
public function remove(NodeInterface ...$nodes): NodeInterface
204207
{
205-
$this->storage['children']->exchangeArray(
208+
$this->storage()->getChildren()->exchangeArray(
206209
\array_filter(
207-
$this->storage['children']->getArrayCopy(),
210+
$this->storage()->getChildren()->getArrayCopy(),
208211
static function ($child) use ($nodes) {
209212
return !\in_array($child, $nodes, true);
210213
}
@@ -219,7 +222,7 @@ static function ($child) use ($nodes) {
219222
*/
220223
public function setParent(NodeInterface $node = null): NodeInterface
221224
{
222-
$this->storage['parent'] = $node;
225+
$this->storage()->setParent($node);
223226

224227
return $this;
225228
}
@@ -230,10 +233,20 @@ public function setParent(NodeInterface $node = null): NodeInterface
230233
public function withChildren(NodeInterface ...$nodes): NodeInterface
231234
{
232235
$clone = clone $this;
233-
$clone->storage['children'] = new \ArrayObject();
236+
$clone->storage()->getChildren()->exchangeArray([]);
234237

235238
return [] === $nodes ?
236239
$clone :
237240
$clone->add(...$nodes);
238241
}
242+
243+
/**
244+
* {@inheritdoc}
245+
*
246+
* @return \drupol\phptree\Storage\NodeStorageInterface
247+
*/
248+
protected function storage(): StorageInterface
249+
{
250+
return $this->storage;
251+
}
239252
}

src/Node/ValueNode.php

+2-9
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@
99
*/
1010
class ValueNode extends NaryNode implements ValueNodeInterface
1111
{
12-
/**
13-
* The value property.
14-
*
15-
* @var null|mixed|string
16-
*/
17-
private $value;
18-
1912
/**
2013
* ValueNode constructor.
2114
*
@@ -27,14 +20,14 @@ public function __construct($value, int $capacity = 0, NodeInterface $parent = n
2720
{
2821
parent::__construct($capacity, $parent);
2922

30-
$this->value = $value;
23+
$this->storage()->set('value', $value);
3124
}
3225

3326
/**
3427
* {@inheritdoc}
3528
*/
3629
public function getValue()
3730
{
38-
return $this->value;
31+
return $this->storage()->get('value');
3932
}
4033
}

0 commit comments

Comments
 (0)