<?php
declare(strict_types=1);

// Save as configured-validator.php in a Composer project.
// composer require symfony/validator:7.4.23
// php configured-validator.php request.json
require __DIR__ . '/vendor/autoload.php';

use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Validator\Validation;

final class ConfiguredValue
{
    private const RULES = /* AEN_RULES */;
    public function __construct(public mixed $value) {}

    #[Assert\Callback]
    public function validate(ExecutionContextInterface $context): void
    {
        $value = $this->value;
        if (!self::RULES['required'] && ($value === null || (is_string($value) && trim($value) === ''))) { return; }
        if (is_string($value) && self::RULES['type'] !== 'date') { $value = trim($value); }
        $constraints = new Assert\Sequentially([
/* AEN_CONSTRAINTS */
        ]);
        $context->getValidator()->inContext($context)->atPath('value')->validate($value, $constraints);
    }
}

// Request JSON supplies only the value. It cannot replace the saved rules.
$value = /* AEN_DEMO */;
if (isset($argv[1])) {
    try {
        $raw = file_get_contents($argv[1], false, null, 0, 32769);
        if ($raw === false || strlen($raw) > 32768) { throw new RuntimeException('Invalid file size.'); }
        $input = json_decode($raw, false, 16, JSON_THROW_ON_ERROR);
        if (!$input instanceof stdClass) { throw new RuntimeException('Object required.'); }
        $payload = property_exists($input, 'scenario') ? ($input->data ?? null) : $input;
        if (!$payload instanceof stdClass || !property_exists($payload, 'value')) { throw new RuntimeException('value required.'); }
        $value = $payload->value;
    } catch (Throwable) {
        fwrite(STDERR, "Передайте JSON-объект {\"value\": ...} или запрос {\"scenario\":\"lab\",\"data\":{\"value\":...}} до 32 КБ.\n");
        exit(2);
    }
}
$validator = Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator();
$errors = $validator->validate(new ConfiguredValue($value));
$violations = [];
foreach ($errors as $error) {
    $violations[] = ['path' => $error->getPropertyPath(), 'message' => $error->getMessage(), 'code' => $error->getCode()];
}
echo json_encode(['valid' => count($errors) === 0, 'violations' => $violations], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR), PHP_EOL;
exit(count($errors) === 0 ? 0 : 1);
