Skip to content

Commit 4ff69b9

Browse files
committed
Merge remote-tracking branch 'origin/8.x'
2 parents 5ad4db1 + bec5ecc commit 4ff69b9

File tree

7 files changed

+114
-35
lines changed

7 files changed

+114
-35
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# Changelog
22

3+
## v8.6.0 (2025-08-11)
4+
5+
### What's new
6+
* Allow programmatic registration of resources #707 by @Pluuk
7+
* Update RoutingModel `model` property to be publicly accessible #706 by @jamesmpigott
8+
9+
### What's fixed
10+
* Fix error when searching via fieldtype #699 #709 by @duncanmcclean
11+
* Refactor `BaseFieldtype::getIndexItems` #708 by @duncanmcclean
12+
* Delete `php-cs-fixer.phar` #704 by @duncanmcclean
13+
14+
15+
316
## v8.5.2 (2025-07-10)
417

518
### What's fixed

php-cs-fixer.phar

-2.73 MB
Binary file not shown.

src/Fieldtypes/BaseFieldtype.php

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
use Statamic\CP\Column;
1313
use Statamic\Facades\Blink;
1414
use Statamic\Facades\Scope;
15+
use Statamic\Facades\Search;
1516
use Statamic\Fieldtypes\Relationship;
16-
use Statamic\Query\Builder as BaseStatamicBuilder;
17+
use Statamic\Http\Requests\FilteredRequest;
1718
use Statamic\Query\Scopes\Filter;
19+
use Statamic\Search\Index;
20+
use Statamic\Search\QueryBuilder as SearchQueryBuilder;
1821
use Statamic\Search\Result;
1922
use StatamicRadPack\Runway\Http\Resources\CP\FieldtypeModel;
2023
use StatamicRadPack\Runway\Http\Resources\CP\FieldtypeModels;
@@ -99,6 +102,11 @@ protected function configFieldItems(): array
99102
'type' => 'text',
100103
'width' => 50,
101104
],
105+
'search_index' => [
106+
'display' => __('Search Index'),
107+
'instructions' => __('An appropriate search index will be used automatically where possible, but you may define an explicit one.'),
108+
'type' => 'text',
109+
],
102110
'query_scopes' => [
103111
'display' => __('Query Scopes'),
104112
'instructions' => __('Select which query fields should be applied when retrieving selectable models.'),
@@ -162,44 +170,68 @@ public function process($data)
162170

163171
public function getIndexItems($request)
164172
{
165-
$resource = $this->resource();
166-
167173
$query = $this->getIndexQuery($request);
168174

169-
$searchQuery = $request->search ?? false;
175+
$this->applyOrderingToIndexQuery($query, $request);
176+
177+
$results = ($paginate = $request->boolean('paginate', true)) ? $query->paginate() : $query->get();
178+
179+
$items = $results->map(fn ($item) => $item instanceof Result ? $item->getSearchable()->model() : $item);
170180

171-
$query = $this->applySearch($resource, $query, $searchQuery);
181+
return $paginate ? $results->setCollection($items) : $items;
182+
}
172183

173-
$query->when(method_exists($query, 'getQuery') && $query->getQuery()->orders, function ($query) use ($request, $resource) {
184+
private function applyOrderingToIndexQuery(Builder|SearchQueryBuilder $query, FilteredRequest $request): void
185+
{
186+
$query->when(method_exists($query, 'getQuery') && $query->getQuery()->orders, function ($query) use ($request) {
174187
if ($orderBy = $request->input('sort')) {
175188
// The stack selector always uses `title` as the default sort column, but
176-
// the "title field" for the model might be a different column so we need to convert it.
177-
$sortColumn = $orderBy === 'title' ? $resource->titleField() : $orderBy;
189+
// the "title field" for the model might be a different column, so we need to convert it.
190+
$sortColumn = $orderBy === 'title' ? $this->resource()->titleField() : $orderBy;
178191

179192
$query->reorder($sortColumn, $request->input('order'));
180193
}
181-
}, fn ($query) => $query->orderBy($resource->orderBy(), $resource->orderByDirection()));
194+
}, fn ($query) => $query->orderBy($this->resource()->orderBy(), $this->resource()->orderByDirection()));
195+
}
182196

183-
$results = ($paginate = $request->boolean('paginate', true)) ? $query->paginate() : $query->get();
197+
protected function getIndexQuery(FilteredRequest $request): Builder|SearchQueryBuilder
198+
{
199+
$query = $this->resource()->newEloquentQuery();
184200

185-
if ($searchQuery && $resource->hasSearchIndex()) {
186-
$results->setCollection($results->getCollection()->map(fn ($item) => $item->getSearchable()->model()));
187-
}
201+
$query = $this->toSearchQuery($query, $request);
188202

189-
$items = $results->map(fn ($item) => $item instanceof Result ? $item->getSearchable() : $item);
203+
$query->when($query instanceof Builder && $query->hasNamedScope('runwayListing'), fn ($query) => $query->runwayListing());
190204

191-
return $paginate ? $results->setCollection($items) : $items;
205+
$this->applyIndexQueryScopes($query, $request->all());
206+
207+
return $query;
192208
}
193209

194-
protected function getIndexQuery($request)
210+
private function toSearchQuery(Builder $query, FilteredRequest $request): Builder|SearchQueryBuilder
195211
{
196-
$query = $this->resource()->newEloquentQuery();
212+
if (! $search = $request->search) {
213+
return $query;
214+
}
197215

198-
$query->when($query->hasNamedScope('runwayListing'), fn ($query) => $query->runwayListing());
216+
if ($index = $this->getSearchIndex()) {
217+
return $index->search($search);
218+
}
199219

200-
$this->applyIndexQueryScopes($query, $request->all());
220+
return $query->runwaySearch($search);
221+
}
201222

202-
return $query;
223+
private function getSearchIndex(): ?Index
224+
{
225+
$index = $this->getExplicitSearchIndex() ?? $this->resource()->searchIndex();
226+
227+
return $index?->ensureExists();
228+
}
229+
230+
private function getExplicitSearchIndex(): ?Index
231+
{
232+
return ($explicit = $this->config('search_index'))
233+
? Search::in($explicit)
234+
: null;
203235
}
204236

205237
public function getResourceCollection($request, $items)
@@ -370,19 +402,6 @@ protected function statusIcons()
370402
return $resource->hasPublishStates();
371403
}
372404

