Skip to content

Commit 81fe0aa

Browse files
authored
Auto create (#10)
* Started on the functionality for automatically creating detours when slugs are changed for pages. * Base version of auto create working. Added findBy to repository to support detour lookup * Added full test coverage for automatically creating detours functionality. * Added an integration test to test the full flow of automatically creating detours * Set default driver back to file * Different approach to functionality * Only listening to entry saved and remove CollectionTreeSaved for now. * Finished implementation with only EntrySaved event listener * Accidentally pushed eloquent as default driver * Fix pipelines and added tests for coverage * Fix pipelines * Add auto create description to README.md * Config publish change suggestion by Kevin * Pull request feedback by Bob * Feedback by Kevin
1 parent 04863c4 commit 81fe0aa

21 files changed

+743
-1
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,21 @@ Or set via environment variable:
117117
STATAMIC_DETOUR_MODE=performance
118118
```
119119

120+
### Auto create
121+
Redirects are automatically created whenever an entry's slug is changed. If you change the slug of a parent, this change will also be reflected in its children.
122+
123+
```php
124+
return [
125+
'auto_create' => true,
126+
];
127+
```
128+
129+
Or set via environment variable:
130+
131+
```env
132+
STATAMIC_DETOUR_AUTO_CREATE=true
133+
```
134+
120135
## Usage
121136

122137
### Creating Redirects

config/statamic-detour.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
'mode' => env('STATAMIC_DETOUR_MODE', 'basic'), // basic | performance
1818

19+
'auto_create' => env('STATAMIC_DETOUR_AUTO_CREATE', true),
20+
1921
'actions' => [
2022
'disk' => 'local',
2123
],
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Actions;
4+
5+
use JustBetter\Detour\Contracts\CreatesDetoursFromEntry;
6+
use JustBetter\Detour\Contracts\DeletesDetour;
7+
use JustBetter\Detour\Contracts\FindsDetour;
8+
use JustBetter\Detour\Contracts\GetsOldEntryUri;
9+
use JustBetter\Detour\Contracts\StoresDetour;
10+
use JustBetter\Detour\Data\Form;
11+
use JustBetter\Detour\Enums\Type;
12+
use JustBetter\Detour\Utils\EntryHelper;
13+
use Statamic\Entries\Entry;
14+
use Statamic\Facades\Entry as EntryFacade;
15+
16+
class CreateDetoursFromEntry implements CreatesDetoursFromEntry
17+
{
18+
public function __construct(
19+
protected FindsDetour $findContract,
20+
protected StoresDetour $storeContract,
21+
protected DeletesDetour $deleteContract,
22+
protected GetsOldEntryUri $getOldEntryUriContract,
23+
) {}
24+
25+
public function create(Entry $entry): void
26+
{
27+
if (! config()->boolean('justbetter.statamic-detour.auto_create')) {
28+
return;
29+
}
30+
31+
$parentEntryId = $entry->id();
32+
$parentOldSlug = $entry->getOriginal('slug');
33+
$parentNewSlug = $entry->slug();
34+
35+
foreach (EntryHelper::entryAndDescendantIds($entry) as $entryId) {
36+
/** @var Entry $target */
37+
$target = $entryId === $parentEntryId
38+
? $entry
39+
: EntryFacade::find($entryId);
40+
41+
if ($entryId === $parentEntryId) {
42+
$this->createDetour($target);
43+
44+
continue;
45+
}
46+
47+
$this->createDetour($target, $parentOldSlug, $parentNewSlug);
48+
}
49+
}
50+
51+
protected function createDetour(Entry $entry, ?string $parentOldSlug = null, ?string $parentNewSlug = null): void
52+
{
53+
if (! $entry->uri()) {
54+
return;
55+
}
56+
if ($parentOldSlug && $parentNewSlug) {
57+
$oldUri = $this->getOldEntryUriContract->get($entry, $parentOldSlug, $parentNewSlug);
58+
} else {
59+
$oldUri = $this->getOldEntryUriContract->get($entry);
60+
}
61+
62+
if (! $oldUri || $entry->uri() === $oldUri) {
63+
return;
64+
}
65+
66+
if ($conflictingDetour = $this->findContract->firstWhere('from', $entry->uri())) {
67+
$this->deleteContract->delete($conflictingDetour->id);
68+
}
69+
70+
$data = Form::make([
71+
'from' => $oldUri,
72+
'to' => $entry->uri(),
73+
'code' => '301',
74+
'type' => Type::Path->value,
75+
]);
76+
77+
$this->storeContract->store($data);
78+
}
79+
80+
public static function bind(): void
81+
{
82+
app()->singleton(CreatesDetoursFromEntry::class, static::class);
83+
}
84+
}

src/Actions/FindDetour.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Actions;
4+
5+
use JustBetter\Detour\Contracts\FindsDetour;
6+
use JustBetter\Detour\Contracts\ResolvesRepository;
7+
use JustBetter\Detour\Data\Detour;
8+
9+
class FindDetour implements FindsDetour
10+
{
11+
public function __construct(
12+
protected ResolvesRepository $resolvesRepository
13+
) {}
14+
15+
public function firstWhere(string $field, mixed $value): ?Detour
16+
{
17+
$repository = $this->resolvesRepository->resolve();
18+
19+
return $repository->firstWhere($field, $value);
20+
}
21+
22+
public static function bind(): void
23+
{
24+
app()->singleton(FindsDetour::class, static::class);
25+
}
26+
}

src/Actions/GetOldEntryUri.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Actions;
4+
5+
use Illuminate\Support\Str;
6+
use JustBetter\Detour\Contracts\GetsOldEntryUri;
7+
use Statamic\Entries\Entry;
8+
9+
class GetOldEntryUri implements GetsOldEntryUri
10+
{
11+
public function get(Entry $entry, ?string $parentOldSlug = null, ?string $parentNewSlug = null): ?string
12+
{
13+
if (! ($uri = $entry->uri()) || ! $entry->published()) {
14+
return null;
15+
}
16+
17+
$originalSlug = $entry->getOriginal('slug');
18+
$uriWithoutSlug = Str::beforeLast($uri, '/');
19+
$slug = is_string($originalSlug) && $originalSlug !== '' ? $originalSlug : $entry->slug();
20+
21+
$oldUri = "$uriWithoutSlug/$slug";
22+
23+
if ($parentOldSlug && $parentNewSlug) {
24+
$oldUri = Str::replace($parentNewSlug, $parentOldSlug, $oldUri);
25+
}
26+
27+
return $oldUri;
28+
}
29+
30+
public static function bind(): void
31+
{
32+
app()->singleton(GetsOldEntryUri::class, static::class);
33+
}
34+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Contracts;
4+
5+
use Statamic\Entries\Entry;
6+
7+
interface CreatesDetoursFromEntry
8+
{
9+
public function create(Entry $entry): void;
10+
}

src/Contracts/FindsDetour.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Contracts;
4+
5+
use JustBetter\Detour\Data\Detour;
6+
7+
interface FindsDetour
8+
{
9+
public function firstWhere(string $field, mixed $value): ?Detour;
10+
}

src/Contracts/GetsOldEntryUri.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Contracts;
4+
5+
use Statamic\Entries\Entry;
6+
7+
interface GetsOldEntryUri
8+
{
9+
public function get(Entry $entry, ?string $parentOldSlug = null, ?string $parentNewSlug = null): ?string;
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace JustBetter\Detour\Listeners;
4+
5+
use JustBetter\Detour\Contracts\CreatesDetoursFromEntry;
6+
use Statamic\Events\EntrySaved;
7+
8+
class EntrySavedListener
9+
{
10+
public function __construct(
11+
protected CreatesDetoursFromEntry $contract,
12+
) {}
13+
14+
public function handle(EntrySaved $event): void
15+
{
16+
$this->contract->create($event->entry);
17+
}
18+
}

src/Repositories/BaseRepository.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ abstract public function paginate(Paginate $paginate): LengthAwarePaginator;
1818

1919
abstract public function find(string $id): ?Detour;
2020

21+
abstract public function firstWhere(string $field, mixed $value): ?Detour;
22+
2123
abstract public function store(Form $form): Detour;
2224

2325
abstract public function update(string $id, Form $form): Detour;

0 commit comments

Comments
 (0)