Skip to content

Commit

Permalink
add breadcrumb
Browse files Browse the repository at this point in the history
  • Loading branch information
rodber committed Jan 8, 2024
1 parent 0747fae commit 398123a
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 5 deletions.
90 changes: 90 additions & 0 deletions src/Breadcrumb.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\VarSupport;

use Chevere\VarSupport\Interfaces\BreadcrumbInterface;
use OutOfBoundsException;
use function Chevere\Message\message;

final class Breadcrumb implements BreadcrumbInterface
{
/**
* @var array<int, string>
*/
private array $items = [];

private int $pos = -1;

private int $id = -1;

public function __toString(): string
{
if ($this->items === []) {
return '';
}

$return = '';
foreach ($this->items as $item) {
$return .= sprintf('[%s]', $item);
}

return $return;
}

public function toArray(): array
{
return $this->items;
}

public function has(int $pos): bool
{
return array_key_exists($pos, $this->items);
}

public function count(): int
{
return count($this->items);
}

public function pos(): int
{
return $this->pos;
}

public function withAdded(string $item): BreadcrumbInterface
{
$new = clone $this;
++$new->id;
$new->items[$new->id] = $item;
$new->pos = $new->id;

return $new;
}

public function withRemoved(int $pos): BreadcrumbInterface
{
if (! array_key_exists($pos, $this->items)) {
throw new OutOfBoundsException(
(string) message(
'Pos `%pos%` not found',
pos: $pos
)
);
}
$new = clone $this;
unset($new->items[$pos]);

return $new;
}
}
69 changes: 69 additions & 0 deletions src/Interfaces/BreadcrumbInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\VarSupport\Interfaces;

use Countable;
use Stringable;

/**
* Describe a general purpose iterator companion which builds a breadcrumb
* path for nested variables, enabling to easily locate current position.
*/
interface BreadcrumbInterface extends Stringable, Countable
{
/**
* Returns an string representation of the object.
*
* ```php
* return '[item0][item1][itemN]...[itemN+1]';
* ```
*/
public function __toString(): string;

/**
* Returns an array representation of the object.
*
* ```php
* return [0 => 'item',];
* ```
* @return array<int, string>
*/
public function toArray(): array;

/**
* Indicates whether the instance has the given position.
*/
public function has(int $pos): bool;

/**
* Returns the current breadcrumb position.
*/
public function pos(): int;

/**
* Return an instance with the specified added item.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified added item.
*/
public function withAdded(string $item): self;

/**
* Return an instance with the specified pos removed.
*
* This method MUST retain the state of the current instance, and return
* an instance that contains the specified pos removed.
*/
public function withRemoved(int $pos): self;
}
3 changes: 1 addition & 2 deletions src/ObjectVariable.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@

namespace Chevere\VarSupport;

use Chevere\Iterator\Breadcrumb;
use Chevere\Iterator\Interfaces\BreadcrumbInterface;
use Chevere\VarSupport\Exceptions\ObjectNotClonableException;
use Chevere\VarSupport\Interfaces\BreadcrumbInterface;
use Chevere\VarSupport\Interfaces\ObjectVariableInterface;
use Chevere\VarSupport\Traits\BreadcrumbIterableTrait;
use ReflectionNamedType;
Expand Down
3 changes: 1 addition & 2 deletions src/StorableVariable.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@

namespace Chevere\VarSupport;

use Chevere\Iterator\Breadcrumb;
use Chevere\Iterator\Interfaces\BreadcrumbInterface;
use Chevere\VarSupport\Exceptions\UnableToStoreException;
use Chevere\VarSupport\Interfaces\BreadcrumbInterface;
use Chevere\VarSupport\Interfaces\StorableVariableInterface;
use Chevere\VarSupport\Traits\BreadcrumbIterableTrait;
use ReflectionNamedType;
Expand Down
2 changes: 1 addition & 1 deletion src/Traits/BreadcrumbIterableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

namespace Chevere\VarSupport\Traits;

use Chevere\Iterator\Interfaces\BreadcrumbInterface;
use Chevere\VarSupport\Exceptions\ObjectNotClonableException;
use Chevere\VarSupport\Interfaces\BreadcrumbInterface;
use OutOfBoundsException;

trait BreadcrumbIterableTrait
Expand Down
83 changes: 83 additions & 0 deletions tests/BreadcrumbTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Chevere\Tests;

use Chevere\VarSupport\Breadcrumb;
use OutOfBoundsException;
use PHPUnit\Framework\TestCase;

final class BreadcrumbTest extends TestCase
{
public function testConstruct(): void
{
$breadcrumb = new Breadcrumb();
$this->assertEmpty($breadcrumb->toArray());
$this->assertEmpty($breadcrumb->__toString());
$this->assertCount(0, $breadcrumb);
$this->assertFalse($breadcrumb->has(0));
$this->assertSame(-1, $breadcrumb->pos());
}

public function testWithAddedItems(): void
{
$items = [
'test-0',
'test-1',
'test-2',
];
$breadcrumb = new Breadcrumb();
$withAdded = $breadcrumb;
foreach ($items as $pos => $item) {
$withAdded = $withAdded->withAdded($item);
$this->assertTrue($withAdded->has($pos));
$this->assertSame($pos, $withAdded->pos());
$this->assertContains($item, $withAdded->toArray());
$this->assertStringContainsString($item, $withAdded->__toString());
}
$this->assertNotSame($breadcrumb, $withAdded);
$this->assertSame($items, $withAdded->toArray());
$this->assertSame(
'[' . implode('][', $items) . ']',
$withAdded->__toString()
);
$withRemoved = $withAdded->withRemoved(1);
$this->assertNotSame($withAdded, $withRemoved);
$this->assertNotContains($items[1], $withRemoved->toArray());
$this->assertStringNotContainsString($items[1], $withRemoved->__toString());
}

public function testWithRemovedItems(): void
{
$items = [
'test-0',
'test-1',
'test-2',
];
$breadcrumb = new Breadcrumb();
$pos = 0;
foreach ($items as $pos => $item) {
$breadcrumb = $breadcrumb
->withAdded($item)
->withRemoved($pos);
$this->assertFalse($breadcrumb->has($pos));
$this->assertNotContains($item, $breadcrumb->toArray());
$this->assertStringNotContainsString($item, $breadcrumb->__toString());
}
$this->assertCount(0, $breadcrumb);
$this->assertEmpty($breadcrumb->toArray());
$this->assertEmpty($breadcrumb->__toString());
$this->expectException(OutOfBoundsException::class);
$breadcrumb->withRemoved($pos);
}
}

0 comments on commit 398123a

Please sign in to comment.