Files
compras/app/Services/CandidateGeography.php
T
nala 63d20b10fc
tests / ci (push) Canceled after 0s
commit de armazens
2026-11-04 09:40:26 +02:00

90 lines
4.9 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
class CandidateGeography
{
/** @param array<string,mixed> $input
* @return array<string,mixed>
*/
public function resolve(array $input): array
{
if (($input['availability_reference'] ?? null) !== null) {
$data = Validator::make($input, ['availability_reference' => 'required|array:country,catalogue,record_id', 'availability_reference.catalogue' => 'required|string|size:64', 'availability_reference.record_id' => 'required|string|regex:/^[0-9]+$/D|max:20'])->validate();
$resolved = $this->locality($data['availability_reference'], 'availability_reference');
$input['availability_reference'] = $resolved['reference'];
$input['availability'] = $resolved['location'];
}
if (array_key_exists('additional_availability_references', $input)) {
$data = Validator::make($input, ['additional_availability' => 'present|array|list|max:20', 'additional_availability.*' => 'array',
'additional_availability_references' => 'present|array|list|max:20', 'additional_availability_references.*' => 'nullable|array:country,catalogue,record_id',
'additional_availability_references.*.catalogue' => 'required_with:additional_availability_references.*|string|size:64',
'additional_availability_references.*.record_id' => 'required_with:additional_availability_references.*|string|regex:/^[0-9]+$/D|max:20'])->validate();
if (count($data['additional_availability']) !== count($data['additional_availability_references'])) {
throw ValidationException::withMessages(['additional_availability_references' => 'Cada local adicional deve ter uma referência correspondente ou vazia.']);
}
foreach ($data['additional_availability_references'] as $index => $reference) {
if ($reference !== null) {
$resolved = $this->locality($reference, 'additional_availability_references.'.$index);
$input['additional_availability'][$index] = $resolved['location'];
$input['additional_availability_references'][$index] = $resolved['reference'];
}
}
}
return $input;
}
/** @param array<string,mixed> $value
* @return array{reference:array<string,mixed>,location:array<string,string>}
*/
private function locality(array $value, string $field): array
{
$geography = app(AdministrativeGeography::class);
try {
$reference = $geography->canonical($value);
} catch (ValidationException $error) {
throw ValidationException::withMessages([$field => array_merge(...array_values($error->errors()))]);
}
abort_unless($reference !== null, 422);
$record = $geography->record($reference['record_id']);
if ($record['level'] !== 4) {
throw ValidationException::withMessages([$field => 'Seleccione um percurso completo até à localidade. Não se presume um distrito ou localidade em falta.']);
}
$description = $geography->describe($reference);
abort_unless($description !== null, 422);
$names = array_column($description['path'], 'name', 'level');
return ['reference' => $reference, 'location' => ['province' => $names[1], 'district' => $names[2], 'locality' => $names[4]]];
}
/** @param array<string,mixed> $data
* @param array<string,mixed> $previous
* @return array<string,mixed>
*/
public function preserve(array $data, array $previous): array
{
if (! array_key_exists('availability_reference', $data) && isset($previous['availability_reference']) && array_map(fn ($key) => $data['availability'][$key], ['province', 'district', 'locality']) === array_map(fn ($key) => $previous['availability'][$key], ['province', 'district', 'locality'])) {
$data['availability_reference'] = $previous['availability_reference'];
}
if (! array_key_exists('additional_availability_references', $data) && array_key_exists('additional_availability_references', $previous)) {
$known = [];
foreach ($previous['additional_availability'] ?? [] as $index => $location) {
$key = json_encode(array_map(fn ($part) => $location[$part], ['province', 'district', 'locality']), JSON_THROW_ON_ERROR);
$known[$key] = $previous['additional_availability_references'][$index] ?? null;
}
$data['additional_availability_references'] = array_map(function ($location) use ($known) {
$key = json_encode(array_map(fn ($part) => $location[$part], ['province', 'district', 'locality']), JSON_THROW_ON_ERROR);
return $known[$key] ?? null;
}, $data['additional_availability']);
}
return $data;
}
}