Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 58

Deprecated: Constant E_STRICT is deprecated in /home/pastorz/old-espace-client/vendor/symfony/error-handler/ErrorHandler.php on line 76
Symfony Profiler

vendor/symfony/form/Extension/Validator/ViolationMapper/ViolationMapper.php line 35

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony package.
  4.  *
  5.  * (c) Fabien Potencier <fabien@symfony.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Component\Form\Extension\Validator\ViolationMapper;
  11. use Symfony\Component\Form\FileUploadError;
  12. use Symfony\Component\Form\FormError;
  13. use Symfony\Component\Form\FormInterface;
  14. use Symfony\Component\Form\FormRendererInterface;
  15. use Symfony\Component\Form\Util\InheritDataAwareIterator;
  16. use Symfony\Component\PropertyAccess\PropertyPathBuilder;
  17. use Symfony\Component\PropertyAccess\PropertyPathIterator;
  18. use Symfony\Component\PropertyAccess\PropertyPathIteratorInterface;
  19. use Symfony\Component\Validator\Constraints\File;
  20. use Symfony\Component\Validator\ConstraintViolation;
  21. use Symfony\Contracts\Translation\TranslatorInterface;
  22. /**
  23.  * @author Bernhard Schussek <bschussek@gmail.com>
  24.  */
  25. class ViolationMapper implements ViolationMapperInterface
  26. {
  27.     private $formRenderer;
  28.     private $translator;
  29.     private $allowNonSynchronized false;
  30.     public function __construct(FormRendererInterface $formRenderer nullTranslatorInterface $translator null)
  31.     {
  32.         $this->formRenderer $formRenderer;
  33.         $this->translator $translator;
  34.     }
  35.     /**
  36.      * {@inheritdoc}
  37.      */
  38.     public function mapViolation(ConstraintViolation $violationFormInterface $formbool $allowNonSynchronized false)
  39.     {
  40.         $this->allowNonSynchronized $allowNonSynchronized;
  41.         // The scope is the currently found most specific form that
  42.         // an error should be mapped to. After setting the scope, the
  43.         // mapper will try to continue to find more specific matches in
  44.         // the children of scope. If it cannot, the error will be
  45.         // mapped to this scope.
  46.         $scope null;
  47.         $violationPath null;
  48.         $relativePath null;
  49.         $match false;
  50.         // Don't create a ViolationPath instance for empty property paths
  51.         if ('' !== $violation->getPropertyPath()) {
  52.             $violationPath = new ViolationPath($violation->getPropertyPath());
  53.             $relativePath $this->reconstructPath($violationPath$form);
  54.         }
  55.         // This case happens if the violation path is empty and thus
  56.         // the violation should be mapped to the root form
  57.         if (null === $violationPath) {
  58.             $scope $form;
  59.         }
  60.         // In general, mapping happens from the root form to the leaf forms
  61.         // First, the rules of the root form are applied to determine
  62.         // the subsequent descendant. The rules of this descendant are then
  63.         // applied to find the next and so on, until we have found the
  64.         // most specific form that matches the violation.
  65.         // If any of the forms found in this process is not synchronized,
  66.         // mapping is aborted. Non-synchronized forms could not reverse
  67.         // transform the value entered by the user, thus any further violations
  68.         // caused by the (invalid) reverse transformed value should be
  69.         // ignored.
  70.         if (null !== $relativePath) {
  71.             // Set the scope to the root of the relative path
  72.             // This root will usually be $form. If the path contains
  73.             // an unmapped form though, the last unmapped form found
  74.             // will be the root of the path.
  75.             $scope $relativePath->getRoot();
  76.             $it = new PropertyPathIterator($relativePath);
  77.             while ($this->acceptsErrors($scope) && null !== ($child $this->matchChild($scope$it))) {
  78.                 $scope $child;
  79.                 $it->next();
  80.                 $match true;
  81.             }
  82.         }
  83.         // This case happens if an error happened in the data under a
  84.         // form inheriting its parent data that does not match any of the
  85.         // children of that form.
  86.         if (null !== $violationPath && !$match) {
  87.             // If we could not map the error to anything more specific
  88.             // than the root element, map it to the innermost directly
  89.             // mapped form of the violation path
  90.             // e.g. "children[foo].children[bar].data.baz"
  91.             // Here the innermost directly mapped child is "bar"
  92.             $scope $form;
  93.             $it = new ViolationPathIterator($violationPath);
  94.             // Note: acceptsErrors() will always return true for forms inheriting
  95.             // their parent data, because these forms can never be non-synchronized
  96.             // (they don't do any data transformation on their own)
  97.             while ($this->acceptsErrors($scope) && $it->valid() && $it->mapsForm()) {
  98.                 if (!$scope->has($it->current())) {
  99.                     // Break if we find a reference to a non-existing child
  100.                     break;
  101.                 }
  102.                 $scope $scope->get($it->current());
  103.                 $it->next();
  104.             }
  105.         }
  106.         // Follow dot rules until we have the final target
  107.         $mapping $scope->getConfig()->getOption('error_mapping');
  108.         while ($this->acceptsErrors($scope) && isset($mapping['.'])) {
  109.             $dotRule = new MappingRule($scope'.'$mapping['.']);
  110.             $scope $dotRule->getTarget();
  111.             $mapping $scope->getConfig()->getOption('error_mapping');
  112.         }
  113.         // Only add the error if the form is synchronized
  114.         if ($this->acceptsErrors($scope)) {
  115.             if ($violation->getConstraint() instanceof File && (string) \UPLOAD_ERR_INI_SIZE === $violation->getCode()) {
  116.                 $errorsTarget $scope;
  117.                 while (null !== $errorsTarget->getParent() && $errorsTarget->getConfig()->getErrorBubbling()) {
  118.                     $errorsTarget $errorsTarget->getParent();
  119.                 }
  120.                 $errors $errorsTarget->getErrors();
  121.                 $errorsTarget->clearErrors();
  122.                 foreach ($errors as $error) {
  123.                     if (!$error instanceof FileUploadError) {
  124.                         $errorsTarget->addError($error);
  125.                     }
  126.                 }
  127.             }
  128.             $message $violation->getMessage();
  129.             $messageTemplate $violation->getMessageTemplate();
  130.             if (false !== strpos($message'{{ label }}') || false !== strpos($messageTemplate'{{ label }}')) {
  131.                 $form $scope;
  132.                 do {
  133.                     $labelFormat $form->getConfig()->getOption('label_format');
  134.                 } while (null === $labelFormat && null !== $form $form->getParent());
  135.                 if (null !== $labelFormat) {
  136.                     $label str_replace(
  137.                         [
  138.                             '%name%',
  139.                             '%id%',
  140.                         ],
  141.                         [
  142.                             $scope->getName(),
  143.                             (string) $scope->getPropertyPath(),
  144.                         ],
  145.                         $labelFormat
  146.                     );
  147.                 } else {
  148.                     $label $scope->getConfig()->getOption('label');
  149.                 }
  150.                 if (false !== $label) {
  151.                     if (null === $label && null !== $this->formRenderer) {
  152.                         $label $this->formRenderer->humanize($scope->getName());
  153.                     } elseif (null === $label) {
  154.                         $label $scope->getName();
  155.                     }
  156.                     if (null !== $this->translator) {
  157.                         $form $scope;
  158.                         $translationParameters[] = $form->getConfig()->getOption('label_translation_parameters', []);
  159.                         do {
  160.                             $translationDomain $form->getConfig()->getOption('translation_domain');
  161.                             array_unshift(
  162.                                 $translationParameters,
  163.                                 $form->getConfig()->getOption('label_translation_parameters', [])
  164.                             );
  165.                         } while (null === $translationDomain && null !== $form $form->getParent());
  166.                         $translationParameters array_merge([], ...$translationParameters);
  167.                         $label $this->translator->trans(
  168.                             $label,
  169.                             $translationParameters,
  170.                             $translationDomain
  171.                         );
  172.                     }
  173.                     $message str_replace('{{ label }}'$label$message);
  174.                     $messageTemplate str_replace('{{ label }}'$label$messageTemplate);
  175.                 }
  176.             }
  177.             $scope->addError(new FormError(
  178.                 $message,
  179.                 $messageTemplate,
  180.                 $violation->getParameters(),
  181.                 $violation->getPlural(),
  182.                 $violation
  183.             ));
  184.         }
  185.     }
  186.     /**
  187.      * Tries to match the beginning of the property path at the
  188.      * current position against the children of the scope.
  189.      *
  190.      * If a matching child is found, it is returned. Otherwise
  191.      * null is returned.
  192.      */
  193.     private function matchChild(FormInterface $formPropertyPathIteratorInterface $it): ?FormInterface
  194.     {
  195.         $target null;
  196.         $chunk '';
  197.         $foundAtIndex null;
  198.         // Construct mapping rules for the given form
  199.         $rules = [];
  200.         foreach ($form->getConfig()->getOption('error_mapping') as $propertyPath => $targetPath) {
  201.             // Dot rules are considered at the very end
  202.             if ('.' !== $propertyPath) {
  203.                 $rules[] = new MappingRule($form$propertyPath$targetPath);
  204.             }
  205.         }
  206.         $children iterator_to_array(new \RecursiveIteratorIterator(new InheritDataAwareIterator($form)), false);
  207.         while ($it->valid()) {
  208.             if ($it->isIndex()) {
  209.                 $chunk .= '['.$it->current().']';
  210.             } else {
  211.                 $chunk .= ('' === $chunk '' '.').$it->current();
  212.             }
  213.             // Test mapping rules as long as we have any
  214.             foreach ($rules as $key => $rule) {
  215.                 /* @var MappingRule $rule */
  216.                 // Mapping rule matches completely, terminate.
  217.                 if (null !== ($form $rule->match($chunk))) {
  218.                     return $form;
  219.                 }
  220.                 // Keep only rules that have $chunk as prefix
  221.                 if (!$rule->isPrefix($chunk)) {
  222.                     unset($rules[$key]);
  223.                 }
  224.             }
  225.             /** @var FormInterface $child */
  226.             foreach ($children as $i => $child) {
  227.                 $childPath = (string) $child->getPropertyPath();
  228.                 if ($childPath === $chunk) {
  229.                     $target $child;
  230.                     $foundAtIndex $it->key();
  231.                 } elseif (str_starts_with($childPath$chunk)) {
  232.                     continue;
  233.                 }
  234.                 unset($children[$i]);
  235.             }
  236.             $it->next();
  237.         }
  238.         if (null !== $foundAtIndex) {
  239.             $it->seek($foundAtIndex);
  240.         }
  241.         return $target;
  242.     }
  243.     /**
  244.      * Reconstructs a property path from a violation path and a form tree.
  245.      */
  246.     private function reconstructPath(ViolationPath $violationPathFormInterface $origin): ?RelativePath
  247.     {
  248.         $propertyPathBuilder = new PropertyPathBuilder($violationPath);
  249.         $it $violationPath->getIterator();
  250.         $scope $origin;
  251.         // Remember the current index in the builder
  252.         $i 0;
  253.         // Expand elements that map to a form (like "children[address]")
  254.         for ($it->rewind(); $it->valid() && $it->mapsForm(); $it->next()) {
  255.             if (!$scope->has($it->current())) {
  256.                 // Scope relates to a form that does not exist
  257.                 // Bail out
  258.                 break;
  259.             }
  260.             // Process child form
  261.             $scope $scope->get($it->current());
  262.             if ($scope->getConfig()->getInheritData()) {
  263.                 // Form inherits its parent data
  264.                 // Cut the piece out of the property path and proceed
  265.                 $propertyPathBuilder->remove($i);
  266.             } else {
  267.                 /* @var \Symfony\Component\PropertyAccess\PropertyPathInterface $propertyPath */
  268.                 $propertyPath $scope->getPropertyPath();
  269.                 if (null === $propertyPath) {
  270.                     // Property path of a mapped form is null
  271.                     // Should not happen, bail out
  272.                     break;
  273.                 }
  274.                 $propertyPathBuilder->replace($i1$propertyPath);
  275.                 $i += $propertyPath->getLength();
  276.             }
  277.         }
  278.         $finalPath $propertyPathBuilder->getPropertyPath();
  279.         return null !== $finalPath ? new RelativePath($origin$finalPath) : null;
  280.     }
  281.     private function acceptsErrors(FormInterface $form): bool
  282.     {
  283.         return $this->allowNonSynchronized || $form->isSynchronized();
  284.     }
  285. }