Skip to content

Commit 5896282

Browse files
[8.x] Add query_scopes option to fieldtypes (#672)
Co-authored-by: duncanmcclean <duncanmcclean@users.noreply.github.com>
1 parent 6285530 commit 5896282

File tree

4 files changed

+101
-22
lines changed

4 files changed

+101
-22
lines changed

docs/relationships.md

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,15 @@ Written by {{ author:first_name }} {{ author:last_name }} ({{ author:location }}
4646

4747
### Options
4848

49-
| **Option** | **Description** |
50-
|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
51-
| `mode` | Set the UI style for this field. Can be one of 'default' (Stack Selector), 'select' (Select Dropdown) or 'typeahead' (Typeahead Field). |
52-
| `resource` | Specify the Runway Resource to be used for this field. |
53-
| `relationship_name` | The name of the Eloquent Relationship this field should use. When left empty, Runway will attempt to guess it based on the field's handle. |
54-
| `create` | By default you may create new models. Set to `false` to only allow selecting from existing models. |
55-
| `with` | Specify any relationships you want to be eager loaded when this field is augmented. This option accepts an array of relationships. |
56-
| `title_format` | Configure the title format used for displaying results in the fieldtype. You can use Antlers to pull in model data. |
49+
| **Option** | **Description** |
50+
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
51+
| `mode` | Set the UI style for this field. Can be one of 'default' (Stack Selector), 'select' (Select Dropdown) or 'typeahead' (Typeahead Field). |
52+
| `resource` | Specify the Runway Resource to be used for this field. |
53+
| `relationship_name` | The name of the Eloquent Relationship this field should use. When left empty, Runway will attempt to guess it based on the field's handle. |
54+
| `create` | By default you may create new models. Set to `false` to only allow selecting from existing models. |
55+
| `with` | Specify any relationships you want to be eager loaded when this field is augmented. This option accepts an array of relationships. |
56+
| `title_format` | Configure the title format used for displaying results in the fieldtype. You can use Antlers to pull in model data. |
57+
| `query-scopes` | Allows you to specify a [query scope](https://statamic.dev/extending/query-scopes-and-filters#scopes) which should be applied when retrieving selectable models. You should specify the query scope's handle, which is usually the name of the class in snake case. For example: `MyAwesomeScope` would be `my_awesome_scope`. |
5758

5859
## Has Many
5960

@@ -101,16 +102,18 @@ Loop through the models and do anything you want with the data.
101102

102103
### Options
103104

104-
| **Option** | **Description** |
105-
|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
106-
| `mode` | Set the UI style for this field. Can be one of 'default' (Stack Selector), 'select' (Select Dropdown) or 'typeahead' (Typeahead Field). |
107-
| `resource` | Specify the Runway Resource to be used for this field. |
108-
| `relationship_name` | The name of the Eloquent Relationship this field should use. When left empty, Runway will attempt to guess it based on the field's handle. |
109-
| `create` | By default you may create new models. Set to `false` to only allow selecting from existing models. |
110-
| `with` | Specify any relationships you want to be eager loaded when this field is augmented. This option accepts an array of relationships. |
111-
| `title_format` | Configure the title format used for displaying results in the fieldtype. You can use Antlers to pull in model data. |
112-
| `reorderable` | Determines whether the models can be reordered. Defaults to `false`. |
113-
| `order_column` | When reordering is enabled, this determines which column should be used for storing the sort order. When the relationship uses a pivot table, the order column must exist on the pivot table. |
105+
| **Option** | **Description** |
106+
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
107+
| `mode` | Set the UI style for this field. Can be one of 'default' (Stack Selector), 'select' (Select Dropdown) or 'typeahead' (Typeahead Field). |
108+
| `resource` | Specify the Runway Resource to be used for this field. |
109+
| `relationship_name` | The name of the Eloquent Relationship this field should use. When left empty, Runway will attempt to guess it based on the field's handle. |
110+
| `create` | By default you may create new models. Set to `false` to only allow selecting from existing models. |
111+
| `with` | Specify any relationships you want to be eager loaded when this field is augmented. This option accepts an array of relationships. |
112+
| `title_format` | Configure the title format used for displaying results in the fieldtype. You can use Antlers to pull in model data. |
113+
| `reorderable` | Determines whether the models can be reordered. Defaults to `false`. |
114+
| `order_column` | When reordering is enabled, this determines which column should be used for storing the sort order. When the relationship uses a pivot table, the order column must exist on the pivot table. |
115+
| `query-scopes` | Allows you to specify a [query scope](https://statamic.dev/extending/query-scopes-and-filters#scopes) which should be applied when retrieving selectable models. You should specify the query scope's handle, which is usually the name of the class in snake case. For example: `MyAwesomeScope` would be `my_awesome_scope`. |
116+
114117

115118
## Belongs To Many
116119

src/Fieldtypes/BaseFieldtype.php

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
use Illuminate\Support\Facades\Schema;
1212
use Statamic\CP\Column;
1313
use Statamic\Facades\Blink;
14+
use Statamic\Facades\Scope;
1415
use Statamic\Fieldtypes\Relationship;
1516
use Statamic\Query\Builder as BaseStatamicBuilder;
17+
use Statamic\Query\Scopes\Filter;
1618
use Statamic\Search\Result;
1719
use StatamicRadPack\Runway\Http\Resources\CP\FieldtypeModel;
1820
use StatamicRadPack\Runway\Http\Resources\CP\FieldtypeModels;
@@ -97,6 +99,16 @@ protected function configFieldItems(): array
9799
'type' => 'text',
98100
'width' => 50,
99101
],
102+
'query_scopes' => [
103+
'display' => __('Query Scopes'),
104+
'instructions' => __('Select which query fields should be applied when retrieving selectable models.'),
105+
'type' => 'taggable',
106+
'options' => Scope::all()
107+
->reject(fn ($scope) => $scope instanceof Filter)
108+
->map->handle()
109+
->values()
110+
->all(),
111+
],
100112
];
101113
}
102114

@@ -150,11 +162,9 @@ public function process($data)
150162

151163
public function getIndexItems($request)
152164
{
153-
$resource = Runway::findResource($this->config('resource'));
165+
$resource = $this->resource();
154166

155-
$query = $resource->newEloquentQuery();
156-
157-
$query->when($query->hasNamedScope('runwayListing'), fn ($query) => $query->runwayListing());
167+
$query = $this->getIndexQuery($request);
158168

159169
$searchQuery = $request->search ?? false;
160170

@@ -181,6 +191,17 @@ public function getIndexItems($request)
181191
return $paginate ? $results->setCollection($items) : $items;
182192
}
183193

194+
protected function getIndexQuery($request)
195+
{
196+
$query = $this->resource()->newEloquentQuery();
197+
198+
$query->when($query->hasNamedScope('runwayListing'), fn ($query) => $query->runwayListing());
199+
200+
$this->applyIndexQueryScopes($query, $request->all());
201+
202+
return $query;
203+
}
204+
184205
public function getResourceCollection($request, $items)
185206
{
186207
$resource = Runway::findResource($this->config('resource'));
@@ -361,4 +382,9 @@ private function applySearch(Resource $resource, Builder $query, string $searchQ
361382

362383
return $query->runwaySearch($searchQuery);
363384
}
385+
386+
private function resource(): Resource
387+
{
388+
return Runway::findResource($this->config('resource'));
389+
}
364390
}

tests/Fieldtypes/BelongsToFieldtypeTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use StatamicRadPack\Runway\Fieldtypes\BelongsToFieldtype;
1414
use StatamicRadPack\Runway\Runway;
1515
use StatamicRadPack\Runway\Tests\Fixtures\Models\Author;
16+
use StatamicRadPack\Runway\Tests\Fixtures\Scopes\TheHoff;
1617
use StatamicRadPack\Runway\Tests\TestCase;
1718

1819
class BelongsToFieldtypeTest extends TestCase
@@ -124,6 +125,35 @@ public function can_get_index_items_in_order_from_runway_listing_scope_when_user
124125
$this->assertEquals($getIndexItems->all()[2]->name, 'Scully');
125126
}
126127

