validator component

This commit is contained in:
Benjamin Dalsass
2025-12-02 15:03:26 +01:00
parent 3d8e429c2b
commit 8f8a0e2672
8 changed files with 141 additions and 9 deletions

View File

@@ -14,6 +14,8 @@ function triggerTurbo(el) {
el.form.querySelector(`[name="${sFormName}[_turbo_trigger]"]`).value = el.getAttribute('name');
el.form.setAttribute('novalidate', true);
el.form.requestSubmit();
el.form.querySelector(`[name="${sFormName}[_turbo_trigger]"]`).value = null;
el.form.setAttribute('novalidate', false);
$aFormBlockDataTransmittedData[name] = el.value;
}

View File

@@ -534,6 +534,8 @@ return array(
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => $baseDir . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => $baseDir . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => $baseDir . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => $baseDir . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => $baseDir . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => $baseDir . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => $baseDir . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => $baseDir . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
@@ -3343,7 +3345,6 @@ return array(
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => $vendorDir . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => $vendorDir . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => $vendorDir . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase' => $vendorDir . '/symfony/validator/Test/ConstraintValidatorTestCase.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => $vendorDir . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => $vendorDir . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => $vendorDir . '/symfony/validator/ValidatorBuilder.php',
@@ -3893,5 +3894,5 @@ return array(
'privUITransactionFile' => $baseDir . '/application/transaction.class.inc.php',
'privUITransactionSession' => $baseDir . '/application/transaction.class.inc.php',
'utils' => $baseDir . '/application/utils.inc.php',
'©' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
'<EFBFBD>' => $vendorDir . '/symfony/cache/Traits/ValueWrapper.php',
);

View File

@@ -920,6 +920,8 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Forms\\Register\\OptionsRegister' => __DIR__ . '/../..' . '/sources/Forms/Register/OptionsRegister.php',
'Combodo\\iTop\\Forms\\Register\\RegisterException' => __DIR__ . '/../..' . '/sources/Forms/Register/RegisterException.php',
'Combodo\\iTop\\Forms\\Twig\\Extension\\FormCompatibilityExtension' => __DIR__ . '/../..' . '/sources/Forms/Twig/Extension/FormCompatibilityExtension.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExist' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExist.php',
'Combodo\\iTop\\Forms\\Validator\\AttributeExistValidator' => __DIR__ . '/../..' . '/sources/Forms/Validator/AttributeExistValidator.php',
'Combodo\\iTop\\PhpParser\\Evaluation\\PhpExpressionEvaluator' => __DIR__ . '/../..' . '/sources/PhpParser/Evaluation/PhpExpressionEvaluator.php',
'Combodo\\iTop\\Renderer\\BlockRenderer' => __DIR__ . '/../..' . '/sources/Renderer/BlockRenderer.php',
'Combodo\\iTop\\Renderer\\Bootstrap\\BsFieldRendererMappings' => __DIR__ . '/../..' . '/sources/Renderer/Bootstrap/BsFieldRendererMappings.php',
@@ -3729,7 +3731,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Symfony\\Component\\Validator\\Mapping\\PropertyMetadataInterface' => __DIR__ . '/..' . '/symfony/validator/Mapping/PropertyMetadataInterface.php',
'Symfony\\Component\\Validator\\Mapping\\TraversalStrategy' => __DIR__ . '/..' . '/symfony/validator/Mapping/TraversalStrategy.php',
'Symfony\\Component\\Validator\\ObjectInitializerInterface' => __DIR__ . '/..' . '/symfony/validator/ObjectInitializerInterface.php',
'Symfony\\Component\\Validator\\Test\\ConstraintValidatorTestCase' => __DIR__ . '/..' . '/symfony/validator/Test/ConstraintValidatorTestCase.php',
'Symfony\\Component\\Validator\\Util\\PropertyPath' => __DIR__ . '/..' . '/symfony/validator/Util/PropertyPath.php',
'Symfony\\Component\\Validator\\Validation' => __DIR__ . '/..' . '/symfony/validator/Validation.php',
'Symfony\\Component\\Validator\\ValidatorBuilder' => __DIR__ . '/..' . '/symfony/validator/ValidatorBuilder.php',
@@ -4279,7 +4280,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'privUITransactionFile' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'privUITransactionSession' => __DIR__ . '/../..' . '/application/transaction.class.inc.php',
'utils' => __DIR__ . '/../..' . '/application/utils.inc.php',
'©' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
'<EFBFBD>' => __DIR__ . '/..' . '/symfony/cache/Traits/ValueWrapper.php',
);
public static function getInitializer(ClassLoader $loader)

View File

@@ -95,9 +95,12 @@ class FormBuilder implements FormBuilderInterface, IteratorAggregate
$oFormBlock->oDependencyMap = $this->oDependencyHandler->GetMap();
}
if (is_null($oFormBlock->GetParent())) {
if ($oFormBlock->IsRootBlock()) {
// Insert a hidden type to save the place
$this->builder->add('_turbo_trigger', HiddenType::class, ['prevent_form_build' => true]);
$this->builder->add('_turbo_trigger', HiddenType::class, [
'prevent_form_build' => true,
'mapped' => false,
]);
}
}

