Skip to content

Commit

Permalink
Implement the Text importer.
Browse files Browse the repository at this point in the history
  • Loading branch information
drupol committed Dec 16, 2018
1 parent da0d636 commit 9b87679
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
46 changes: 46 additions & 0 deletions spec/drupol/phptree/Importer/TextSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types = 1);

namespace spec\drupol\phptree\Importer;

use drupol\phptree\Importer\Text;
use drupol\phptree\Node\ValueNode;
use drupol\phptree\Node\ValueNodeInterface;
use PhpSpec\ObjectBehavior;

class TextSpec extends ObjectBehavior
{
public function it_is_initializable()
{
$this->shouldHaveType(Text::class);
}

public function it_can_import()
{
$string = '[root [A [C [G] [H]] [D [I] [J]]] [B [E] [F]]]';

$tree = new ValueNode('root', 2);

$nodes = [];
foreach (\range('A', 'J') as $value) {
$nodes[$value] = new ValueNode($value);
}

$tree->add(...\array_values($nodes));

$this
->import($string)
->shouldImplement(ValueNodeInterface::class);

$this
->import($string)
->count()
->shouldReturn(10);

$this
->import($string)
->isRoot()
->shouldReturn(TRUE);
}
}
24 changes: 24 additions & 0 deletions src/Importer/ImporterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types = 1);

namespace drupol\phptree\Importer;

use drupol\phptree\Node\NodeInterface;

/**
* Interface ImporterInterface
*/
interface ImporterInterface
{
/**
* Import data into a node.
*
* @param mixed $data
* The data to import.
*
* @return NodeInterface
* The new node.
*/
public function import($data): NodeInterface;
}
83 changes: 83 additions & 0 deletions src/Importer/Text.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types = 1);

namespace drupol\phptree\Importer;

use drupol\phptree\Node\NodeInterface;
use drupol\phptree\Node\ValueNode;
use drupol\phptree\Node\ValueNodeInterface;

/**
* Class Text
*/
class Text implements ImporterInterface
{
/**
* {@inheritdoc}
*/
public function import($data): NodeInterface
{
$parsed = $this->parse($data);

return $this->arrayToTree($parsed[0]);
}

/**
* Convert an array into a tree.
*
* @param array $data
*
* @return \drupol\phptree\Node\ValueNodeInterface
* The tree.
*/
private function arrayToTree(array $data): ValueNodeInterface
{
$data += [
'children' => [],
];

$node = new ValueNode($data['value']);

foreach ($data['children'] as $key => $child) {
$node->add($this->arrayToTree($child));
}

return $node;
}

/**
* Parse a string into an array.
*
* @param string $subject
* The subject string.
*
* @return array|bool
* The array.
*/
private function parse(string $subject)
{
$result = false;

\preg_match_all('~[^\[\]]+|\[(?<nested>(?R)*)\]~', $subject, $matches);

foreach (\array_filter($matches['nested']) as $match) {
$item = [];
$position = \strpos($match, '[');

if (false !== $position) {
$item['value'] = \substr($match, 0, $position);
} else {
$item['value'] = $match;
}

if (false !== $children = $this->parse($match)) {
$item['children'] = $children;
}

$result[] = $item;
}

return $result;
}
}

0 comments on commit 9b87679

Please sign in to comment.