128+
#[Test]
129+
public function can_get_index_items_with_query_scopes()
130+
{
131+
TheHoff::register();
132+
133+
Author::factory()->count(10)->create();
134+
$hasselhoff = Author::factory()->create(['name' => 'David Hasselhoff']);
135+
136+
$fieldtype = tap(new BelongsToFieldtype)
137+
->setField(new Field('author', [
138+
'max_items' => 1,
139+
'mode' => 'stack',
140+
'resource' => 'author',
141+
'display' => 'Author',
142+
'type' => 'belongs_to',
143+
'query_scopes' => ['the_hoff'],
144+
]));
145+
146+
$getIndexItems = $fieldtype->getIndexItems(
147+
new FilteredRequest(['paginate' => true])
148+
);
149+
150+
$this->assertIsObject($getIndexItems);
151+
$this->assertTrue($getIndexItems instanceof Paginator);
152+
$this->assertEquals($getIndexItems->count(), 1);
153+
154+
$this->assertEquals($getIndexItems->first()['id'], $hasselhoff->id);
155+
}
156+
127157
#[Test]
128158
public function can_get_index_items_and_search()
129159
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace StatamicRadPack\Runway\Tests\Fixtures\Scopes;
4+
5+
use Statamic\Query\Scopes\Scope;
6+
7+
class TheHoff extends Scope
8+
{
9+
/**
10+
* Apply the scope.
11+
*
12+
* @param \Statamic\Query\Builder $query
13+
* @param array $values
14+
* @return void
15+
*/
16+
public function apply($query, $values)
17+
{
18+
$query->where('name', 'like', '%Hasselhoff%');
19+
}
20+
}

0 commit comments

Comments
 (0)