$input * @return array */ 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 $value * @return array{reference:array,location:array} */ 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 $data * @param array $previous * @return array */ 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; } }