vendor/symfony/validator/Constraint.php line 183

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\Validator;
  11. use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
  12. use Symfony\Component\Validator\Exception\InvalidArgumentException;
  13. use Symfony\Component\Validator\Exception\InvalidOptionsException;
  14. use Symfony\Component\Validator\Exception\MissingOptionsException;
  15. /**
  16.  * Contains the properties of a constraint definition.
  17.  *
  18.  * A constraint can be defined on a class, a property or a getter method.
  19.  * The Constraint class encapsulates all the configuration required for
  20.  * validating this class, property or getter result successfully.
  21.  *
  22.  * Constraint instances are immutable and serializable.
  23.  *
  24.  * @property array $groups The groups that the constraint belongs to
  25.  *
  26.  * @author Bernhard Schussek <bschussek@gmail.com>
  27.  */
  28. abstract class Constraint
  29. {
  30.     /**
  31.      * The name of the group given to all constraints with no explicit group.
  32.      */
  33.     public const DEFAULT_GROUP 'Default';
  34.     /**
  35.      * Marks a constraint that can be put onto classes.
  36.      */
  37.     public const CLASS_CONSTRAINT 'class';
  38.     /**
  39.      * Marks a constraint that can be put onto properties.
  40.      */
  41.     public const PROPERTY_CONSTRAINT 'property';
  42.     /**
  43.      * Maps error codes to the names of their constants.
  44.      */
  45.     protected static $errorNames = [];
  46.     /**
  47.      * Domain-specific data attached to a constraint.
  48.      *
  49.      * @var mixed
  50.      */
  51.     public $payload;
  52.     /**
  53.      * Returns the name of the given error code.
  54.      *
  55.      * @param string $errorCode The error code
  56.      *
  57.      * @return string The name of the error code
  58.      *
  59.      * @throws InvalidArgumentException If the error code does not exist
  60.      */
  61.     public static function getErrorName($errorCode)
  62.     {
  63.         if (!isset(static::$errorNames[$errorCode])) {
  64.             throw new InvalidArgumentException(sprintf('The error code "%s" does not exist for constraint of type "%s".'$errorCode, static::class));
  65.         }
  66.         return static::$errorNames[$errorCode];
  67.     }
  68.     /**
  69.      * Initializes the constraint with options.
  70.      *
  71.      * You should pass an associative array. The keys should be the names of
  72.      * existing properties in this class. The values should be the value for these
  73.      * properties.
  74.      *
  75.      * Alternatively you can override the method getDefaultOption() to return the
  76.      * name of an existing property. If no associative array is passed, this
  77.      * property is set instead.
  78.      *
  79.      * You can force that certain options are set by overriding
  80.      * getRequiredOptions() to return the names of these options. If any
  81.      * option is not set here, an exception is thrown.
  82.      *
  83.      * @param mixed $options The options (as associative array)
  84.      *                       or the value for the default
  85.      *                       option (any other type)
  86.      *
  87.      * @throws InvalidOptionsException       When you pass the names of non-existing
  88.      *                                       options
  89.      * @throws MissingOptionsException       When you don't pass any of the options
  90.      *                                       returned by getRequiredOptions()
  91.      * @throws ConstraintDefinitionException When you don't pass an associative
  92.      *                                       array, but getDefaultOption() returns
  93.      *                                       null
  94.      */
  95.     public function __construct($options null)
  96.     {
  97.         foreach ($this->normalizeOptions($options) as $name => $value) {
  98.             $this->$name $value;
  99.         }
  100.     }
  101.     protected function normalizeOptions($options): array
  102.     {
  103.         $normalizedOptions = [];
  104.         $defaultOption $this->getDefaultOption();
  105.         $invalidOptions = [];
  106.         $missingOptions array_flip((array) $this->getRequiredOptions());
  107.         $knownOptions get_class_vars(static::class);
  108.         // The "groups" option is added to the object lazily
  109.         $knownOptions['groups'] = true;
  110.         if (\is_array($options) && isset($options['value']) && !property_exists($this'value')) {
  111.             if (null === $defaultOption) {
  112.                 throw new ConstraintDefinitionException(sprintf('No default option is configured for constraint "%s".', static::class));
  113.             }
  114.             $options[$defaultOption] = $options['value'];
  115.             unset($options['value']);
  116.         }
  117.         if (\is_array($options)) {
  118.             reset($options);
  119.         }
  120.         if ($options && \is_array($options) && \is_string(key($options))) {
  121.             foreach ($options as $option => $value) {
  122.                 if (\array_key_exists($option$knownOptions)) {
  123.                     $normalizedOptions[$option] = $value;
  124.                     unset($missingOptions[$option]);
  125.                 } else {
  126.                     $invalidOptions[] = $option;
  127.                 }
  128.             }
  129.         } elseif (null !== $options && !(\is_array($options) && === \count($options))) {
  130.             if (null === $defaultOption) {
  131.                 throw new ConstraintDefinitionException(sprintf('No default option is configured for constraint "%s".', static::class));
  132.             }
  133.             if (\array_key_exists($defaultOption$knownOptions)) {
  134.                 $normalizedOptions[$defaultOption] = $options;
  135.                 unset($missingOptions[$defaultOption]);
  136.             } else {
  137.                 $invalidOptions[] = $defaultOption;
  138.             }
  139.         }
  140.         if (\count($invalidOptions) > 0) {
  141.             throw new InvalidOptionsException(sprintf('The options "%s" do not exist in constraint "%s".'implode('", "'$invalidOptions), static::class), $invalidOptions);
  142.         }
  143.         if (\count($missingOptions) > 0) {
  144.             throw new MissingOptionsException(sprintf('The options "%s" must be set for constraint "%s".'implode('", "'array_keys($missingOptions)), static::class), array_keys($missingOptions));
  145.         }
  146.         return $normalizedOptions;
  147.     }
  148.     /**
  149.      * Sets the value of a lazily initialized option.
  150.      *
  151.      * Corresponding properties are added to the object on first access. Hence
  152.      * this method will be called at most once per constraint instance and
  153.      * option name.
  154.      *
  155.      * @param mixed $value The value to set
  156.      *
  157.      * @throws InvalidOptionsException If an invalid option name is given
  158.      */
  159.     public function __set(string $option$value)
  160.     {
  161.         if ('groups' === $option) {
  162.             $this->groups = (array) $value;
  163.             return;
  164.         }
  165.         throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint "%s".'$option, static::class), [$option]);
  166.     }
  167.     /**
  168.      * Returns the value of a lazily initialized option.
  169.      *
  170.      * Corresponding properties are added to the object on first access. Hence
  171.      * this method will be called at most once per constraint instance and
  172.      * option name.
  173.      *
  174.      * @param string $option The option name
  175.      *
  176.      * @return mixed The value of the option
  177.      *
  178.      * @throws InvalidOptionsException If an invalid option name is given
  179.      *
  180.      * @internal this method should not be used or overwritten in userland code
  181.      */
  182.     public function __get(string $option)
  183.     {
  184.         if ('groups' === $option) {
  185.             $this->groups = [self::DEFAULT_GROUP];
  186.             return $this->groups;
  187.         }
  188.         throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint "%s".'$option, static::class), [$option]);
  189.     }
  190.     /**
  191.      * @param string $option The option name
  192.      *
  193.      * @return bool
  194.      */
  195.     public function __isset(string $option)
  196.     {
  197.         return 'groups' === $option;
  198.     }
  199.     /**
  200.      * Adds the given group if this constraint is in the Default group.
  201.      *
  202.      * @param string $group
  203.      */
  204.     public function addImplicitGroupName($group)
  205.     {
  206.         if (\in_array(self::DEFAULT_GROUP$this->groups) && !\in_array($group$this->groups)) {
  207.             $this->groups[] = $group;
  208.         }
  209.     }
  210.     /**
  211.      * Returns the name of the default option.
  212.      *
  213.      * Override this method to define a default option.
  214.      *
  215.      * @return string|null
  216.      *
  217.      * @see __construct()
  218.      */
  219.     public function getDefaultOption()
  220.     {
  221.         return null;
  222.     }
  223.     /**
  224.      * Returns the name of the required options.
  225.      *
  226.      * Override this method if you want to define required options.
  227.      *
  228.      * @return array
  229.      *
  230.      * @see __construct()
  231.      */
  232.     public function getRequiredOptions()
  233.     {
  234.         return [];
  235.     }
  236.     /**
  237.      * Returns the name of the class that validates this constraint.
  238.      *
  239.      * By default, this is the fully qualified name of the constraint class
  240.      * suffixed with "Validator". You can override this method to change that
  241.      * behavior.
  242.      *
  243.      * @return string
  244.      */
  245.     public function validatedBy()
  246.     {
  247.         return static::class.'Validator';
  248.     }
  249.     /**
  250.      * Returns whether the constraint can be put onto classes, properties or
  251.      * both.
  252.      *
  253.      * This method should return one or more of the constants
  254.      * Constraint::CLASS_CONSTRAINT and Constraint::PROPERTY_CONSTRAINT.
  255.      *
  256.      * @return string|array One or more constant values
  257.      */
  258.     public function getTargets()
  259.     {
  260.         return self::PROPERTY_CONSTRAINT;
  261.     }
  262.     /**
  263.      * Optimizes the serialized value to minimize storage space.
  264.      *
  265.      * @internal
  266.      */
  267.     public function __sleep()
  268.     {
  269.         // Initialize "groups" option if it is not set
  270.         $this->groups;
  271.         return array_keys(get_object_vars($this));
  272.     }
  273. }