Skip to content

Commit 095d0f7

Browse files
authored
Merge pull request #118 from Lomkit/feature/laravel-scout-integration
🚧 laravel scout implementation
2 parents 3c18e55 + a759e44 commit 095d0f7

19 files changed

+898
-26
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,4 @@ Here is a quick look at what you can do using API search method:
9090

9191
- Metrics support
9292
- Refactor the response class
93-
- Plain text search using Laravel Scout
9493
- Alias for includes / aggregates

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"require-dev": {
1818
"guzzlehttp/guzzle": "^6.0|^7.0",
1919
"orchestra/testbench": "^8.5|^9.0",
20-
"phpunit/phpunit": "^8.0|^9.0|^10.0|^11.0"
20+
"phpunit/phpunit": "^8.0|^9.0|^10.0|^11.0",
21+
"laravel/scout": "^10.0|^11.0"
2122
},
2223
"autoload": {
2324
"psr-4": {

src/Concerns/PerformsQueries.php

+13
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ public function searchQuery(\Lomkit\Rest\Http\Requests\RestRequest $request, \Il
1717
return $query;
1818
}
1919

20+
/**
21+
* Build a "search" scout query for fetching resource.
22+
*
23+
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
24+
* @param \Laravel\Scout\Builder $query
25+
*
26+
* @return \Laravel\Scout\Builder
27+
*/
28+
public function searchScoutQuery(\Lomkit\Rest\Http\Requests\RestRequest $request, \Laravel\Scout\Builder $query)
29+
{
30+
return $query;
31+
}
32+
2033
/**
2134
* Build a query for mutating resource.
2235
*

src/Concerns/PerformsRestOperations.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use Lomkit\Rest\Http\Requests\OperateRequest;
1212
use Lomkit\Rest\Http\Requests\RestoreRequest;
1313
use Lomkit\Rest\Http\Requests\SearchRequest;
14+
use Lomkit\Rest\Query\ScoutBuilder;
1415

1516
trait PerformsRestOperations
1617
{
@@ -47,7 +48,9 @@ public function search(SearchRequest $request)
4748

4849
$this->beforeSearch($request);
4950

50-
$query = app()->make(QueryBuilder::class, ['resource' => $resource, 'query' => null])
51+
$builder = $request->has('search.text') ? ScoutBuilder::class : QueryBuilder::class;
52+
53+
$query = app()->make($builder, ['resource' => $resource, 'query' => null])
5154
->search($request->input('search', []));
5255

5356
$responsable = $resource->paginate($query, $request);

src/Concerns/Resource/Paginable.php

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
namespace Lomkit\Rest\Concerns\Resource;
44

5-
use Illuminate\Database\Eloquent\Builder;
5+
use Laravel\Scout\Builder;
66
use Lomkit\Rest\Http\Requests\RestRequest;
77

88
trait Paginable
99
{
1010
/**
1111
* Paginate the results of a query.
1212
*
13-
* @param Builder $query
14-
* @param RestRequest $request
13+
* @param Illuminate\Database\Eloquent\Builder|\Laravel\Scout\Builder $query
14+
* @param RestRequest $request
1515
*
1616
* @return mixed
1717
*/
18-
public function paginate(Builder $query, RestRequest $request)
18+
public function paginate($query, RestRequest $request)
1919
{
20+
// In case we have a scout builder
21+
if ($query instanceof Builder) {
22+
return $query->paginate($request->input('search.limit', 50), 'page', $request->input('search.page', 1));
23+
}
24+
2025
return $query->paginate($request->input('search.limit', 50), ['*'], 'page', $request->input('search.page', 1));
2126
}
2227
}

src/Concerns/Resource/Scoutable.php

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?php
2+
3+
namespace Lomkit\Rest\Concerns\Resource;
4+
5+
use Lomkit\Rest\Http\Requests\RestRequest;
6+
use Lomkit\Rest\Instructions\Instruction;
7+
8+
trait Scoutable
9+
{
10+
/**
11+
* The calculated scout fields if already done in this request.
12+
*
13+
* @var array
14+
*/
15+
protected array $calculatedScoutFields;
16+
17+
/**
18+
* The calculated scout instructions if already done in this request.
19+
*
20+
* @var array
21+
*/
22+
protected array $calculatedScoutInstructions;
23+
24+
/**
25+
* The scout fields that could be provided.
26+
*
27+
* @param RestRequest $request
28+
*
29+
* @return array
30+
*/
31+
public function scoutFields(RestRequest $request): array
32+
{
33+
return [];
34+
}
35+
36+
/**
37+
* The scout instructions that could be provided.
38+
*
39+
* @param RestRequest $request
40+
*
41+
* @return array
42+
*/
43+
public function scoutInstructions(RestRequest $request): array
44+
{
45+
return [];
46+
}
47+
48+
/**
49+
* Get the resource's scout fields.
50+
*
51+
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
52+
*
53+
* @return array
54+
*/
55+
public function getScoutFields(\Lomkit\Rest\Http\Requests\RestRequest $request): array
56+
{
57+
return $this->calculatedScoutFields ?? ($this->calculatedScoutFields = $this->scoutFields($request));
58+
}
59+
60+
/**
61+
* Get the resource's scout instructions.
62+
*
63+
* @param \Lomkit\Rest\Http\Requests\RestRequest $request
64+
*
65+
* @return array
66+
*/
67+
public function getScoutInstructions(\Lomkit\Rest\Http\Requests\RestRequest $request): array
68+
{
69+
return $this->calculatedScoutInstructions ?? ($this->calculatedScoutInstructions = $this->scoutInstructions($request));
70+
}
71+
72+
/**
73+
* Retrieve a specific scout instruction by its key.
74+
*
75+
* @param RestRequest $request The REST request instance.
76+
* @param string $instructionKey The key of the instruction to retrieve.
77+
*
78+
* @return Instruction|null The instruction instance or null if not found.
79+
*/
80+
public function scoutInstruction(RestRequest $request, string $instructionKey)
81+
{
82+
$instruction = collect($this->getScoutInstructions($request))
83+
->first(function (Instruction $instruction) use ($instructionKey) {
84+
return $instruction->uriKey() === $instructionKey;
85+
});
86+
87+
if (!is_null($instruction)) {
88+
$instruction
89+
->resource($this);
90+
}
91+
92+
return $instruction;
93+
}
94+
}

src/Contracts/QueryBuilder.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public function search(array $parameters = []);
1616
/**
1717
* Convert the query builder to an Eloquent query builder.
1818
*
19-
* @return \Illuminate\Database\Eloquent\Builder
19+
* @return \Illuminate\Database\Eloquent\Builder|\Laravel\Scout\Builder
2020
*/
2121
public function toBase();
2222
}

