diff --git a/docs/guide/context.md b/docs/guide/context.md index fa5af0b91..8cbbd9ba0 100644 --- a/docs/guide/context.md +++ b/docs/guide/context.md @@ -67,7 +67,7 @@ sharp()->context()->breadcrumb(); Get the current or previous breadcrumb item. -### `previousShowSegment(?string $entityKeyOrClassName = null): ?BreadcrumbItem` +### `previousShowSegment(?string $entityKeyOrClassName = null, ?string $subEntity = null): ?BreadcrumbItem` ### `previousListSegment(?string $entityKeyOrClassName = null): ?BreadcrumbItem` Get (if existing) the closest Show or List in the breadcrumb. @@ -87,6 +87,7 @@ A `BreadcrumbItem` instance has the same methods seen above: #### `isUpdate(): bool` #### `isCreation(): bool` #### `instanceId(): string` +#### `entityIs(string $entityKeyOrClassName, ?string $subEntity = null): bool` Here's an example of how this information could be useful: imagine you have a Show for a `Post` instance, with an Embedded Entity List of `Comment`. When creating a new `Comment`, you'll need to set its `post_id` attribute on the Form `update()` method. You can for this make use of the breadcrumb context like this: diff --git a/src/Http/Context/SharpBreadcrumb.php b/src/Http/Context/SharpBreadcrumb.php index c3c3487c9..e08dea7d3 100644 --- a/src/Http/Context/SharpBreadcrumb.php +++ b/src/Http/Context/SharpBreadcrumb.php @@ -62,9 +62,9 @@ public function previousSegment(): ?BreadcrumbItem return $this->breadcrumbItems()->reverse()->skip(1)->first(); } - public function previousShowSegment(?string $entityKeyOrClassName = null): ?BreadcrumbItem + public function previousShowSegment(?string $entityKeyOrClassName = null, ?string $subEntity = null): ?BreadcrumbItem { - return $this->findPreviousSegment('s-show', $entityKeyOrClassName); + return $this->findPreviousSegment('s-show', $entityKeyOrClassName, $subEntity); } public function previousListSegment(?string $entityKeyOrClassName = null): ?BreadcrumbItem @@ -111,7 +111,7 @@ public function breadcrumbItems(): Collection return $this->breadcrumbItems; } - private function findPreviousSegment(string $type, ?string $entityKeyOrClassName = null): ?BreadcrumbItem + private function findPreviousSegment(string $type, ?string $entityKeyOrClassName = null, ?string $subEntity = null): ?BreadcrumbItem { $modeNotEquals = false; if ($entityKeyOrClassName && Str::startsWith($entityKeyOrClassName, '!')) { @@ -124,10 +124,8 @@ private function findPreviousSegment(string $type, ?string $entityKeyOrClassName ->filter(fn (BreadcrumbItem $item) => $item->type === $type) ->when($entityKeyOrClassName !== null, fn ($items) => $items ->filter(fn (BreadcrumbItem $breadcrumbItem) => $modeNotEquals - ? $breadcrumbItem->entityKey() !== app(SharpEntityManager::class) - ->entityKeyFor($entityKeyOrClassName) - : $breadcrumbItem->entityKey() === app(SharpEntityManager::class) - ->entityKeyFor($entityKeyOrClassName) + ? ! $breadcrumbItem->entityIs($entityKeyOrClassName, $subEntity) + : $breadcrumbItem->entityIs($entityKeyOrClassName, $subEntity) ) ) ->first(); diff --git a/src/Http/Context/Util/BreadcrumbItem.php b/src/Http/Context/Util/BreadcrumbItem.php index e9c5e3bc9..7d6163085 100644 --- a/src/Http/Context/Util/BreadcrumbItem.php +++ b/src/Http/Context/Util/BreadcrumbItem.php @@ -3,6 +3,7 @@ namespace Code16\Sharp\Http\Context\Util; use Code16\Sharp\Utils\Entities\SharpEntityManager; +use Code16\Sharp\Utils\Entities\ValueObjects\EntityKey; class BreadcrumbItem { @@ -67,6 +68,15 @@ public function is(BreadcrumbItem $item): bool && $this->instance === $item->instance; } + public function entityIs(string $entityKeyOrClassName, ?string $subEntity = null): bool + { + $selfKey = new EntityKey($this->key); + $resolvedEntityKey = app(SharpEntityManager::class)->entityKeyFor($entityKeyOrClassName); + + return $selfKey->baseKey() === $resolvedEntityKey + && (! $subEntity || $selfKey->subEntity() === $subEntity); + } + public function entityKey(): string { return $this->key; diff --git a/tests/Http/Context/SharpContextTest.php b/tests/Http/Context/SharpContextTest.php index bd2ff8900..046af4f91 100644 --- a/tests/Http/Context/SharpContextTest.php +++ b/tests/Http/Context/SharpContextTest.php @@ -1,10 +1,14 @@ declareEntity(PersonEntity::class); + app(SharpConfigBuilder::class)->declareEntity(PersonEntity::class); $this->fakeBreadcrumbWithUrl('/sharp/s-list/person/s-show/person/31/s-show/person/42/s-show/child/84/s-form/child/84'); expect(sharp()->context()->breadcrumb()) @@ -95,6 +99,62 @@ ->previousShowSegment(PersonEntity::class)->instanceId()->toEqual(42); }); +it('allows to get previous show of a given entity class name & subentity from request', function () { + app(SharpConfigBuilder::class)->declareEntity(PersonEntity::class); + app(SharpEntityManager::class)->entityFor('person')->setMultiforms([ + 'multiform' => [PersonForm::class, 'Multiform'], + ]); + $this->fakeBreadcrumbWithUrl('/sharp/s-list/person/s-show/person/31/s-show/person:multiform/42/s-show/child:multiform/84/s-form/child/84'); + + expect(sharp()->context()->breadcrumb()) + ->previousShowSegment()->entityKey()->toBe('child:multiform') + ->previousShowSegment()->instanceId()->toEqual(84) + ->previousShowSegment(PersonEntity::class)->entityKey()->toBe('person:multiform') + ->previousShowSegment(PersonEntity::class)->instanceId()->toEqual(42) + ->previousShowSegment(PersonEntity::class, 'multiform')->entityKey()->toBe('person:multiform') + ->previousShowSegment(PersonEntity::class, 'multiform')->instanceId()->toEqual(42); +}); + +it('allows to check entity of a segment', function () { + app(SharpConfigBuilder::class)->declareEntity(PersonEntity::class); + app(SharpConfigBuilder::class)->declareEntity(SinglePersonEntity::class); + $this->fakeBreadcrumbWithUrl('/sharp/s-list/person/s-show/person/1/s-form/person/1'); + + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(PersonEntity::class))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs('person'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(PersonEntity::class, 'multiform'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(SinglePersonEntity::class))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs('child'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(PersonEntity::class))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(PersonEntity::class, 'multiform'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(SinglePersonEntity::class))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs('child'))->toBeFalse(); +}); + +it('allows to check entity with subentity of a segment', function () { + app(SharpConfigBuilder::class)->declareEntity(PersonEntity::class); + app(SharpConfigBuilder::class)->declareEntity(SinglePersonEntity::class); + app(SharpEntityManager::class)->entityFor('person')->setMultiforms([ + 'multiform' => [PersonForm::class, 'Multiform'], + ]); + $this->fakeBreadcrumbWithUrl('/sharp/s-list/person/s-show/person:multiform/1/s-form/person:multiform/1'); + + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(PersonEntity::class))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs('person'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs('person', 'multiform'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(PersonEntity::class, 'multiform'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(PersonEntity::class, 'other-multiform'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs(SinglePersonEntity::class))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->currentSegment()->entityIs('child'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(PersonEntity::class))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs('person'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs('person', 'multiform'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(PersonEntity::class, 'multiform'))->toBeTrue(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(PersonEntity::class, 'other-multiform'))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs(SinglePersonEntity::class))->toBeFalse(); + expect(sharp()->context()->breadcrumb()->previousShowSegment()->entityIs('child'))->toBeFalse(); +}); + it('allows to get previous url from request', function () { $this->fakeBreadcrumbWithUrl('/sharp/s-list/person/s-show/person/42/s-form/child/2');