373-
private function applySearch(Resource $resource, Builder $query, string $searchQuery): Builder|BaseStatamicBuilder
374-
{
375-
if (! $searchQuery) {
376-
return $query;
377-
}
378-
379-
if ($resource->hasSearchIndex() && ($index = $resource->searchIndex())) {
380-
return $index->ensureExists()->search($searchQuery);
381-
}
382-
383-
return $query->runwaySearch($searchQuery);
384-
}
385-
386405
private function resource(): Resource
387406
{
388407
return Runway::findResource($this->config('resource'));

src/Routing/RoutingModel.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Statamic\Contracts\Data\Augmentable;
88
use Statamic\Data\ContainsSupplementalData;
99
use Statamic\Data\HasAugmentedData;
10+
use StatamicRadPack\Runway\Resource;
1011
use StatamicRadPack\Runway\Runway;
1112

1213
class RoutingModel implements Augmentable, Responsable
@@ -51,14 +52,19 @@ public function toResponse($request)
5152
->toResponse($request);
5253
}
5354

55+
public function resource(): ?Resource
56+
{
57+
return Runway::findResourceByModel($this->model);
58+
}
59+
5460
public function template(): string
5561
{
56-
return Runway::findResourceByModel($this->model)->template();
62+
return $this->resource()->template();
5763
}
5864

5965
public function layout(): string
6066
{
61-
return Runway::findResourceByModel($this->model)->layout();
67+
return $this->resource()->layout();
6268
}
6369

6470
public function id()

src/Runway.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
class Runway
1212
{
1313
protected static array $resources = [];
14+
protected static array $registeredResources = [];
1415

1516
public static function discoverResources(): self
1617
{
1718
static::$resources = collect(config('runway.resources'))
19+
->merge(static::$registeredResources)
1820
->mapWithKeys(function ($config, $model) {
1921
$config = collect($config);
2022
$handle = $config->get('handle', Str::snake(class_basename($model)));
@@ -66,6 +68,15 @@ public static function findResourceByModel(object $model): ?Resource
6668
return $resource;
6769
}
6870

71+
public static function registerResource(string $model, array $config): self
72+
{
73+
static::$registeredResources[$model] = $config;
74+
75+
static::discoverResources();
76+
77+
return new static;
78+
}
79+
6980
public static function usesRouting(): bool
7081
{
7182
return static::allResources()->filter->hasRouting()->count() >= 1;

tests/Routing/RoutingModelTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Http\Response;
77
use Illuminate\Support\Facades\Config;
88
use PHPUnit\Framework\Attributes\Test;
9+
use StatamicRadPack\Runway\Resource;
910
use StatamicRadPack\Runway\Routing\RoutingModel;
1011
use StatamicRadPack\Runway\Runway;
1112
use StatamicRadPack\Runway\Tests\Fixtures\Models\Post;
@@ -84,6 +85,18 @@ public function can_get_response()
8485
$this->assertStringContainsString("<article>{$post->body}</article>", $response->getContent());
8586
}
8687

88+
#[Test]
89+
public function can_get_resource()
90+
{
91+
Runway::discoverResources();
92+
93+
$post = Post::factory()->createQuietly();
94+
95+
$routingModel = new RoutingModel($post);
96+
97+
$this->assertInstanceOf(Resource::class, $routingModel->resource());
98+
}
99+
87100
#[Test]
88101
public function can_get_template()
89102
{

tests/RunwayTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Statamic\Fields\Blueprint;
99
use StatamicRadPack\Runway\Resource;
1010
use StatamicRadPack\Runway\Runway;
11+
use StatamicRadPack\Runway\Tests\Fixtures\Models\Author;
1112

1213
class RunwayTest extends TestCase
1314
{
@@ -49,4 +50,20 @@ public function can_find_resource()
4950
$this->assertTrue($find->model() instanceof Model);
5051
$this->assertTrue($find->blueprint() instanceof Blueprint);
5152
}
53+
54+
#[Test]
55+
public function can_register_resource()
56+
{
57+
config()->set('runway.resources', []);
58+
59+
Runway::discoverResources();
60+
61+
$this->assertFalse(Runway::allResources()->has('author'));
62+
63+
Runway::registerResource(Author::class, [
64+
'name' => 'Authors',
65+
]);
66+
67+
$this->assertTrue(Runway::allResources()->has('author'));
68+
}
5269
}

0 commit comments

Comments
 (0)