Skip to content

Commit 28567cb

Browse files
author
antoine
committed
wip POC autocomplete endpoint / closure
1 parent 7236c75 commit 28567cb

File tree

2 files changed

+133
-0
lines changed

2 files changed

+133
-0
lines changed

src/Form/Fields/SharpFormAutocompleteRemoteField.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
namespace Code16\Sharp\Form\Fields;
44

5+
use Closure;
56
use Code16\Sharp\Form\Fields\Formatters\AutocompleteFormatter;
67
use Code16\Sharp\Form\Fields\Utils\IsSharpFormAutocompleteField;
78
use Code16\Sharp\Form\Fields\Utils\SharpFormAutocompleteCommonField;
89
use Code16\Sharp\Utils\Fields\IsSharpFieldWithLocalization;
10+
use Illuminate\Contracts\View\View;
11+
use Illuminate\Support\Facades\Blade;
912

1013
class SharpFormAutocompleteRemoteField
1114
extends SharpFormField
@@ -19,6 +22,8 @@ class SharpFormAutocompleteRemoteField
1922
protected int $searchMinChars = 1;
2023
protected string $dataWrapper = '';
2124
protected int $debounceDelay = 300;
25+
protected ?Closure $queryResultsCallback = null;
26+
protected View|string $template;
2227

2328
public static function make(string $key): self
2429
{
@@ -27,6 +32,29 @@ public static function make(string $key): self
2732

2833
return $instance;
2934
}
35+
36+
public function queryResultsUsing(Closure $closure): self
37+
{
38+
$this->queryResultsCallback = $closure;
39+
40+
return $this;
41+
}
42+
43+
public function setTemplate(View|string $template): self
44+
{
45+
$this->template = $template;
46+
47+
return $this;
48+
}
49+
50+
public function render(array $data): string
51+
{
52+
if (is_string($this->template)) {
53+
return Blade::render($this->template, $data);
54+
}
55+
56+
return $this->template->with($data)->render();
57+
}
3058

3159
public function setRemoteEndpoint(string $remoteEndpoint): self
3260
{
@@ -96,6 +124,31 @@ public function setDataWrapper(string $dataWrapper): self
96124

97125
return $this;
98126
}
127+
128+
public function dataWrapper(): string
129+
{
130+
return $this->dataWrapper;
131+
}
132+
133+
public function remoteEndpoint(): string
134+
{
135+
return $this->remoteEndpoint;
136+
}
137+
138+
public function remoteMethod(): string
139+
{
140+
return $this->remoteMethod;
141+
}
142+
143+
public function remoteSearchAttribute(): string
144+
{
145+
return $this->remoteSearchAttribute;
146+
}
147+
148+
public function getQueryResultsCallback(): ?Closure
149+
{
150+
return $this->queryResultsCallback;
151+
}
99152

100153
protected function validationRules(): array
101154
{
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
namespace Code16\Sharp\Http\Controllers\Api;
4+
5+
use Code16\Sharp\Form\Fields\SharpFormAutocompleteRemoteField;
6+
use Illuminate\Contracts\Http\Kernel;
7+
use Illuminate\Http\Client\Response;
8+
use Illuminate\Http\Request;
9+
use Illuminate\Support\Arr;
10+
use Illuminate\Support\Facades\Http;
11+
use Illuminate\Validation\ValidationException;
12+
13+
class ApiAutocompleteController extends ApiController
14+
{
15+
public function index(string $entityKey, string $autocompleteFieldKey)
16+
{
17+
$entity = $this->entityManager->entityFor($entityKey);
18+
19+
sharp_check_ability(
20+
'view',
21+
$entityKey,
22+
);
23+
24+
$form = $entity->getFormOrFail(sharp_normalize_entity_key($entityKey)[1]);
25+
26+
$field = $form->findFieldByKey($autocompleteFieldKey);
27+
28+
if(!$field instanceof SharpFormAutocompleteRemoteField) {
29+
throw ValidationException::withMessages([
30+
'autocompleteFieldKey' => 'Unknown remote autocomplete field : '.$autocompleteFieldKey,
31+
]);
32+
}
33+
34+
request()->validate([
35+
'endpoint' => ['nullable', 'starts_with:'.str($field->remoteEndpoint())->before('{{')],
36+
'search' => ['required', 'string'],
37+
]);
38+
39+
if($callback = $field->getQueryResultsCallback()) {
40+
$data = $callback(request()->input('search'));
41+
} else {
42+
if(str($field->remoteEndpoint())->startsWith('/')) {
43+
$response = app()->handle(
44+
tap(Request::create(
45+
uri: url($field->remoteEndpoint()),
46+
method: $field->remoteMethod(),
47+
parameters: [
48+
$field->remoteSearchAttribute() => request()->input('search'),
49+
],
50+
cookies: request()->cookies->all(),
51+
), function(Request $request) use($field) {
52+
$request->headers->set('Accept', 'application/json');
53+
})
54+
);
55+
56+
$data = json_decode($response->getContent());
57+
} else {
58+
$pendingRequest = Http::createPendingRequest()
59+
->acceptJson()
60+
->throw()
61+
->withQueryParameters([
62+
$field->remoteSearchAttribute() => request()->input('search'),
63+
]);
64+
if($field->remoteMethod() === 'POST') {
65+
$apiResponse = $pendingRequest->post(request()->input('endpoint'));
66+
} else {
67+
$apiResponse = $pendingRequest->get(request()->input('endpoint'));
68+
}
69+
$data = $apiResponse->json();
70+
}
71+
}
72+
73+
return response()->json([
74+
'data' => collect(Arr::get($data, $field->dataWrapper() ?: null))->map(fn ($item) => [
75+
...$item,
76+
'_html' => $field->render($item),
77+
]),
78+
]);
79+
}
80+
}

0 commit comments

Comments
 (0)