src/Http/Resource.php

+17-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Database\Eloquent\Model;
66
use Illuminate\Support\Str;
7+
use Laravel\Scout\Searchable;
78
use Lomkit\Rest\Actions\Actionable;
89
use Lomkit\Rest\Concerns\Authorizable;
910
use Lomkit\Rest\Concerns\PerformsModelOperations;
@@ -13,6 +14,7 @@
1314
use Lomkit\Rest\Concerns\Resource\Paginable;
1415
use Lomkit\Rest\Concerns\Resource\Relationable;
1516
use Lomkit\Rest\Concerns\Resource\Rulable;
17+
use Lomkit\Rest\Concerns\Resource\Scoutable;
1618
use Lomkit\Rest\Http\Requests\RestRequest;
1719
use Lomkit\Rest\Instructions\Instructionable;
1820

@@ -22,6 +24,7 @@ class Resource implements \JsonSerializable
2224
use PerformsModelOperations;
2325
use Relationable;
2426
use Paginable;
27+
use Scoutable;
2528
use Rulable;
2629
use ConfiguresRestParameters;
2730
use Authorizable;
@@ -142,6 +145,11 @@ public function cacheAuthorizationFor()
142145
return now()->addMinutes(config('rest.authorizations.cache.default', 5));
143146
}
144147

148+
public function isModelSearchable()
149+
{
150+
return in_array(Searchable::class, class_uses_recursive(static::$model));
151+
}
152+
145153
/**
146154
* Serialize the resource into a JSON-serializable format.
147155
*
@@ -152,13 +160,15 @@ public function jsonSerialize(): mixed
152160
$request = app(RestRequest::class);
153161

154162
return [
155-
'actions' => collect($this->getActions($request))->map->jsonSerialize()->toArray(),
156-
'instructions' => collect($this->getInstructions($request))->map->jsonSerialize()->toArray(),
157-
'fields' => $this->getFields($request),
158-
'limits' => $this->getLimits($request),
159-
'scopes' => $this->getScopes($request),
160-
'relations' => collect($this->getRelations($request))->map->jsonSerialize()->toArray(),
161-
'rules' => [
163+
'actions' => collect($this->getActions($request))->map->jsonSerialize()->toArray(),
164+
'instructions' => collect($this->getInstructions($request))->map->jsonSerialize()->toArray(),
165+
'scout_instructions' => collect($this->getScoutInstructions($request))->map->jsonSerialize()->toArray(),
166+
'fields' => $this->getFields($request),
167+
'scout_fields' => $this->getScoutFields($request),
168+
'limits' => $this->getLimits($request),
169+
'scopes' => $this->getScopes($request),
170+
'relations' => collect($this->getRelations($request))->map->jsonSerialize()->toArray(),
171+
'rules' => [
162172
'all' => $this->rules($request),
163173
'create' => $this->createRules($request),
164174
'update' => $this->updateRules($request),

src/Instructions/Instruction.php

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Lomkit\Rest\Instructions;
44

5+
use http\Exception\RuntimeException;
56
use Illuminate\Support\Str;
67
use Lomkit\Rest\Concerns\Fieldable;
78
use Lomkit\Rest\Concerns\Makeable;
@@ -72,4 +73,17 @@ public function handle(array $fields, \Illuminate\Database\Eloquent\Builder $que
7273
{
7374
// ...
7475
}
76+
77+
/**
78+
* Perform the instruction on the scout query.
79+
*
80+
* @param array $fields
81+
* @param \Laravel\Scout\Builder $query
82+
*
83+
* @return void
84+
*/
85+
public function handleScout(array $fields, \Laravel\Scout\Builder $query)
86+
{
87+
throw new RuntimeException('Not implemented');
88+
}
7589
}

0 commit comments

Comments
 (0)