login consent app sql
This commit is contained in:
36
vendor/symfony/form/Extension/Validator/Constraints/Form.php
vendored
Normal file
36
vendor/symfony/form/Extension/Validator/Constraints/Form.php
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class Form extends Constraint
|
||||
{
|
||||
public const NOT_SYNCHRONIZED_ERROR = '1dafa156-89e1-4736-b832-419c2e501fca';
|
||||
public const NO_SUCH_FIELD_ERROR = '6e5212ed-a197-4339-99aa-5654798a4854';
|
||||
|
||||
protected static $errorNames = [
|
||||
self::NOT_SYNCHRONIZED_ERROR => 'NOT_SYNCHRONIZED_ERROR',
|
||||
self::NO_SUCH_FIELD_ERROR => 'NO_SUCH_FIELD_ERROR',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTargets()
|
||||
{
|
||||
return self::CLASS_CONSTRAINT;
|
||||
}
|
||||
}
|
279
vendor/symfony/form/Extension/Validator/Constraints/FormValidator.php
vendored
Normal file
279
vendor/symfony/form/Extension/Validator/Constraints/FormValidator.php
vendored
Normal file
@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Constraints;
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\Composite;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
use Symfony\Component\Validator\Constraints\Valid;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class FormValidator extends ConstraintValidator
|
||||
{
|
||||
/**
|
||||
* @var \SplObjectStorage<FormInterface, array<int, string|string[]|GroupSequence>>
|
||||
*/
|
||||
private $resolvedGroups;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($form, Constraint $formConstraint)
|
||||
{
|
||||
if (!$formConstraint instanceof Form) {
|
||||
throw new UnexpectedTypeException($formConstraint, Form::class);
|
||||
}
|
||||
|
||||
if (!$form instanceof FormInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* @var FormInterface $form */
|
||||
$config = $form->getConfig();
|
||||
|
||||
$validator = $this->context->getValidator()->inContext($this->context);
|
||||
|
||||
if ($form->isSubmitted() && $form->isSynchronized()) {
|
||||
// Validate the form data only if transformation succeeded
|
||||
$groups = $this->getValidationGroups($form);
|
||||
|
||||
if (!$groups) {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $form->getData();
|
||||
// Validate the data against its own constraints
|
||||
$validateDataGraph = $form->isRoot()
|
||||
&& (\is_object($data) || \is_array($data))
|
||||
&& (($groups && \is_array($groups)) || ($groups instanceof GroupSequence && $groups->groups))
|
||||
;
|
||||
|
||||
// Validate the data against the constraints defined in the form
|
||||
/** @var Constraint[] $constraints */
|
||||
$constraints = $config->getOption('constraints', []);
|
||||
|
||||
$hasChildren = $form->count() > 0;
|
||||
|
||||
if ($hasChildren && $form->isRoot()) {
|
||||
$this->resolvedGroups = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
if ($groups instanceof GroupSequence) {
|
||||
// Validate the data, the form AND nested fields in sequence
|
||||
$violationsCount = $this->context->getViolations()->count();
|
||||
|
||||
foreach ($groups->groups as $group) {
|
||||
if ($validateDataGraph) {
|
||||
$validator->atPath('data')->validate($data, null, $group);
|
||||
}
|
||||
|
||||
if ($groupedConstraints = self::getConstraintsInGroups($constraints, $group)) {
|
||||
$validator->atPath('data')->validate($data, $groupedConstraints, $group);
|
||||
}
|
||||
|
||||
foreach ($form->all() as $field) {
|
||||
if ($field->isSubmitted()) {
|
||||
// remember to validate this field in one group only
|
||||
// otherwise resolving the groups would reuse the same
|
||||
// sequence recursively, thus some fields could fail
|
||||
// in different steps without breaking early enough
|
||||
$this->resolvedGroups[$field] = (array) $group;
|
||||
$fieldFormConstraint = new Form();
|
||||
$fieldFormConstraint->groups = $group;
|
||||
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $fieldFormConstraint, $group);
|
||||
}
|
||||
}
|
||||
|
||||
if ($violationsCount < $this->context->getViolations()->count()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($validateDataGraph) {
|
||||
$validator->atPath('data')->validate($data, null, $groups);
|
||||
}
|
||||
|
||||
$groupedConstraints = [];
|
||||
|
||||
foreach ($constraints as $constraint) {
|
||||
// For the "Valid" constraint, validate the data in all groups
|
||||
if ($constraint instanceof Valid) {
|
||||
if (\is_object($data) || \is_array($data)) {
|
||||
$validator->atPath('data')->validate($data, $constraint, $groups);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise validate a constraint only once for the first
|
||||
// matching group
|
||||
foreach ($groups as $group) {
|
||||
if (\in_array($group, $constraint->groups)) {
|
||||
$groupedConstraints[$group][] = $constraint;
|
||||
|
||||
// Prevent duplicate validation
|
||||
if (!$constraint instanceof Composite) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($groupedConstraints as $group => $constraint) {
|
||||
$validator->atPath('data')->validate($data, $constraint, $group);
|
||||
}
|
||||
|
||||
foreach ($form->all() as $field) {
|
||||
if ($field->isSubmitted()) {
|
||||
$this->resolvedGroups[$field] = $groups;
|
||||
$this->context->setNode($this->context->getValue(), $field, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||
$validator->atPath(sprintf('children[%s]', $field->getName()))->validate($field, $formConstraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasChildren && $form->isRoot()) {
|
||||
// destroy storage to avoid memory leaks
|
||||
$this->resolvedGroups = new \SplObjectStorage();
|
||||
}
|
||||
} elseif (!$form->isSynchronized()) {
|
||||
$childrenSynchronized = true;
|
||||
|
||||
/** @var FormInterface $child */
|
||||
foreach ($form as $child) {
|
||||
if (!$child->isSynchronized()) {
|
||||
$childrenSynchronized = false;
|
||||
$this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath());
|
||||
$validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $formConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the form with an error if it is not synchronized BUT all
|
||||
// of its children are synchronized. If any child is not
|
||||
// synchronized, an error is displayed there already and showing
|
||||
// a second error in its parent form is pointless, or worse, may
|
||||
// lead to duplicate errors if error bubbling is enabled on the
|
||||
// child.
|
||||
// See also https://github.com/symfony/symfony/issues/4359
|
||||
if ($childrenSynchronized) {
|
||||
$clientDataAsString = is_scalar($form->getViewData())
|
||||
? (string) $form->getViewData()
|
||||
: get_debug_type($form->getViewData());
|
||||
|
||||
$failure = $form->getTransformationFailure();
|
||||
|
||||
$this->context->setConstraint($formConstraint);
|
||||
$this->context->buildViolation($failure->getInvalidMessage() ?? $config->getOption('invalid_message'))
|
||||
->setParameters(array_replace(
|
||||
['{{ value }}' => $clientDataAsString],
|
||||
$config->getOption('invalid_message_parameters'),
|
||||
$failure->getInvalidMessageParameters()
|
||||
))
|
||||
->setInvalidValue($form->getViewData())
|
||||
->setCode(Form::NOT_SYNCHRONIZED_ERROR)
|
||||
->setCause($failure)
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the form with an error if it contains extra fields
|
||||
if (!$config->getOption('allow_extra_fields') && \count($form->getExtraData()) > 0) {
|
||||
$this->context->setConstraint($formConstraint);
|
||||
$this->context->buildViolation($config->getOption('extra_fields_message', ''))
|
||||
->setParameter('{{ extra_fields }}', '"'.implode('", "', array_keys($form->getExtraData())).'"')
|
||||
->setPlural(\count($form->getExtraData()))
|
||||
->setInvalidValue($form->getExtraData())
|
||||
->setCode(Form::NO_SUCH_FIELD_ERROR)
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the validation groups of the given form.
|
||||
*
|
||||
* @return string|GroupSequence|array<string|GroupSequence>
|
||||
*/
|
||||
private function getValidationGroups(FormInterface $form)
|
||||
{
|
||||
// Determine the clicked button of the complete form tree
|
||||
$clickedButton = null;
|
||||
|
||||
if (method_exists($form, 'getClickedButton')) {
|
||||
$clickedButton = $form->getClickedButton();
|
||||
}
|
||||
|
||||
if (null !== $clickedButton) {
|
||||
$groups = $clickedButton->getConfig()->getOption('validation_groups');
|
||||
|
||||
if (null !== $groups) {
|
||||
return self::resolveValidationGroups($groups, $form);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
$groups = $form->getConfig()->getOption('validation_groups');
|
||||
|
||||
if (null !== $groups) {
|
||||
return self::resolveValidationGroups($groups, $form);
|
||||
}
|
||||
|
||||
if (isset($this->resolvedGroups[$form])) {
|
||||
return $this->resolvedGroups[$form];
|
||||
}
|
||||
|
||||
$form = $form->getParent();
|
||||
} while (null !== $form);
|
||||
|
||||
return [Constraint::DEFAULT_GROUP];
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-processes the validation groups option for a given form.
|
||||
*
|
||||
* @param string|GroupSequence|array<string|GroupSequence>|callable $groups The validation groups
|
||||
*
|
||||
* @return GroupSequence|array<string|GroupSequence>
|
||||
*/
|
||||
private static function resolveValidationGroups($groups, FormInterface $form)
|
||||
{
|
||||
if (!\is_string($groups) && \is_callable($groups)) {
|
||||
$groups = $groups($form);
|
||||
}
|
||||
|
||||
if ($groups instanceof GroupSequence) {
|
||||
return $groups;
|
||||
}
|
||||
|
||||
return (array) $groups;
|
||||
}
|
||||
|
||||
private static function getConstraintsInGroups($constraints, $group)
|
||||
{
|
||||
$groups = (array) $group;
|
||||
|
||||
return array_filter($constraints, static function (Constraint $constraint) use ($groups) {
|
||||
foreach ($groups as $group) {
|
||||
if (\in_array($group, $constraint->groups, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
59
vendor/symfony/form/Extension/Validator/EventListener/ValidationListener.php
vendored
Normal file
59
vendor/symfony/form/Extension/Validator/EventListener/ValidationListener.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
|
||||
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ValidationListener implements EventSubscriberInterface
|
||||
{
|
||||
private $validator;
|
||||
|
||||
private $violationMapper;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [FormEvents::POST_SUBMIT => 'validateForm'];
|
||||
}
|
||||
|
||||
public function __construct(ValidatorInterface $validator, ViolationMapperInterface $violationMapper)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->violationMapper = $violationMapper;
|
||||
}
|
||||
|
||||
public function validateForm(FormEvent $event)
|
||||
{
|
||||
$form = $event->getForm();
|
||||
|
||||
if ($form->isRoot()) {
|
||||
// Form groups are validated internally (FormValidator). Here we don't set groups as they are retrieved into the validator.
|
||||
foreach ($this->validator->validate($form) as $violation) {
|
||||
// Allow the "invalid" constraint to be put onto
|
||||
// non-synchronized forms
|
||||
$allowNonSynchronized = $violation->getConstraint() instanceof Form && Form::NOT_SYNCHRONIZED_ERROR === $violation->getCode();
|
||||
|
||||
$this->violationMapper->mapViolation($violation, $form, $allowNonSynchronized);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
59
vendor/symfony/form/Extension/Validator/Type/BaseValidatorExtension.php
vendored
Normal file
59
vendor/symfony/form/Extension/Validator/Type/BaseValidatorExtension.php
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\GroupSequence;
|
||||
|
||||
/**
|
||||
* Encapsulates common logic of {@link FormTypeValidatorExtension} and
|
||||
* {@link SubmitTypeValidatorExtension}.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
abstract class BaseValidatorExtension extends AbstractTypeExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
// Make sure that validation groups end up as null, closure or array
|
||||
$validationGroupsNormalizer = function (Options $options, $groups) {
|
||||
if (false === $groups) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (empty($groups)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (\is_callable($groups)) {
|
||||
return $groups;
|
||||
}
|
||||
|
||||
if ($groups instanceof GroupSequence) {
|
||||
return $groups;
|
||||
}
|
||||
|
||||
return (array) $groups;
|
||||
};
|
||||
|
||||
$resolver->setDefaults([
|
||||
'validation_groups' => null,
|
||||
]);
|
||||
|
||||
$resolver->setNormalizer('validation_groups', $validationGroupsNormalizer);
|
||||
}
|
||||
}
|
90
vendor/symfony/form/Extension/Validator/Type/FormTypeValidatorExtension.php
vendored
Normal file
90
vendor/symfony/form/Extension/Validator/Type/FormTypeValidatorExtension.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Type;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener;
|
||||
use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormRendererInterface;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class FormTypeValidatorExtension extends BaseValidatorExtension
|
||||
{
|
||||
private $validator;
|
||||
private $violationMapper;
|
||||
private $legacyErrorMessages;
|
||||
|
||||
public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->violationMapper = new ViolationMapper($formRenderer, $translator);
|
||||
$this->legacyErrorMessages = $legacyErrorMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->addEventSubscriber(new ValidationListener($this->validator, $this->violationMapper));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
parent::configureOptions($resolver);
|
||||
|
||||
// Constraint should always be converted to an array
|
||||
$constraintsNormalizer = function (Options $options, $constraints) {
|
||||
return \is_object($constraints) ? [$constraints] : (array) $constraints;
|
||||
};
|
||||
|
||||
$resolver->setDefaults([
|
||||
'error_mapping' => [],
|
||||
'constraints' => [],
|
||||
'invalid_message' => 'This value is not valid.',
|
||||
'invalid_message_parameters' => [],
|
||||
'legacy_error_messages' => $this->legacyErrorMessages,
|
||||
'allow_extra_fields' => false,
|
||||
'extra_fields_message' => 'This form should not contain extra fields.',
|
||||
]);
|
||||
$resolver->setAllowedTypes('constraints', [Constraint::class, Constraint::class.'[]']);
|
||||
$resolver->setAllowedTypes('legacy_error_messages', 'bool');
|
||||
$resolver->setDeprecated('legacy_error_messages', 'symfony/form', '5.2', function (Options $options, $value) {
|
||||
if (true === $value) {
|
||||
return 'Setting the "legacy_error_messages" option to "true" is deprecated. It will be disabled in Symfony 6.0.';
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
|
||||
$resolver->setNormalizer('constraints', $constraintsNormalizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getExtendedTypes(): iterable
|
||||
{
|
||||
return [FormType::class];
|
||||
}
|
||||
}
|
46
vendor/symfony/form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
vendored
Normal file
46
vendor/symfony/form/Extension/Validator/Type/RepeatedTypeValidatorExtension.php
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RepeatedTypeValidatorExtension extends AbstractTypeExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
// Map errors to the first field
|
||||
$errorMapping = function (Options $options) {
|
||||
return ['.' => $options['first_name']];
|
||||
};
|
||||
|
||||
$resolver->setDefaults([
|
||||
'error_mapping' => $errorMapping,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getExtendedTypes(): iterable
|
||||
{
|
||||
return [RepeatedType::class];
|
||||
}
|
||||
}
|
28
vendor/symfony/form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
vendored
Normal file
28
vendor/symfony/form/Extension/Validator/Type/SubmitTypeValidatorExtension.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Type;
|
||||
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class SubmitTypeValidatorExtension extends BaseValidatorExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getExtendedTypes(): iterable
|
||||
{
|
||||
return [SubmitType::class];
|
||||
}
|
||||
}
|
56
vendor/symfony/form/Extension/Validator/Type/UploadValidatorExtension.php
vendored
Normal file
56
vendor/symfony/form/Extension/Validator/Type/UploadValidatorExtension.php
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
|
||||
* @author David Badura <d.a.badura@gmail.com>
|
||||
*/
|
||||
class UploadValidatorExtension extends AbstractTypeExtension
|
||||
{
|
||||
private $translator;
|
||||
private $translationDomain;
|
||||
|
||||
public function __construct(TranslatorInterface $translator, string $translationDomain = null)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
$this->translationDomain = $translationDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$translator = $this->translator;
|
||||
$translationDomain = $this->translationDomain;
|
||||
$resolver->setNormalizer('upload_max_size_message', function (Options $options, $message) use ($translator, $translationDomain) {
|
||||
return function () use ($translator, $translationDomain, $message) {
|
||||
return $translator->trans($message(), [], $translationDomain);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getExtendedTypes(): iterable
|
||||
{
|
||||
return [FormType::class];
|
||||
}
|
||||
}
|
25
vendor/symfony/form/Extension/Validator/Util/ServerParams.php
vendored
Normal file
25
vendor/symfony/form/Extension/Validator/Util/ServerParams.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\Util;
|
||||
|
||||
use Symfony\Component\Form\Util\ServerParams as BaseServerParams;
|
||||
|
||||
trigger_deprecation('symfony/form', '5.1', 'The "%s" class is deprecated. Use "%s" instead.', ServerParams::class, BaseServerParams::class);
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @deprecated since Symfony 5.1. Use {@see BaseServerParams} instead.
|
||||
*/
|
||||
class ServerParams extends BaseServerParams
|
||||
{
|
||||
}
|
67
vendor/symfony/form/Extension/Validator/ValidatorExtension.php
vendored
Normal file
67
vendor/symfony/form/Extension/Validator/ValidatorExtension.php
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator;
|
||||
|
||||
use Symfony\Component\Form\AbstractExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\Constraints\Form;
|
||||
use Symfony\Component\Form\FormRendererInterface;
|
||||
use Symfony\Component\Validator\Constraints\Traverse;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadata;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Extension supporting the Symfony Validator component in forms.
|
||||
*
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ValidatorExtension extends AbstractExtension
|
||||
{
|
||||
private $validator;
|
||||
private $formRenderer;
|
||||
private $translator;
|
||||
private $legacyErrorMessages;
|
||||
|
||||
public function __construct(ValidatorInterface $validator, bool $legacyErrorMessages = true, FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
|
||||
{
|
||||
$this->legacyErrorMessages = $legacyErrorMessages;
|
||||
|
||||
$metadata = $validator->getMetadataFor('Symfony\Component\Form\Form');
|
||||
|
||||
// Register the form constraints in the validator programmatically.
|
||||
// This functionality is required when using the Form component without
|
||||
// the DIC, where the XML file is loaded automatically. Thus the following
|
||||
// code must be kept synchronized with validation.xml
|
||||
|
||||
/* @var $metadata ClassMetadata */
|
||||
$metadata->addConstraint(new Form());
|
||||
$metadata->addConstraint(new Traverse(false));
|
||||
|
||||
$this->validator = $validator;
|
||||
$this->formRenderer = $formRenderer;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
public function loadTypeGuesser()
|
||||
{
|
||||
return new ValidatorTypeGuesser($this->validator);
|
||||
}
|
||||
|
||||
protected function loadTypeExtensions()
|
||||
{
|
||||
return [
|
||||
new Type\FormTypeValidatorExtension($this->validator, $this->legacyErrorMessages, $this->formRenderer, $this->translator),
|
||||
new Type\RepeatedTypeValidatorExtension(),
|
||||
new Type\SubmitTypeValidatorExtension(),
|
||||
];
|
||||
}
|
||||
}
|
283
vendor/symfony/form/Extension/Validator/ValidatorTypeGuesser.php
vendored
Normal file
283
vendor/symfony/form/Extension/Validator/ValidatorTypeGuesser.php
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator;
|
||||
|
||||
use Symfony\Component\Form\FormTypeGuesserInterface;
|
||||
use Symfony\Component\Form\Guess\Guess;
|
||||
use Symfony\Component\Form\Guess\TypeGuess;
|
||||
use Symfony\Component\Form\Guess\ValueGuess;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
|
||||
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
|
||||
|
||||
class ValidatorTypeGuesser implements FormTypeGuesserInterface
|
||||
{
|
||||
private $metadataFactory;
|
||||
|
||||
public function __construct(MetadataFactoryInterface $metadataFactory)
|
||||
{
|
||||
$this->metadataFactory = $metadataFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function guessType(string $class, string $property)
|
||||
{
|
||||
return $this->guess($class, $property, function (Constraint $constraint) {
|
||||
return $this->guessTypeForConstraint($constraint);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function guessRequired(string $class, string $property)
|
||||
{
|
||||
return $this->guess($class, $property, function (Constraint $constraint) {
|
||||
return $this->guessRequiredForConstraint($constraint);
|
||||
// If we don't find any constraint telling otherwise, we can assume
|
||||
// that a field is not required (with LOW_CONFIDENCE)
|
||||
}, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function guessMaxLength(string $class, string $property)
|
||||
{
|
||||
return $this->guess($class, $property, function (Constraint $constraint) {
|
||||
return $this->guessMaxLengthForConstraint($constraint);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function guessPattern(string $class, string $property)
|
||||
{
|
||||
return $this->guess($class, $property, function (Constraint $constraint) {
|
||||
return $this->guessPatternForConstraint($constraint);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a field class name for a given constraint.
|
||||
*
|
||||
* @return TypeGuess|null
|
||||
*/
|
||||
public function guessTypeForConstraint(Constraint $constraint)
|
||||
{
|
||||
switch (\get_class($constraint)) {
|
||||
case 'Symfony\Component\Validator\Constraints\Type':
|
||||
switch ($constraint->type) {
|
||||
case 'array':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
case 'boolean':
|
||||
case 'bool':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case 'double':
|
||||
case 'float':
|
||||
case 'numeric':
|
||||
case 'real':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case 'integer':
|
||||
case 'int':
|
||||
case 'long':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case \DateTime::class:
|
||||
case '\DateTime':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case 'string':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Country':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CountryType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Currency':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CurrencyType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Date':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', ['input' => 'string'], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\DateTime':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateTimeType', ['input' => 'string'], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Email':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\EmailType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\File':
|
||||
case 'Symfony\Component\Validator\Constraints\Image':
|
||||
$options = [];
|
||||
if ($constraint->mimeTypes) {
|
||||
$options = ['attr' => ['accept' => implode(',', (array) $constraint->mimeTypes)]];
|
||||
}
|
||||
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\FileType', $options, Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Language':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\LanguageType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Locale':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\LocaleType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Time':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'string'], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Url':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\UrlType', [], Guess::HIGH_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Ip':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Length':
|
||||
case 'Symfony\Component\Validator\Constraints\Regex':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TextType', [], Guess::LOW_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Range':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::LOW_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Count':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::LOW_CONFIDENCE);
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\IsTrue':
|
||||
case 'Symfony\Component\Validator\Constraints\IsFalse':
|
||||
return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CheckboxType', [], Guess::MEDIUM_CONFIDENCE);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses whether a field is required based on the given constraint.
|
||||
*
|
||||
* @return ValueGuess|null
|
||||
*/
|
||||
public function guessRequiredForConstraint(Constraint $constraint)
|
||||
{
|
||||
switch (\get_class($constraint)) {
|
||||
case 'Symfony\Component\Validator\Constraints\NotNull':
|
||||
case 'Symfony\Component\Validator\Constraints\NotBlank':
|
||||
case 'Symfony\Component\Validator\Constraints\IsTrue':
|
||||
return new ValueGuess(true, Guess::HIGH_CONFIDENCE);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a field's maximum length based on the given constraint.
|
||||
*
|
||||
* @return ValueGuess|null
|
||||
*/
|
||||
public function guessMaxLengthForConstraint(Constraint $constraint)
|
||||
{
|
||||
switch (\get_class($constraint)) {
|
||||
case 'Symfony\Component\Validator\Constraints\Length':
|
||||
if (is_numeric($constraint->max)) {
|
||||
return new ValueGuess($constraint->max, Guess::HIGH_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Type':
|
||||
if (\in_array($constraint->type, ['double', 'float', 'numeric', 'real'])) {
|
||||
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Range':
|
||||
if (is_numeric($constraint->max)) {
|
||||
return new ValueGuess(\strlen((string) $constraint->max), Guess::LOW_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guesses a field's pattern based on the given constraint.
|
||||
*
|
||||
* @return ValueGuess|null
|
||||
*/
|
||||
public function guessPatternForConstraint(Constraint $constraint)
|
||||
{
|
||||
switch (\get_class($constraint)) {
|
||||
case 'Symfony\Component\Validator\Constraints\Length':
|
||||
if (is_numeric($constraint->min)) {
|
||||
return new ValueGuess(sprintf('.{%s,}', (string) $constraint->min), Guess::LOW_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Regex':
|
||||
$htmlPattern = $constraint->getHtmlPattern();
|
||||
|
||||
if (null !== $htmlPattern) {
|
||||
return new ValueGuess($htmlPattern, Guess::HIGH_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Range':
|
||||
if (is_numeric($constraint->min)) {
|
||||
return new ValueGuess(sprintf('.{%s,}', \strlen((string) $constraint->min)), Guess::LOW_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Symfony\Component\Validator\Constraints\Type':
|
||||
if (\in_array($constraint->type, ['double', 'float', 'numeric', 'real'])) {
|
||||
return new ValueGuess(null, Guess::MEDIUM_CONFIDENCE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the constraints of a property, executes a constraints on
|
||||
* them and returns the best guess.
|
||||
*
|
||||
* @param \Closure $closure The closure that returns a guess
|
||||
* for a given constraint
|
||||
* @param mixed $defaultValue The default value assumed if no other value
|
||||
* can be guessed
|
||||
*
|
||||
* @return Guess|null
|
||||
*/
|
||||
protected function guess(string $class, string $property, \Closure $closure, $defaultValue = null)
|
||||
{
|
||||
$guesses = [];
|
||||
$classMetadata = $this->metadataFactory->getMetadataFor($class);
|
||||
|
||||
if ($classMetadata instanceof ClassMetadataInterface && $classMetadata->hasPropertyMetadata($property)) {
|
||||
foreach ($classMetadata->getPropertyMetadata($property) as $memberMetadata) {
|
||||
foreach ($memberMetadata->getConstraints() as $constraint) {
|
||||
if ($guess = $closure($constraint)) {
|
||||
$guesses[] = $guess;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $defaultValue) {
|
||||
$guesses[] = new ValueGuess($defaultValue, Guess::LOW_CONFIDENCE);
|
||||
}
|
||||
|
||||
return Guess::getBestGuess($guesses);
|
||||
}
|
||||
}
|
87
vendor/symfony/form/Extension/Validator/ViolationMapper/MappingRule.php
vendored
Normal file
87
vendor/symfony/form/Extension/Validator/ViolationMapper/MappingRule.php
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\Exception\ErrorMappingException;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class MappingRule
|
||||
{
|
||||
private $origin;
|
||||
private $propertyPath;
|
||||
private $targetPath;
|
||||
|
||||
public function __construct(FormInterface $origin, string $propertyPath, string $targetPath)
|
||||
{
|
||||
$this->origin = $origin;
|
||||
$this->propertyPath = $propertyPath;
|
||||
$this->targetPath = $targetPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FormInterface
|
||||
*/
|
||||
public function getOrigin()
|
||||
{
|
||||
return $this->origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a property path against the rule path.
|
||||
*
|
||||
* If the rule matches, the form mapped by the rule is returned.
|
||||
* Otherwise this method returns false.
|
||||
*
|
||||
* @return FormInterface|null
|
||||
*/
|
||||
public function match(string $propertyPath)
|
||||
{
|
||||
return $propertyPath === $this->propertyPath ? $this->getTarget() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a property path against a prefix of the rule path.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrefix(string $propertyPath)
|
||||
{
|
||||
$length = \strlen($propertyPath);
|
||||
$prefix = substr($this->propertyPath, 0, $length);
|
||||
$next = $this->propertyPath[$length] ?? null;
|
||||
|
||||
return $prefix === $propertyPath && ('[' === $next || '.' === $next);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FormInterface
|
||||
*
|
||||
* @throws ErrorMappingException
|
||||
*/
|
||||
public function getTarget()
|
||||
{
|
||||
$childNames = explode('.', $this->targetPath);
|
||||
$target = $this->origin;
|
||||
|
||||
foreach ($childNames as $childName) {
|
||||
if (!$target->has($childName)) {
|
||||
throw new ErrorMappingException(sprintf('The child "%s" of "%s" mapped by the rule "%s" in "%s" does not exist.', $childName, $target->getName(), $this->targetPath, $this->origin->getName()));
|
||||
}
|
||||
$target = $target->get($childName);
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
}
|
38
vendor/symfony/form/Extension/Validator/ViolationMapper/RelativePath.php
vendored
Normal file
38
vendor/symfony/form/Extension/Validator/ViolationMapper/RelativePath.php
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class RelativePath extends PropertyPath
|
||||
{
|
||||
private $root;
|
||||
|
||||
public function __construct(FormInterface $root, string $propertyPath)
|
||||
{
|
||||
parent::__construct($propertyPath);
|
||||
|
||||
$this->root = $root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FormInterface
|
||||
*/
|
||||
public function getRoot()
|
||||
{
|
||||
return $this->root;
|
||||
}
|
||||
}
|
343
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationMapper.php
vendored
Normal file
343
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationMapper.php
vendored
Normal file
@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\FileUploadError;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormRendererInterface;
|
||||
use Symfony\Component\Form\Util\InheritDataAwareIterator;
|
||||
use Symfony\Component\PropertyAccess\PropertyPathBuilder;
|
||||
use Symfony\Component\PropertyAccess\PropertyPathIterator;
|
||||
use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ViolationMapper implements ViolationMapperInterface
|
||||
{
|
||||
private $formRenderer;
|
||||
private $translator;
|
||||
private $allowNonSynchronized = false;
|
||||
|
||||
public function __construct(FormRendererInterface $formRenderer = null, TranslatorInterface $translator = null)
|
||||
{
|
||||
$this->formRenderer = $formRenderer;
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false)
|
||||
{
|
||||
$this->allowNonSynchronized = $allowNonSynchronized;
|
||||
|
||||
// The scope is the currently found most specific form that
|
||||
// an error should be mapped to. After setting the scope, the
|
||||
// mapper will try to continue to find more specific matches in
|
||||
// the children of scope. If it cannot, the error will be
|
||||
// mapped to this scope.
|
||||
$scope = null;
|
||||
|
||||
$violationPath = null;
|
||||
$relativePath = null;
|
||||
$match = false;
|
||||
|
||||
// Don't create a ViolationPath instance for empty property paths
|
||||
if ('' !== $violation->getPropertyPath()) {
|
||||
$violationPath = new ViolationPath($violation->getPropertyPath());
|
||||
$relativePath = $this->reconstructPath($violationPath, $form);
|
||||
}
|
||||
|
||||
// This case happens if the violation path is empty and thus
|
||||
// the violation should be mapped to the root form
|
||||
if (null === $violationPath) {
|
||||
$scope = $form;
|
||||
}
|
||||
|
||||
// In general, mapping happens from the root form to the leaf forms
|
||||
// First, the rules of the root form are applied to determine
|
||||
// the subsequent descendant. The rules of this descendant are then
|
||||
// applied to find the next and so on, until we have found the
|
||||
// most specific form that matches the violation.
|
||||
|
||||
// If any of the forms found in this process is not synchronized,
|
||||
// mapping is aborted. Non-synchronized forms could not reverse
|
||||
// transform the value entered by the user, thus any further violations
|
||||
// caused by the (invalid) reverse transformed value should be
|
||||
// ignored.
|
||||
|
||||
if (null !== $relativePath) {
|
||||
// Set the scope to the root of the relative path
|
||||
// This root will usually be $form. If the path contains
|
||||
// an unmapped form though, the last unmapped form found
|
||||
// will be the root of the path.
|
||||
$scope = $relativePath->getRoot();
|
||||
$it = new PropertyPathIterator($relativePath);
|
||||
|
||||
while ($this->acceptsErrors($scope) && null !== ($child = $this->matchChild($scope, $it))) {
|
||||
$scope = $child;
|
||||
$it->next();
|
||||
$match = true;
|
||||
}
|
||||
}
|
||||
|
||||
// This case happens if an error happened in the data under a
|
||||
// form inheriting its parent data that does not match any of the
|
||||
// children of that form.
|
||||
if (null !== $violationPath && !$match) {
|
||||
// If we could not map the error to anything more specific
|
||||
// than the root element, map it to the innermost directly
|
||||
// mapped form of the violation path
|
||||
// e.g. "children[foo].children[bar].data.baz"
|
||||
// Here the innermost directly mapped child is "bar"
|
||||
|
||||
$scope = $form;
|
||||
$it = new ViolationPathIterator($violationPath);
|
||||
|
||||
// Note: acceptsErrors() will always return true for forms inheriting
|
||||
// their parent data, because these forms can never be non-synchronized
|
||||
// (they don't do any data transformation on their own)
|
||||
while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) {
|
||||
if (!$scope->has($it->current())) {
|
||||
// Break if we find a reference to a non-existing child
|
||||
break;
|
||||
}
|
||||
|
||||
$scope = $scope->get($it->current());
|
||||
$it->next();
|
||||
}
|
||||
}
|
||||
|
||||
// Follow dot rules until we have the final target
|
||||
$mapping = $scope->getConfig()->getOption('error_mapping');
|
||||
|
||||
while ($this->acceptsErrors($scope) && isset($mapping['.'])) {
|
||||
$dotRule = new MappingRule($scope, '.', $mapping['.']);
|
||||
$scope = $dotRule->getTarget();
|
||||
$mapping = $scope->getConfig()->getOption('error_mapping');
|
||||
}
|
||||
|
||||
// Only add the error if the form is synchronized
|
||||
if ($this->acceptsErrors($scope)) {
|
||||
if ($violation->getConstraint() instanceof File && (string) \UPLOAD_ERR_INI_SIZE === $violation->getCode()) {
|
||||
$errorsTarget = $scope;
|
||||
|
||||
while (null !== $errorsTarget->getParent() && $errorsTarget->getConfig()->getErrorBubbling()) {
|
||||
$errorsTarget = $errorsTarget->getParent();
|
||||
}
|
||||
|
||||
$errors = $errorsTarget->getErrors();
|
||||
$errorsTarget->clearErrors();
|
||||
|
||||
foreach ($errors as $error) {
|
||||
if (!$error instanceof FileUploadError) {
|
||||
$errorsTarget->addError($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$message = $violation->getMessage();
|
||||
$messageTemplate = $violation->getMessageTemplate();
|
||||
|
||||
if (false !== strpos($message, '{{ label }}') || false !== strpos($messageTemplate, '{{ label }}')) {
|
||||
$form = $scope;
|
||||
|
||||
do {
|
||||
$labelFormat = $form->getConfig()->getOption('label_format');
|
||||
} while (null === $labelFormat && null !== $form = $form->getParent());
|
||||
|
||||
if (null !== $labelFormat) {
|
||||
$label = str_replace(
|
||||
[
|
||||
'%name%',
|
||||
'%id%',
|
||||
],
|
||||
[
|
||||
$scope->getName(),
|
||||
(string) $scope->getPropertyPath(),
|
||||
],
|
||||
$labelFormat
|
||||
);
|
||||
} else {
|
||||
$label = $scope->getConfig()->getOption('label');
|
||||
}
|
||||
|
||||
if (false !== $label) {
|
||||
if (null === $label && null !== $this->formRenderer) {
|
||||
$label = $this->formRenderer->humanize($scope->getName());
|
||||
} elseif (null === $label) {
|
||||
$label = $scope->getName();
|
||||
}
|
||||
|
||||
if (null !== $this->translator) {
|
||||
$form = $scope;
|
||||
$translationParameters[] = $form->getConfig()->getOption('label_translation_parameters', []);
|
||||
|
||||
do {
|
||||
$translationDomain = $form->getConfig()->getOption('translation_domain');
|
||||
array_unshift(
|
||||
$translationParameters,
|
||||
$form->getConfig()->getOption('label_translation_parameters', [])
|
||||
);
|
||||
} while (null === $translationDomain && null !== $form = $form->getParent());
|
||||
|
||||
$translationParameters = array_merge([], ...$translationParameters);
|
||||
|
||||
$label = $this->translator->trans(
|
||||
$label,
|
||||
$translationParameters,
|
||||
$translationDomain
|
||||
);
|
||||
}
|
||||
|
||||
$message = str_replace('{{ label }}', $label, $message);
|
||||
$messageTemplate = str_replace('{{ label }}', $label, $messageTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
$scope->addError(new FormError(
|
||||
$message,
|
||||
$messageTemplate,
|
||||
$violation->getParameters(),
|
||||
$violation->getPlural(),
|
||||
$violation
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to match the beginning of the property path at the
|
||||
* current position against the children of the scope.
|
||||
*
|
||||
* If a matching child is found, it is returned. Otherwise
|
||||
* null is returned.
|
||||
*/
|
||||
private function matchChild(FormInterface $form, PropertyPathIteratorInterface $it): ?FormInterface
|
||||
{
|
||||
$target = null;
|
||||
$chunk = '';
|
||||
$foundAtIndex = null;
|
||||
|
||||
// Construct mapping rules for the given form
|
||||
$rules = [];
|
||||
|
||||
foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) {
|
||||
// Dot rules are considered at the very end
|
||||
if ('.' !== $propertyPath) {
|
||||
$rules[] = new MappingRule($form, $propertyPath, $targetPath);
|
||||
}
|
||||
}
|
||||
|
||||
$children = iterator_to_array(new \RecursiveIteratorIterator(new InheritDataAwareIterator($form)), false);
|
||||
|
||||
while ($it->valid()) {
|
||||
if ($it->isIndex()) {
|
||||
$chunk .= '['.$it->current().']';
|
||||
} else {
|
||||
$chunk .= ('' === $chunk ? '' : '.').$it->current();
|
||||
}
|
||||
|
||||
// Test mapping rules as long as we have any
|
||||
foreach ($rules as $key => $rule) {
|
||||
/* @var MappingRule $rule */
|
||||
|
||||
// Mapping rule matches completely, terminate.
|
||||
if (null !== ($form = $rule->match($chunk))) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
// Keep only rules that have $chunk as prefix
|
||||
if (!$rule->isPrefix($chunk)) {
|
||||
unset($rules[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var FormInterface $child */
|
||||
foreach ($children as $i => $child) {
|
||||
$childPath = (string) $child->getPropertyPath();
|
||||
if ($childPath === $chunk) {
|
||||
$target = $child;
|
||||
$foundAtIndex = $it->key();
|
||||
} elseif (str_starts_with($childPath, $chunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unset($children[$i]);
|
||||
}
|
||||
|
||||
$it->next();
|
||||
}
|
||||
|
||||
if (null !== $foundAtIndex) {
|
||||
$it->seek($foundAtIndex);
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs a property path from a violation path and a form tree.
|
||||
*/
|
||||
private function reconstructPath(ViolationPath $violationPath, FormInterface $origin): ?RelativePath
|
||||
{
|
||||
$propertyPathBuilder = new PropertyPathBuilder($violationPath);
|
||||
$it = $violationPath->getIterator();
|
||||
$scope = $origin;
|
||||
|
||||
// Remember the current index in the builder
|
||||
$i = 0;
|
||||
|
||||
// Expand elements that map to a form (like "children[address]")
|
||||
for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) {
|
||||
if (!$scope->has($it->current())) {
|
||||
// Scope relates to a form that does not exist
|
||||
// Bail out
|
||||
break;
|
||||
}
|
||||
|
||||
// Process child form
|
||||
$scope = $scope->get($it->current());
|
||||
|
||||
if ($scope->getConfig()->getInheritData()) {
|
||||
// Form inherits its parent data
|
||||
// Cut the piece out of the property path and proceed
|
||||
$propertyPathBuilder->remove($i);
|
||||
} else {
|
||||
/* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
|
||||
$propertyPath = $scope->getPropertyPath();
|
||||
|
||||
if (null === $propertyPath) {
|
||||
// Property path of a mapped form is null
|
||||
// Should not happen, bail out
|
||||
break;
|
||||
}
|
||||
|
||||
$propertyPathBuilder->replace($i, 1, $propertyPath);
|
||||
$i += $propertyPath->getLength();
|
||||
}
|
||||
}
|
||||
|
||||
$finalPath = $propertyPathBuilder->getPropertyPath();
|
||||
|
||||
return null !== $finalPath ? new RelativePath($origin, $finalPath) : null;
|
||||
}
|
||||
|
||||
private function acceptsErrors(FormInterface $form): bool
|
||||
{
|
||||
return $this->allowNonSynchronized || $form->isSynchronized();
|
||||
}
|
||||
}
|
29
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
vendored
Normal file
29
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationMapperInterface.php
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Validator\ConstraintViolation;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface ViolationMapperInterface
|
||||
{
|
||||
/**
|
||||
* Maps a constraint violation to a form in the form tree under
|
||||
* the given form.
|
||||
*
|
||||
* @param bool $allowNonSynchronized Whether to allow mapping to non-synchronized forms
|
||||
*/
|
||||
public function mapViolation(ConstraintViolation $violation, FormInterface $form, bool $allowNonSynchronized = false);
|
||||
}
|
256
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationPath.php
vendored
Normal file
256
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationPath.php
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\Form\Exception\OutOfBoundsException;
|
||||
use Symfony\Component\PropertyAccess\PropertyPath;
|
||||
use Symfony\Component\PropertyAccess\PropertyPathInterface;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*
|
||||
* @implements \IteratorAggregate<int, string>
|
||||
*/
|
||||
class ViolationPath implements \IteratorAggregate, PropertyPathInterface
|
||||
{
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
private $elements = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $isIndex = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $mapsForm = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $pathAsString = '';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $length = 0;
|
||||
|
||||
/**
|
||||
* Creates a new violation path from a string.
|
||||
*
|
||||
* @param string $violationPath The property path of a {@link \Symfony\Component\Validator\ConstraintViolation} object
|
||||
*/
|
||||
public function __construct(string $violationPath)
|
||||
{
|
||||
$path = new PropertyPath($violationPath);
|
||||
$elements = $path->getElements();
|
||||
$data = false;
|
||||
|
||||
for ($i = 0, $l = \count($elements); $i < $l; ++$i) {
|
||||
if (!$data) {
|
||||
// The element "data" has not yet been passed
|
||||
if ('children' === $elements[$i] && $path->isProperty($i)) {
|
||||
// Skip element "children"
|
||||
++$i;
|
||||
|
||||
// Next element must exist and must be an index
|
||||
// Otherwise consider this the end of the path
|
||||
if ($i >= $l || !$path->isIndex($i)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// All the following index items (regardless if .children is
|
||||
// explicitly used) are children and grand-children
|
||||
for (; $i < $l && $path->isIndex($i); ++$i) {
|
||||
$this->elements[] = $elements[$i];
|
||||
$this->isIndex[] = true;
|
||||
$this->mapsForm[] = true;
|
||||
}
|
||||
|
||||
// Rewind the pointer as the last element above didn't match
|
||||
// (even if the pointer was moved forward)
|
||||
--$i;
|
||||
} elseif ('data' === $elements[$i] && $path->isProperty($i)) {
|
||||
// Skip element "data"
|
||||
++$i;
|
||||
|
||||
// End of path
|
||||
if ($i >= $l) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->elements[] = $elements[$i];
|
||||
$this->isIndex[] = $path->isIndex($i);
|
||||
$this->mapsForm[] = false;
|
||||
$data = true;
|
||||
} else {
|
||||
// Neither "children" nor "data" property found
|
||||
// Consider this the end of the path
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Already after the "data" element
|
||||
// Pick everything as is
|
||||
$this->elements[] = $elements[$i];
|
||||
$this->isIndex[] = $path->isIndex($i);
|
||||
$this->mapsForm[] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->length = \count($this->elements);
|
||||
|
||||
$this->buildString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->pathAsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getParent()
|
||||
{
|
||||
if ($this->length <= 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$parent = clone $this;
|
||||
|
||||
--$parent->length;
|
||||
array_pop($parent->elements);
|
||||
array_pop($parent->isIndex);
|
||||
array_pop($parent->mapsForm);
|
||||
|
||||
$parent->buildString();
|
||||
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElements()
|
||||
{
|
||||
return $this->elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getElement(int $index)
|
||||
{
|
||||
if (!isset($this->elements[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index));
|
||||
}
|
||||
|
||||
return $this->elements[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isProperty(int $index)
|
||||
{
|
||||
if (!isset($this->isIndex[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index));
|
||||
}
|
||||
|
||||
return !$this->isIndex[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isIndex(int $index)
|
||||
{
|
||||
if (!isset($this->isIndex[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index));
|
||||
}
|
||||
|
||||
return $this->isIndex[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an element maps directly to a form.
|
||||
*
|
||||
* Consider the following violation path:
|
||||
*
|
||||
* children[address].children[office].data.street
|
||||
*
|
||||
* In this example, "address" and "office" map to forms, while
|
||||
* "street does not.
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @throws OutOfBoundsException if the offset is invalid
|
||||
*/
|
||||
public function mapsForm(int $index)
|
||||
{
|
||||
if (!isset($this->mapsForm[$index])) {
|
||||
throw new OutOfBoundsException(sprintf('The index "%s" is not within the violation path.', $index));
|
||||
}
|
||||
|
||||
return $this->mapsForm[$index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new iterator for this path.
|
||||
*
|
||||
* @return ViolationPathIterator
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
return new ViolationPathIterator($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the string representation from the elements.
|
||||
*/
|
||||
private function buildString()
|
||||
{
|
||||
$this->pathAsString = '';
|
||||
$data = false;
|
||||
|
||||
foreach ($this->elements as $index => $element) {
|
||||
if ($this->mapsForm[$index]) {
|
||||
$this->pathAsString .= ".children[$element]";
|
||||
} elseif (!$data) {
|
||||
$this->pathAsString .= '.data'.($this->isIndex[$index] ? "[$element]" : ".$element");
|
||||
$data = true;
|
||||
} else {
|
||||
$this->pathAsString .= $this->isIndex[$index] ? "[$element]" : ".$element";
|
||||
}
|
||||
}
|
||||
|
||||
if ('' !== $this->pathAsString) {
|
||||
// remove leading dot
|
||||
$this->pathAsString = substr($this->pathAsString, 1);
|
||||
}
|
||||
}
|
||||
}
|
30
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
vendored
Normal file
30
vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationPathIterator.php
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
|
||||
|
||||
use Symfony\Component\PropertyAccess\PropertyPathIterator;
|
||||
|
||||
/**
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class ViolationPathIterator extends PropertyPathIterator
|
||||
{
|
||||
public function __construct(ViolationPath $violationPath)
|
||||
{
|
||||
parent::__construct($violationPath);
|
||||
}
|
||||
|
||||
public function mapsForm()
|
||||
{
|
||||
return $this->path->mapsForm($this->key());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user