From 80c7f3fba0b4f620d30547a4859ee6253199cd84 Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Sat, 24 Jan 2026 13:52:43 +0100 Subject: [PATCH 1/4] Update DataTables helper to use controller --- composer.json | 3 +- src/API/Controllers/BaseController.php | 56 +++++++++++++ src/API/Controllers/DataTablesController.php | 79 +++++++++++++------ src/DTO/DataTablesLoadRequest/Column.php | 13 --- .../DataTablesLoadRequest.php | 36 +++++++-- src/DTO/DataTablesLoadRequest/OrderItem.php | 9 --- src/DTO/DataTablesLoadRequest/Search.php | 8 -- .../DataTablesLoadResponse.php | 2 +- 8 files changed, 142 insertions(+), 64 deletions(-) create mode 100644 src/API/Controllers/BaseController.php diff --git a/composer.json b/composer.json index ff4aa3add..50d1039be 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "ext-simplexml": "*", "ext-xsl": "*", "ext-zip": "*", - "api-platform/laravel": "^4.1", + "api-platform/laravel": "^4.2.14", + "cuyz/valinor": "^2.3", "davidepastore/codice-fiscale": "^0.10.0", "devcode-it/ical-easy-reader": "dev-main", "devcode-it/sdd_ita": "dev-master", diff --git a/src/API/Controllers/BaseController.php b/src/API/Controllers/BaseController.php new file mode 100644 index 000000000..3d6bc3fda --- /dev/null +++ b/src/API/Controllers/BaseController.php @@ -0,0 +1,56 @@ +messages(); + + $formatted = []; + foreach ($messages as $message) { + $formatted[] = str_replace(". for", " for", $message->withBody('{original_message} for parameter "{node_path}"')->toString()); + } + + parent::__construct("Invalid input: ".implode("\n", $formatted)); + } +} + +abstract class BaseController extends Controller +{ + /** + * @template T + * @param class-string $class_reference + * @return T + */ + public function _cast(Request $request, string $class_reference): mixed + { + try { + return (new \CuyZ\Valinor\MapperBuilder()) + ->allowUndefinedValues() + ->allowSuperfluousKeys() + ->allowScalarValueCasting() + ->mapper() + ->map( + $class_reference, + [...$request->route()->parameters(), ...$request->all()] + ); + } catch (\CuyZ\Valinor\Mapper\MappingError $error) { + throw new InvalidInputException($error); + } + } +} diff --git a/src/API/Controllers/DataTablesController.php b/src/API/Controllers/DataTablesController.php index 7e4beec4a..fcae21183 100644 --- a/src/API/Controllers/DataTablesController.php +++ b/src/API/Controllers/DataTablesController.php @@ -2,18 +2,20 @@ namespace API\Controllers; -use ApiPlatform\Metadata\Operation; use ApiPlatform\Metadata\Post; -use ApiPlatform\State\ProcessorInterface; use DTO\DataTablesLoadRequest\Column; use DTO\DataTablesLoadRequest\DataTablesLoadRequest; use DTO\DataTablesLoadResponse\DataTablesLoadResponse; use Models\Module; use Util\Query; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; + + #[Post( uriTemplate: '/datatables/list/{id_module}/{id_plugin}/{id_parent}', - processor: DataTablesController::class, + controller: DataTablesController::class, input: DataTablesLoadRequest::class, output: DataTablesLoadResponse::class, )] @@ -21,11 +23,34 @@ class DataTablesResource { } -final class DataTablesController implements ProcessorInterface +final class DataTablesController extends BaseController { - public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): DataTablesLoadResponse + public function __invoke(Request $request): JsonResponse { - if (!$data instanceof DataTablesLoadRequest) { + $request_body = $this->_cast($request, DataTablesLoadRequest::class); + + $id_module = (int) $request_body->getIdModule(); + $id_plugin = (int) $request_body->getIdPlugin(); + $id_parent = (int) $request_body->getIdParent(); + + $module = \Modules::get($id_module); + \Modules::setCurrent($id_module); + + $plugin = null; + if (!empty($id_plugin)) { + \Plugins::setCurrent($id_plugin); + $plugin = \Plugins::get($id_plugin); + } + + $structure = $plugin ?? $module; + + return new JsonResponse($this->retrieveRecords($structure, $request_body, $id_module, $id_plugin, $id_parent)); + } + + /* + public function process(mixed $request, Operation $operation, array $uriVariables = [], array $context = []): DataTablesLoadResponse + { + if (!$request instanceof DataTablesLoadRequest) { throw new \InvalidArgumentException(); } @@ -44,21 +69,23 @@ public function process(mixed $data, Operation $operation, array $uriVariables = $structure = $plugin ?? $module; - return $this->retrieveRecords($structure, $data, $id_module, $id_plugin, $id_parent); - } + return $this->retrieveRecords($structure, $request, $id_module, $id_plugin, $id_parent); + }*/ - private function retrieveRecords($structure, DataTablesLoadRequest $data, $id_module, $id_plugin, $id_parent): DataTablesLoadResponse + private function retrieveRecords($structure, DataTablesLoadRequest $request, $id_module, $id_plugin, $id_parent): DataTablesLoadResponse { // Informazioni fondamentali - $order = $data->order ? $data->order[0] : []; + $order = $request->order ? $request->order[0] : []; if (!empty($order)) { - $order['column'] = $order['column'] - 1; + $order->column = $order->column - 1; } + $order_array = $order->toArray(); + $query_structure = Query::readQuery($structure); - $response = new DataTablesLoadResponse($data->draw); + $response = new DataTablesLoadResponse($request->draw); $query = Query::getQuery($structure, [], [], [], $query_structure); if (empty($query)) { @@ -67,7 +94,7 @@ private function retrieveRecords($structure, DataTablesLoadRequest $data, $id_mo // Ricerca $search = []; - $columns = $data->columns; + $columns = $request->columns; array_shift($columns); for ($i = 0; $i < count($columns); ++$i) { $col = Column::fromArray($columns[$i]); @@ -80,7 +107,7 @@ private function retrieveRecords($structure, DataTablesLoadRequest $data, $id_mo $response->recordsTotal = database()->fetchNum($query); // CONTEGGIO RECORD FILTRATI (senza LIMIT) - $query_filtered = Query::getQuery($structure, $search, $order, [], $query_structure); + $query_filtered = Query::getQuery($structure, $search, $order_array, [], $query_structure); if (empty($id_plugin)) { $query_filtered = \Modules::replaceAdditionals($id_module, $query_filtered); } @@ -93,11 +120,11 @@ private function retrieveRecords($structure, DataTablesLoadRequest $data, $id_mo $response->avg = Query::getAverages($structure, $search); $limit = [ - 'start' => $data->start, - 'length' => $data->length, + 'start' => $request->start, + 'length' => $request->length, ]; // RISULTATI VISIBILI (con LIMIT) - $query = Query::getQuery($structure, $search, $order, $limit, $query_structure); + $query = Query::getQuery($structure, $search, $order_array, $limit, $query_structure); // Filtri derivanti dai permessi (eventuali) if (empty($id_plugin)) { @@ -154,7 +181,7 @@ private function getSingleRow($r, $query_structure, $align, $id_module, $id_plug $result = [ 'id' => $r['id'], - '', // Colonna ID + '', // Colonna ID ]; foreach ($query_structure['fields'] as $pos => $field) { @@ -162,9 +189,9 @@ private function getSingleRow($r, $query_structure, $align, $id_module, $id_plug if (!empty($r['_bg_'])) { if (preg_match('/-light$/', (string) $r['_bg_'])) { - $column['data-background'] = substr((string) $r['_bg_'], 0, -6); // Remove the "-light" suffix from the word + $column['request-background'] = substr((string) $r['_bg_'], 0, -6); // Remove the "-light" suffix from the word } else { - $column['data-background'] = $r['_bg_']; + $column['request-background'] = $r['_bg_']; } } @@ -211,7 +238,7 @@ private function getSingleRow($r, $query_structure, $align, $id_module, $id_plug } $column['class'] = 'text-center small'; - $column['data-background'] = $r[$field]; + $column['request-background'] = $r[$field]; } // Icona di stampa @@ -245,8 +272,8 @@ private function getSingleRow($r, $query_structure, $align, $id_module, $id_plug } // Colore del testo - if (!empty($column['data-background'])) { - $column['data-color'] ??= color_inverse(trim((string) $column['data-background'])); + if (!empty($column['request-background'])) { + $column['request-color'] ??= color_inverse(trim((string) $column['request-background'])); } elseif (preg_match('/^mailto_(.+?)$/', trim((string) $field), $m)) { $column['class'] = ''; $value = ($r[$field] ? ' '.$r[$field].'' : ''); @@ -269,13 +296,13 @@ private function getSingleRow($r, $query_structure, $align, $id_module, $id_plug // Link per i moduli if (empty($id_plugin)) { - $column['data-link'] = base_path_osm().'/editor.php?id_module='.$id_module.'&id_record='.$id_record.$hash; + $column['request-link'] = base_path_osm().'/editor.php?id_module='.$id_module.'&id_record='.$id_record.$hash; } // Link per i plugin else { - $column['data-link'] = base_path_osm().'/add.php?id_module='.$id_module.'&id_record='.$id_record.'&id_plugin='.$id_plugin.'&id_parent='.$id_parent.'&edit=1'.$hash; + $column['request-link'] = base_path_osm().'/add.php?id_module='.$id_module.'&id_record='.$id_record.'&id_plugin='.$id_plugin.'&id_parent='.$id_parent.'&edit=1'.$hash; - $column['data-type'] = 'dialog'; + $column['request-type'] = 'dialog'; } } diff --git a/src/DTO/DataTablesLoadRequest/Column.php b/src/DTO/DataTablesLoadRequest/Column.php index 37d6a9113..756e4f419 100644 --- a/src/DTO/DataTablesLoadRequest/Column.php +++ b/src/DTO/DataTablesLoadRequest/Column.php @@ -15,19 +15,6 @@ public function __construct( ) { } - public static function fromArray(array $input = []): self - { - $data = isset($input['data']) ? (string) $input['data'] : ''; - $name = isset($input['name']) ? (string) $input['name'] : null; - $searchable = isset($input['searchable']) ? filter_var($input['searchable'], FILTER_VALIDATE_BOOLEAN) : true; - $orderable = isset($input['orderable']) ? filter_var($input['orderable'], FILTER_VALIDATE_BOOLEAN) : true; - $search = isset($input['search']) && is_array($input['search']) - ? Search::fromArray($input['search']) - : null; - - return new self($data, $name, $searchable, $orderable, $search); - } - public function getData(): string { return $this->data; diff --git a/src/DTO/DataTablesLoadRequest/DataTablesLoadRequest.php b/src/DTO/DataTablesLoadRequest/DataTablesLoadRequest.php index 54dc7a6b2..b67acbe2f 100644 --- a/src/DTO/DataTablesLoadRequest/DataTablesLoadRequest.php +++ b/src/DTO/DataTablesLoadRequest/DataTablesLoadRequest.php @@ -4,25 +4,49 @@ namespace DTO\DataTablesLoadRequest; +use Symfony\Component\Serializer\Attribute\Ignore; + final class DataTablesLoadRequest { + // Private properties are from the route + // We must use Ignore on the getters to prevent them from being serialized + private ?int $id_module = 0; + private ?int $id_plugin = 0; + private ?int $id_parent = 0; + public int $draw = 0; public int $start = 0; public int $length = 200; - /** - * @var Search - */ - public array $search; // Deserialization is not working correctly + + public Search $search; /** * @var OrderItem[] */ - public array $order = []; // Deserialization is not working correctly + public array $order = []; /** * @var Column[] */ - public array $columns = []; // Deserialization is not working correctly + public array $columns = []; public ?string $_ = null; + #[Ignore] + public function getIdModule(): int + { + return $this->id_module; + } + + #[Ignore] + public function getIdPlugin(): int + { + return $this->id_plugin; + } + + #[Ignore] + public function getIdParent(): int + { + return $this->id_parent; + } + public function getDraw(): int { return $this->draw; diff --git a/src/DTO/DataTablesLoadRequest/OrderItem.php b/src/DTO/DataTablesLoadRequest/OrderItem.php index 0556dbfb2..b1546c2c7 100644 --- a/src/DTO/DataTablesLoadRequest/OrderItem.php +++ b/src/DTO/DataTablesLoadRequest/OrderItem.php @@ -14,15 +14,6 @@ public function __construct(public int $column = 0, public ?string $name = null, { } - public static function fromArray(array $input = []): self - { - $col = isset($input['column']) ? (int) $input['column'] : 0; - $name = isset($input['name']) && $input['name'] !== '' ? (string) $input['name'] : null; - $dirStr = isset($input['dir']) ? (string) $input['dir'] : SortDirection::ASC->value; - - return new self($col, $name, SortDirection::from($dirStr)); - } - public function getColumnIndex(): int { return $this->column; diff --git a/src/DTO/DataTablesLoadRequest/Search.php b/src/DTO/DataTablesLoadRequest/Search.php index 4b1cbc603..9e841d4dc 100644 --- a/src/DTO/DataTablesLoadRequest/Search.php +++ b/src/DTO/DataTablesLoadRequest/Search.php @@ -10,14 +10,6 @@ public function __construct(public string $value, public bool $regex = false) { } - public static function fromArray(array $input = []): self - { - $value = isset($input['value']) ? (string) $input['value'] : ''; - $regex = isset($input['regex']) ? filter_var($input['regex'], FILTER_VALIDATE_BOOLEAN) : false; - - return new self($value, $regex); - } - public function getValue(): string { return $this->value; diff --git a/src/DTO/DataTablesLoadResponse/DataTablesLoadResponse.php b/src/DTO/DataTablesLoadResponse/DataTablesLoadResponse.php index 069eb9537..ecf22daf1 100644 --- a/src/DTO/DataTablesLoadResponse/DataTablesLoadResponse.php +++ b/src/DTO/DataTablesLoadResponse/DataTablesLoadResponse.php @@ -31,7 +31,7 @@ public function toArray(): array 'data' => $this->data, 'summable' => $this->summable, 'avg' => $this->avg, - 'error' => $this->error, + $this->error ? ['error' => $this->error] : [], ]; } } From 97f6bfe360ba08766efd8f0c09b830163966ef21 Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Sat, 7 Feb 2026 09:49:10 +0100 Subject: [PATCH 2/4] Update Impostazioni to use controller system --- .../Controllers/GetImpostazioneController.php | 24 ++++++++++++++ .../Controllers/GetImpostazioneProvider.php | 23 ------------- ...der.php => ListImpostazioniController.php} | 20 +++++------ ... => ListSezioniImpostazioniController.php} | 11 ++++--- .../UpdateImpostazioneController.php | 32 ++++++++++++++++++ .../UpdateImpostazioneProcessor.php | 33 ------------------- .../src/API/ImpostazioneResource.php | 17 +++++----- 7 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 modules/impostazioni/src/API/Controllers/GetImpostazioneController.php delete mode 100644 modules/impostazioni/src/API/Controllers/GetImpostazioneProvider.php rename modules/impostazioni/src/API/Controllers/{ListImpostazioniProvider.php => ListImpostazioniController.php} (53%) rename modules/impostazioni/src/API/Controllers/{ListSezioniImpostazioniProvider.php => ListSezioniImpostazioniController.php} (63%) create mode 100644 modules/impostazioni/src/API/Controllers/UpdateImpostazioneController.php delete mode 100644 modules/impostazioni/src/API/Controllers/UpdateImpostazioneProcessor.php diff --git a/modules/impostazioni/src/API/Controllers/GetImpostazioneController.php b/modules/impostazioni/src/API/Controllers/GetImpostazioneController.php new file mode 100644 index 000000000..bcaddaae3 --- /dev/null +++ b/modules/impostazioni/src/API/Controllers/GetImpostazioneController.php @@ -0,0 +1,24 @@ +route('id')); + if (!$setting) { + return null; + } + + $response = ImpostazioneResource::fromModel($setting); + + return new JsonResponse($response); + } +} diff --git a/modules/impostazioni/src/API/Controllers/GetImpostazioneProvider.php b/modules/impostazioni/src/API/Controllers/GetImpostazioneProvider.php deleted file mode 100644 index e37422074..000000000 --- a/modules/impostazioni/src/API/Controllers/GetImpostazioneProvider.php +++ /dev/null @@ -1,23 +0,0 @@ -getParameters()->get('sezione')->getValue(); - $search = $operation->getParameters()->get('ricerca')->getValue(); + $sezione = $request->query('sezione'); + $search = $request->query('ricerca'); // Trova le impostazioni che corrispondono alla ricerca - if (!$search instanceof ParameterNotFound) { + if (!empty($search)) { $impostazioni = Setting::where('nome', 'like', '%'.$search.'%') ->orWhere('sezione', 'like', '%'.$search.'%') ->get(); - } elseif (!$sezione instanceof ParameterNotFound) { + } elseif (!empty($sezione)) { $impostazioni = Setting::where('sezione', $sezione)->get(); } else { $impostazioni = Setting::all(); @@ -31,6 +31,6 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $results[] = ImpostazioneResource::fromModel($impostazione); } - return $results; + return new JsonResponse($results); } } diff --git a/modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniProvider.php b/modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniController.php similarity index 63% rename from modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniProvider.php rename to modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniController.php index cf89b5376..1877a18c3 100644 --- a/modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniProvider.php +++ b/modules/impostazioni/src/API/Controllers/ListSezioniImpostazioniController.php @@ -2,14 +2,15 @@ namespace Modules\Impostazioni\API\Controllers; -use ApiPlatform\Metadata\Operation; -use ApiPlatform\State\ProviderInterface; +use API\Controllers\BaseController; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; use Models\Setting; use Modules\Impostazioni\API\Models\ListSezioniImpostazioniResponse; -final class ListSezioniImpostazioniProvider implements ProviderInterface +final class ListSezioniImpostazioniController extends BaseController { - public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?ListSezioniImpostazioniResponse + public function __invoke(Request $request): JsonResponse { $gruppi = Setting::selectRaw('sezione AS nome, COUNT(id) AS numero') ->groupBy(['sezione']) @@ -23,6 +24,6 @@ public function provide(Operation $operation, array $uriVariables = [], array $c $response->sezioni[$gruppo->nome] = $gruppo->numero; } - return $response; + return new JsonResponse($response); } } diff --git a/modules/impostazioni/src/API/Controllers/UpdateImpostazioneController.php b/modules/impostazioni/src/API/Controllers/UpdateImpostazioneController.php new file mode 100644 index 000000000..d2105d9f0 --- /dev/null +++ b/modules/impostazioni/src/API/Controllers/UpdateImpostazioneController.php @@ -0,0 +1,32 @@ +_cast($request, UpdateImpostazioneRequest::class); + + $id = $request->route('id'); + $response = new UpdateImpostazioneResponse(); + + $impostazione = Setting::find($id); + if (!$impostazione->editable) { + $response->edited = true; + + return new JsonResponse($response); + } + + $response->edited = \Settings::setValue($impostazione->id, $data->valore); + + return new JsonResponse($response); + } +} diff --git a/modules/impostazioni/src/API/Controllers/UpdateImpostazioneProcessor.php b/modules/impostazioni/src/API/Controllers/UpdateImpostazioneProcessor.php deleted file mode 100644 index 0d449b762..000000000 --- a/modules/impostazioni/src/API/Controllers/UpdateImpostazioneProcessor.php +++ /dev/null @@ -1,33 +0,0 @@ -editable) { - $response->edited = true; - - return $response; - } - - $response->edited = \Settings::setValue($impostazione->id, $data->valore); - - return $response; - } -} diff --git a/modules/impostazioni/src/API/ImpostazioneResource.php b/modules/impostazioni/src/API/ImpostazioneResource.php index a52c0826f..6a8116028 100644 --- a/modules/impostazioni/src/API/ImpostazioneResource.php +++ b/modules/impostazioni/src/API/ImpostazioneResource.php @@ -8,10 +8,10 @@ use ApiPlatform\Metadata\Put; use ApiPlatform\Metadata\QueryParameter; use Models\Setting; -use Modules\Impostazioni\API\Controllers\GetImpostazioneProvider; -use Modules\Impostazioni\API\Controllers\ListImpostazioniProvider; -use Modules\Impostazioni\API\Controllers\ListSezioniImpostazioniProvider; -use Modules\Impostazioni\API\Controllers\UpdateImpostazioneProcessor; +use Modules\Impostazioni\API\Controllers\GetImpostazioneController; +use Modules\Impostazioni\API\Controllers\ListImpostazioniController; +use Modules\Impostazioni\API\Controllers\ListSezioniImpostazioniController; +use Modules\Impostazioni\API\Controllers\UpdateImpostazioneController; use Modules\Impostazioni\API\Models\ListSezioniImpostazioniResponse; use Modules\Impostazioni\API\Models\UpdateImpostazioneRequest; use Modules\Impostazioni\API\Models\UpdateImpostazioneResponse; @@ -21,12 +21,12 @@ operations: [ new Get( uriTemplate: '/impostazioni/sezioni', - provider: ListSezioniImpostazioniProvider::class, + controller: ListSezioniImpostazioniController::class, output: ListSezioniImpostazioniResponse::class, ), new GetCollection( uriTemplate: '/impostazioni', - provider: ListImpostazioniProvider::class, + controller: ListImpostazioniController::class, paginationEnabled: false, parameters: [ 'ricerca' => new QueryParameter(property: 'hydra:freetextQuery', required: false), @@ -35,12 +35,11 @@ ), new Get( uriTemplate: '/impostazione/{id}', - provider: GetImpostazioneProvider::class, + controller: GetImpostazioneController::class, ), new Put( uriTemplate: '/impostazione/{id}', - provider: GetImpostazioneProvider::class, - processor: UpdateImpostazioneProcessor::class, + controller: UpdateImpostazioneController::class, input: UpdateImpostazioneRequest::class, output: UpdateImpostazioneResponse::class, ), From ab870efbcdaa07d01a0c555b2cb9789681929c01 Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Sat, 7 Feb 2026 09:50:10 +0100 Subject: [PATCH 3/4] Disable provider/processor auto-discovery --- src/Providers/AppServiceProvider.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Providers/AppServiceProvider.php b/src/Providers/AppServiceProvider.php index cb3a8a48a..02d397b60 100644 --- a/src/Providers/AppServiceProvider.php +++ b/src/Providers/AppServiceProvider.php @@ -39,6 +39,8 @@ public function boot(): void $translator->setLocale($lang, $formatter); } + /* + Disable: we should use controllers for better performance // Register all Providers and Processors from Modules and Plugins foreach (get_declared_classes() as $className) { if (str_contains($className, 'Modules\\') || str_contains($className, 'API\\') || str_contains($className, 'Plugins\\')) { @@ -50,5 +52,6 @@ public function boot(): void } } } + */ } } From 01536bf49fdb1741992755cb860bc5ef97bb34dd Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Sat, 28 Feb 2026 07:35:20 +0100 Subject: [PATCH 4/4] Add support for ApiPlatform home --- package.json | 3 ++- src/Controllers/APIForUIController.php | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8955202bf..855b8fd1b 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,8 @@ "setup-corepack": "npm install -g corepack && corepack enable", "export-openapi": "php artisan api:openapi:export --output=openapi.json", "fix-openapi-js": "node -e \"require('fs').writeFileSync('assets/api/src/main.js', \\\"import * as API from './index';global.window.API = API;\\\");\"", - "update-openapi-client": "npm run-script export-openapi && npx @openapitools/openapi-generator-cli generate -i openapi.json -g javascript -o assets/api --skip-validate-spec && npm run-script fix-openapi-js && npm install --no-save ./assets/api && cd ./assets/api && npx babel src -d dist && cd ../.. && npx browserify ./assets/api/dist/main.js -o ./assets/dist/js/api.js" + "copy-vendor-css-folder": "node -e \"const fs = require('fs'); const sourceFolder = './vendor/api-platform/laravel/public'; const destFolder = './assets/dist/apiplatform'; const copyFolder = (src, dest) => { if (!fs.existsSync(dest)) fs.mkdirSync(dest); fs.readdirSync(src).forEach(file => { const srcFile = path.join(src, file); const destFile = path.join(dest, file); if (fs.statSync(srcFile).isDirectory()) copyFolder(srcFile, destFile); else fs.copyFileSync(srcFile, destFile); }); }; copyFolder(sourceFolder, destFolder);\"", + "update-openapi-client": "npm run copy-vendor-css-folder && npm run-script export-openapi && npx @openapitools/openapi-generator-cli generate -i openapi.json -g javascript -o assets/api --skip-validate-spec && npm run-script fix-openapi-js && npm install --no-save ./assets/api && cd ./assets/api && npx babel src -d dist && cd ../.. && npx browserify ./assets/api/dist/main.js -o ./assets/dist/js/api.js" }, "packageManager": "yarn@4.12.0" } diff --git a/src/Controllers/APIForUIController.php b/src/Controllers/APIForUIController.php index 2942449bf..9b38ec995 100644 --- a/src/Controllers/APIForUIController.php +++ b/src/Controllers/APIForUIController.php @@ -18,7 +18,19 @@ public function __invoke(Request $request, ?string $path = null) $tokens = Auth::user()->getApiTokens(); // Determine actual API path - $url = str_replace('api-for-ui/', '', $request->fullUrl()); + $urlPieces = explode('/', $request->fullUrl()); + $apiForUIIndex = array_search('api-for-ui', $urlPieces); + + if ($apiForUIIndex === false) { // This should never happen due to the route definition + return response()->json(['error' => 'Invalid API path'], 400); + } + + $pathLength = count($urlPieces) - 1 - (int) $apiForUIIndex; + + // Only remove the api-for-ui part and keep the rest of the path + $prefix = implode('/', array_slice($urlPieces, 0, $apiForUIIndex)); + array_splice($urlPieces, $apiForUIIndex, 1); + $url = implode('/', $urlPieces); // Create a new Guzzle client $client = new Client(); @@ -36,7 +48,7 @@ public function __invoke(Request $request, ?string $path = null) $formattedHeaders['X-API-Key'] = $tokens[0]['token']; try { - // Make the GET request + // Make the request $response = $client->request($request->method(), $url, [ 'headers' => $formattedHeaders, 'json' => $request->all(), @@ -44,6 +56,10 @@ public function __invoke(Request $request, ?string $path = null) // Get the body of the response $body = $response->getBody(); + if ($pathLength == 1 && str_ends_with($url, "/api")) { + return str_replace("/vendor/api-platform", str_replace("/public", "", $prefix)."/assets/dist/apiplatform", $body); + } + $data = json_decode($body, true); // Decode JSON to array // Return the response data