Skip to content

Commit 9b87679

Browse files
committed
Implement the Text importer.
1 parent da0d636 commit 9b87679

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace spec\drupol\phptree\Importer;
6+
7+
use drupol\phptree\Importer\Text;
8+
use drupol\phptree\Node\ValueNode;
9+
use drupol\phptree\Node\ValueNodeInterface;
10+
use PhpSpec\ObjectBehavior;
11+
12+
class TextSpec extends ObjectBehavior
13+
{
14+
public function it_is_initializable()
15+
{
16+
$this->shouldHaveType(Text::class);
17+
}
18+
19+
public function it_can_import()
20+
{
21+
$string = '[root [A [C [G] [H]] [D [I] [J]]] [B [E] [F]]]';
22+
23+
$tree = new ValueNode('root', 2);
24+
25+
$nodes = [];
26+
foreach (\range('A', 'J') as $value) {
27+
$nodes[$value] = new ValueNode($value);
28+
}
29+
30+
$tree->add(...\array_values($nodes));
31+
32+
$this
33+
->import($string)
34+
->shouldImplement(ValueNodeInterface::class);
35+
36+
$this
37+
->import($string)
38+
->count()
39+
->shouldReturn(10);
40+
41+
$this
42+
->import($string)
43+
->isRoot()
44+
->shouldReturn(TRUE);
45+
}
46+
}

src/Importer/ImporterInterface.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace drupol\phptree\Importer;
6+
7+
use drupol\phptree\Node\NodeInterface;
8+
9+
/**
10+
* Interface ImporterInterface
11+
*/
12+
interface ImporterInterface
13+
{
14+
/**
15+
* Import data into a node.
16+
*
17+
* @param mixed $data
18+
* The data to import.
19+
*
20+
* @return NodeInterface
21+
* The new node.
22+
*/
23+
public function import($data): NodeInterface;
24+
}

src/Importer/Text.php

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace drupol\phptree\Importer;
6+
7+
use drupol\phptree\Node\NodeInterface;
8+
use drupol\phptree\Node\ValueNode;
9+
use drupol\phptree\Node\ValueNodeInterface;
10+
11+
/**
12+
* Class Text
13+
*/
14+
class Text implements ImporterInterface
15+
{
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
public function import($data): NodeInterface
20+
{
21+
$parsed = $this->parse($data);
22+
23+
return $this->arrayToTree($parsed[0]);
24+
}
25+
26+
/**
27+
* Convert an array into a tree.
28+
*
29+
* @param array $data
30+
*
31+
* @return \drupol\phptree\Node\ValueNodeInterface
32+
* The tree.
33+
*/
34+
private function arrayToTree(array $data): ValueNodeInterface
35+
{
36+
$data += [
37+
'children' => [],
38+
];
39+
40+
$node = new ValueNode($data['value']);
41+
42+
foreach ($data['children'] as $key => $child) {
43+
$node->add($this->arrayToTree($child));
44+
}
45+
46+
return $node;
47+
}
48+
49+
/**
50+
* Parse a string into an array.
51+
*
52+
* @param string $subject
53+
* The subject string.
54+
*
55+
* @return array|bool
56+
* The array.
57+
*/
58+
private function parse(string $subject)
59+
{
60+
$result = false;
61+
62+
\preg_match_all('~[^\[\]]+|\[(?<nested>(?R)*)\]~', $subject, $matches);
63+
64+
foreach (\array_filter($matches['nested']) as $match) {
65+
$item = [];
66+
$position = \strpos($match, '[');
67+
68+
if (false !== $position) {
69+
$item['value'] = \substr($match, 0, $position);
70+
} else {
71+
$item['value'] = $match;
72+
}
73+
74+
if (false !== $children = $this->parse($match)) {
75+
$item['children'] = $children;
76+
}
77+
78+
$result[] = $item;
79+
}
80+
81+
return $result;
82+
}
83+
}

0 commit comments

Comments
 (0)