View File

@@ -38,7 +38,9 @@ final class Forms
public static function createFormFactoryBuilder(): FormFactoryBuilderInterface
{
// Set up the Validator component
$validator = Validation::createValidator();
$validator = Validation::createValidatorBuilder()
->enableAttributeMapping()->getValidator();
return (new FormFactoryBuilder())
->addExtension(new HttpFoundationExtension())
->addExtension(new ValidatorExtension($validator))

View File

@@ -36,8 +36,6 @@ class OqlToClassConverter extends AbstractConverter
$oModelReflection = DIService::GetInstance()->GetService('ModelReflection');
try {
$oQuery = $oModelReflection->GetQuery($oData);
} catch (\OQLParserException $e) {
throw new FormBlockIOException($e->GetIssue(), $e->getCode(), $e);
} catch (Exception $e) {
throw new FormBlockIOException($e->getMessage(), $e->getCode(), $e);
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\Validator;
use Attribute;
use InvalidArgumentException;
use Symfony\Component\Validator\Constraint;
/**
* Attribute exist constraint.
*
* @package Combodo\iTop\Forms\Validator
* @since 3.3.0
*/
#[Attribute]
class AttributeExist extends Constraint
{
/** @var string Violation message */
public string $sMessage = 'The attribute "{{ attribute }}" doesn\'t exist in class "{{ class }}" from OQL "{{ oql }}".';
/** @var string|mixed OQL expression property path */
public string $sOqlPropertyPath;
/** @var string|null Attribute list filter */
public ?string $sFilter;
/**
* Constructor.
*
* @param string|null $sOqlPropertyPath
* @param string|null $sFilter
* @param array $aOptions
* @param array|null $aGroups
* @param mixed|null $oPayload
*/
public function __construct(string $sOqlPropertyPath = null, string $sFilter = null, array $aOptions = [], ?array $aGroups = null, mixed $oPayload = null)
{
if ($sOqlPropertyPath === null) {
throw new InvalidArgumentException('The argument "sOqlPropertyPath" must be set.');
}
// Merge argument into options array
$aOptions = array_merge([
'sOqlPropertyPath' => $sOqlPropertyPath,
], $aOptions);
parent::__construct($aOptions, $aGroups, $oPayload);
// Retrieve options
$this->sFilter = $sFilter;
$this->sOqlPropertyPath = $aOptions['sOqlPropertyPath'];
}
public function getDefaultOption(): string
{
return 'sOqlPropertyPath';
}
public function getRequiredOptions(): array
{
return ['sOqlPropertyPath'];
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* @copyright Copyright (C) 2010-2025 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Forms\Validator;
use Combodo\iTop\Forms\IO\Converter\OqlToClassConverter;
use Combodo\iTop\Service\DependencyInjection\DIService;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Attribute exist validator.
*
* @package Combodo\iTop\Forms\Validator
* @since 3.3.0
*/
class AttributeExistValidator extends ConstraintValidator
{
private ?PropertyAccessorInterface $propertyAccessor;
public function __construct()
{
$this->propertyAccessor = PropertyAccess::createPropertyAccessor();
}
/**
* @inheritDoc
*/
public function validate(mixed $value, Constraint $constraint): void
{
$sOql = $this->propertyAccessor->getValue($this->context->getObject(), $constraint->sOqlPropertyPath);
$oOqlToClassConverter = new OqlToClassConverter();
$sClass = strval($oOqlToClassConverter->Convert($sOql));
$sClass = "UserRequest";
/** List attributes @var ModelReflection $oModelReflection */
$oModelReflection = DIService::GetInstance()->GetService('ModelReflection');
$aAttributeCodes = array_keys($oModelReflection->ListAttributes($sClass));
if (!in_array($value, $aAttributeCodes, true)) {
$this->context->buildViolation($constraint->sMessage)
->setParameter('{{ attribute }}', $value)
->setParameter('{{ class }}', $sClass)
->setParameter('{{ oql }}', $sOql)
->addViolation();
}
}
}