Files
Investidor-V2/app/Services/OpportunityRealEstateDraft.php
nala 01405cbf8a
tests / ci (push) Canceled after 0s
oportunidades 5
2026-10-10 14:15:28 +02:00

91 lines
3.7 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
/** First draft adapter, not a complete contract validator or a publication gate. */
class OpportunityRealEstateDraft
{
/**
* @param array<string,mixed> $values
* @return array<string,mixed>
*/
public function validate(array $values): array
{
abort_unless(config('portal.opportunity_specialized_drafts_enabled'), 422, 'Campos especializados ainda não disponibilizados neste ambiente.');
$bytes = file_get_contents(resource_path('data/investmoz-opportunity-modular.schema.json'));
if ($bytes === false) {
throw new \RuntimeException('Normative opportunity schema unavailable.');
}
$schema = json_decode($bytes, true, 512, JSON_THROW_ON_ERROR);
$properties = $schema['$defs']['realEstatePatch']['properties'];
if ($values === [] || array_diff(array_keys($values), array_keys($properties))) {
throw ValidationException::withMessages(['real_estate' => 'Indique campos do contrato imobiliário; campos desconhecidos ou de resposta não são graváveis.']);
}
$errors = [];
foreach ($values as $key => $value) {
$this->check($value, $properties[$key], 'real_estate.'.$key, $errors);
}
if ($errors) {
throw ValidationException::withMessages($errors);
}
return $values;
}
/**
* @param array<string,mixed> $schema
* @param array<string,string> $errors
*/
private function check(mixed $value, array $schema, string $path, array &$errors): void
{
$types = (array) ($schema['type'] ?? []);
$valid = $types === [] || array_filter($types, fn ($type) => match ($type) {
'null' => $value === null,
'string' => is_string($value),
'integer' => is_int($value),
'number' => is_int($value) || is_float($value),
'boolean' => is_bool($value),
'array' => is_array($value) && array_is_list($value),
// Laravel request arrays represent JSON objects, including empty ones.
'object' => is_array($value) && ($value === [] || ! array_is_list($value)),
default => false,
}) !== [];
if (! $valid || (isset($schema['enum']) && ! in_array($value, $schema['enum'], true))) {
$errors[$path] = 'Tipo ou valor fora do contrato imobiliário §26.';
return;
}
if ($value === null) {
return;
}
$rules = [];
foreach (['minLength' => 'min', 'maxLength' => 'max', 'minItems' => 'min'] as $keyword => $rule) {
if (isset($schema[$keyword])) {
$rules[] = $rule.':'.$schema[$keyword];
}
}
if (in_array('number', $types, true) || in_array('integer', $types, true)) {
$rules[] = 'numeric';
foreach (['minimum' => 'min', 'maximum' => 'max', 'exclusiveMinimum' => 'gt'] as $keyword => $rule) {
if (isset($schema[$keyword])) {
$rules[] = $rule.':'.$schema[$keyword];
}
}
}
if (($schema['format'] ?? null) === 'uuid') {
$rules[] = 'uuid';
}
if ($rules && Validator::make(['value' => $value], ['value' => $rules])->fails()) {
$errors[$path] = 'Valor fora dos limites/formato do contrato imobiliário §26.';
}
if (isset($schema['items']) && is_array($value)) {
foreach ($value as $index => $item) {
$this->check($item, $schema['items'], $path.'.'.$index, $errors);
}
}
}
}