vendor/symfony/validator/Constraint.php line 171

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.         $defaultOption $this->getDefaultOption();
  98.         $invalidOptions = [];
  99.         $missingOptions array_flip((array) $this->getRequiredOptions());
  100.         $knownOptions get_class_vars(static::class);
  101.         // The "groups" option is added to the object lazily
  102.         $knownOptions['groups'] = true;
  103.         if (\is_array($options) && isset($options['value']) && !property_exists($this'value')) {
  104.             if (null === $defaultOption) {
  105.                 throw new ConstraintDefinitionException(sprintf('No default option is configured for constraint "%s".', static::class));
  106.             }
  107.             $options[$defaultOption] = $options['value'];
  108.             unset($options['value']);
  109.         }
  110.         if (\is_array($options)) {
  111.             reset($options);
  112.         }
  113.         if ($options && \is_array($options) && \is_string(key($options))) {
  114.             foreach ($options as $option => $value) {
  115.                 if (\array_key_exists($option$knownOptions)) {
  116.                     $this->$option $value;
  117.                     unset($missingOptions[$option]);
  118.                 } else {
  119.                     $invalidOptions[] = $option;
  120.                 }
  121.             }
  122.         } elseif (null !== $options && !(\is_array($options) && === \count($options))) {
  123.             if (null === $defaultOption) {
  124.                 throw new ConstraintDefinitionException(sprintf('No default option is configured for constraint "%s".', static::class));
  125.             }
  126.             if (\array_key_exists($defaultOption$knownOptions)) {
  127.                 $this->$defaultOption $options;
  128.                 unset($missingOptions[$defaultOption]);
  129.             } else {
  130.                 $invalidOptions[] = $defaultOption;
  131.             }
  132.         }
  133.         if (\count($invalidOptions) > 0) {
  134.             throw new InvalidOptionsException(sprintf('The options "%s" do not exist in constraint "%s".'implode('", "'$invalidOptions), static::class), $invalidOptions);
  135.         }
  136.         if (\count($missingOptions) > 0) {
  137.             throw new MissingOptionsException(sprintf('The options "%s" must be set for constraint "%s".'implode('", "'array_keys($missingOptions)), static::class), array_keys($missingOptions));
  138.         }
  139.     }
  140.     /**
  141.      * Sets the value of a lazily initialized option.
  142.      *
  143.      * Corresponding properties are added to the object on first access. Hence
  144.      * this method will be called at most once per constraint instance and
  145.      * option name.
  146.      *
  147.      * @param string $option The option name
  148.      * @param mixed  $value  The value to set
  149.      *
  150.      * @throws InvalidOptionsException If an invalid option name is given
  151.      */
  152.     public function __set($option$value)
  153.     {
  154.         if ('groups' === $option) {
  155.             $this->groups = (array) $value;
  156.             return;
  157.         }
  158.         throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint "%s".'$option, static::class), [$option]);
  159.     }
  160.     /**
  161.      * Returns the value of a lazily initialized option.
  162.      *
  163.      * Corresponding properties are added to the object on first access. Hence
  164.      * this method will be called at most once per constraint instance and
  165.      * option name.
  166.      *
  167.      * @param string $option The option name
  168.      *
  169.      * @return mixed The value of the option
  170.      *
  171.      * @throws InvalidOptionsException If an invalid option name is given
  172.      *
  173.      * @internal this method should not be used or overwritten in userland code
  174.      */
  175.     public function __get($option)
  176.     {
  177.         if ('groups' === $option) {
  178.             $this->groups = [self::DEFAULT_GROUP];
  179.             return $this->groups;
  180.         }
  181.         throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint "%s".'$option, static::class), [$option]);
  182.     }
  183.     /**
  184.      * @param string $option The option name
  185.      *
  186.      * @return bool
  187.      */
  188.     public function __isset($option)
  189.     {
  190.         return 'groups' === $option;
  191.     }
  192.     /**
  193.      * Adds the given group if this constraint is in the Default group.
  194.      *
  195.      * @param string $group
  196.      */
  197.     public function addImplicitGroupName($group)
  198.     {
  199.         if (\in_array(self::DEFAULT_GROUP$this->groups) && !\in_array($group$this->groups)) {
  200.             $this->groups[] = $group;
  201.         }
  202.     }
  203.     /**
  204.      * Returns the name of the default option.
  205.      *
  206.      * Override this method to define a default option.
  207.      *
  208.      * @return string|null
  209.      *
  210.      * @see __construct()
  211.      */
  212.     public function getDefaultOption()
  213.     {
  214.         return null;
  215.     }
  216.     /**
  217.      * Returns the name of the required options.
  218.      *
  219.      * Override this method if you want to define required options.
  220.      *
  221.      * @return array
  222.      *
  223.      * @see __construct()
  224.      */
  225.     public function getRequiredOptions()
  226.     {
  227.         return [];
  228.     }
  229.     /**
  230.      * Returns the name of the class that validates this constraint.
  231.      *
  232.      * By default, this is the fully qualified name of the constraint class
  233.      * suffixed with "Validator". You can override this method to change that
  234.      * behavior.
  235.      *
  236.      * @return string
  237.      */
  238.     public function validatedBy()
  239.     {
  240.         return static::class.'Validator';
  241.     }
  242.     /**
  243.      * Returns whether the constraint can be put onto classes, properties or
  244.      * both.
  245.      *
  246.      * This method should return one or more of the constants
  247.      * Constraint::CLASS_CONSTRAINT and Constraint::PROPERTY_CONSTRAINT.
  248.      *
  249.      * @return string|array One or more constant values
  250.      */
  251.     public function getTargets()
  252.     {
  253.         return self::PROPERTY_CONSTRAINT;
  254.     }
  255.     /**
  256.      * Optimizes the serialized value to minimize storage space.
  257.      *
  258.      * @internal
  259.      */
  260.     public function __sleep()
  261.     {
  262.         // Initialize "groups" option if it is not set
  263.         $this->groups;
  264.         return array_keys(get_object_vars($this));
  265.     }
  266. }