90 lines
4.9 KiB
PHP
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;
|
|
}
|
|
}
|