Skip to content

Commit

Permalink
Moves MPT static methods to a separate helper class (Path)
Browse files Browse the repository at this point in the history
  • Loading branch information
dakujem committed Jan 26, 2024
1 parent bf2be86 commit 0979d26
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 42 deletions.
8 changes: 6 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ The following tree will be used in the examples below:
```

Simple example of a fixed-length MPT:

```php
use Any\Item;
use Dakujem\Oliva\MaterializedPath\Path;
use Dakujem\Oliva\MaterializedPath\TreeBuilder;
use Dakujem\Oliva\Node;

Expand All @@ -128,7 +130,7 @@ $collection = [

$builder = new TreeBuilder(
node: fn(Item $item) => new Node($item), // How to create a node.
vector: TreeBuilder::fixed( // How to extract path vector.
vector: Path::fixed( // How to extract path vector.
levelWidth: 3,
accessor: fn(Item $item) => $item->path,
),
Expand All @@ -140,8 +142,10 @@ $root = $builder->build(
```

Same example with an equivalent delimited MPT:

```php
use Any\Item;
use Dakujem\Oliva\MaterializedPath\Path;
use Dakujem\Oliva\MaterializedPath\TreeBuilder;
use Dakujem\Oliva\Node;

Expand All @@ -158,7 +162,7 @@ $collection = [

$builder = new TreeBuilder(
node: fn(Item $item) => new Node($item), // How to create a node.
vector: TreeBuilder::delimited( // How to extract path vector.
vector: Path::delimited( // How to extract path vector.
delimiter: '.',
accessor: fn(Item $item) => $item->path,
),
Expand Down
68 changes: 68 additions & 0 deletions src/MaterializedPath/Path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

declare(strict_types=1);

namespace Dakujem\Oliva\MaterializedPath;

use LogicException;

/**
* @author Andrej Rypak <xrypak@gmail.com>
*/
final class Path
{
/**
* Creates an extractor callable for tree builders that extracts vectors from materialized paths with delimiters.
* These paths contain hierarchy information with variable-width levels delimited by a selected character.
* The vectors are extracted by exploding the path string.
*
* @param string $delimiter The delimiter character.
* @param callable $accessor An accessor callable that returns the raw path, signature `fn(mixed $data, mixed $inputIndex, TreeNodeContract $node): string`.
* @return callable Vector extractor for the MPT builder.
*/
public static function delimited(string $delimiter, callable $accessor): callable
{
if (strlen($delimiter) !== 1) {
throw new LogicException('The delimiter must be a single character.');
}
return function (mixed $data) use ($delimiter, $accessor): array {
$path = $accessor($data);
if (null === $path) {
return [];
}
if (!is_string($path)) {
// TODO improve exceptions (index/path etc)
throw new InvalidTreePath('Invalid tree path returned by the accessor. A string is required.');
}
$path = trim($path, $delimiter);
if ('' === $path) {
return [];
}
return explode($delimiter, $path);
};
}

/**
* Creates an extractor callable for tree builders that extracts vectors from materialized paths without delimiters.
* These paths contain hierarchy information with constant character count per level of depth.
* The vectors are extracted by splitting the path string by the given number.
*
* @param int $levelWidth The number of characters per level.
* @param callable $accessor An accessor callable that returns the raw path, signature `fn(mixed $data, mixed $inputIndex, TreeNodeContract $node): string`.
* @return callable Vector extractor for the MPT builder.
*/
public static function fixed(int $levelWidth, callable $accessor): callable
{
return function (mixed $data) use ($levelWidth, $accessor): array {
$path = $accessor($data);
if (null === $path || $path === '') {
return [];
}
if (!is_string($path)) {
// TODO improve exceptions (index/path etc)
throw new InvalidTreePath('Invalid tree path returned by the accessor. A string is required.');
}
return str_split($path, $levelWidth);
};
}
}
37 changes: 0 additions & 37 deletions src/MaterializedPath/TreeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,43 +67,6 @@ public function __construct(
$this->vector = $vector;
}

public static function fixed(int $levelWidth, callable $accessor): callable
{
return function (mixed $data) use ($levelWidth, $accessor): array {
$path = $accessor($data);
if (null === $path || $path === '') {
return [];
}
if (!is_string($path)) {
// TODO improve exceptions (index/path etc)
throw new InvalidTreePath('Invalid tree path returned by the accessor. A string is required.');
}
return str_split($path, $levelWidth);
};
}

public static function delimited(string $delimiter, callable $accessor): callable
{
if (strlen($delimiter) !== 1) {
throw new LogicException('The delimiter must be a single character.');
}
return function (mixed $data) use ($delimiter, $accessor): array {
$path = $accessor($data);
if (null === $path) {
return [];
}
if (!is_string($path)) {
// TODO improve exceptions (index/path etc)
throw new InvalidTreePath('Invalid tree path returned by the accessor. A string is required.');
}
$path = trim($path, $delimiter);
if ('' === $path) {
return [];
}
return explode($delimiter, $path);
};
}

public function build(iterable $input): TreeNodeContract
{
$root = $this->processInput($input)->root();
Expand Down
7 changes: 4 additions & 3 deletions tests/mptree.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
declare(strict_types=1);

use Dakujem\Oliva\Iterator\PreOrderTraversal;
use Dakujem\Oliva\MaterializedPath\Path;
use Dakujem\Oliva\MaterializedPath\Support\AlmostThere;
use Dakujem\Oliva\MaterializedPath\TreeBuilder;
use Dakujem\Oliva\Node;
Expand Down Expand Up @@ -53,7 +54,7 @@ class Item

$builder = new TreeBuilder(
node: fn(?Item $item) => new Node($item),
vector: TreeBuilder::fixed(
vector: Path::fixed(
3,
fn(?Item $item) => $item?->path,
),
Expand All @@ -80,7 +81,7 @@ class Item
], $toArray($almost->root()));


$vectorExtractor = TreeBuilder::fixed(
$vectorExtractor = Path::fixed(
3,
fn(mixed $path) => $path,
);
Expand Down Expand Up @@ -139,7 +140,7 @@ class Item

$builder = new TreeBuilder(
node: fn(Item $item) => new Node($item),
vector: TreeBuilder::delimited(
vector: Path::delimited(
delimiter: '.',
accessor: fn(Item $item) => $item->path,
),
Expand Down

0 comments on commit 0979d26

Please sign in to comment.