Constraint.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. namespace Symfony\Component\Validator;
  3. /*
  4. * This file is part of the Symfony framework.
  5. *
  6. * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
  7. *
  8. * This source file is subject to the MIT license that is bundled
  9. * with this source code in the file LICENSE.
  10. */
  11. use Symfony\Component\Validator\Exception\InvalidOptionsException;
  12. use Symfony\Component\Validator\Exception\MissingOptionsException;
  13. use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
  14. /**
  15. * Contains the properties of a constraint definition.
  16. *
  17. * A constraint can be defined on a class, an option or a getter method.
  18. * The Constraint class encapsulates all the configuration required for
  19. * validating this class, option or getter result successfully.
  20. *
  21. * Constraint instances are immutable and serializable.
  22. *
  23. * @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
  24. */
  25. abstract class Constraint
  26. {
  27. const DEFAULT_GROUP = 'Default';
  28. public $groups = array(self::DEFAULT_GROUP);
  29. /**
  30. * Initializes the constraint with options.
  31. *
  32. * You should pass an associative array. The keys should be the names of
  33. * existing properties in this class. The values should be the value for these
  34. * properties.
  35. *
  36. * Alternatively you can override the method defaultOption() to return the
  37. * name of an existing property. If no associative array is passed, this
  38. * property is set instead.
  39. *
  40. * You can force that certain options are set by overriding
  41. * requiredOptions() to return the names of these options. If any
  42. * option is not set here, an exception is thrown.
  43. *
  44. * @param mixed $options The options (as associative array)
  45. * or the value for the default
  46. * option (any other type)
  47. *
  48. * @throws InvalidOptionsException When you pass the names of non-existing
  49. * options
  50. * @throws MissingOptionsException When you don't pass any of the options
  51. * returned by requiredOptions()
  52. * @throws ConstraintDefinitionException When you don't pass an associative
  53. * array, but defaultOption() returns
  54. * NULL
  55. */
  56. public function __construct($options = null)
  57. {
  58. $invalidOptions = array();
  59. $missingOptions = array_flip((array)$this->requiredOptions());
  60. if (is_array($options) && count($options) == 1 && isset($options['value'])) {
  61. $options = $options['value'];
  62. }
  63. if (is_array($options) && count($options) > 0 && is_string(key($options))) {
  64. foreach ($options as $option => $value) {
  65. if (property_exists($this, $option)) {
  66. $this->$option = $value;
  67. unset($missingOptions[$option]);
  68. } else {
  69. $invalidOptions[] = $option;
  70. }
  71. }
  72. } else if ($options !== null && ! (is_array($options) && count($options) === 0)) {
  73. $option = $this->defaultOption();
  74. if (null === $option) {
  75. throw new ConstraintDefinitionException(
  76. sprintf('No default option is configured for constraint %s', get_class($this))
  77. );
  78. }
  79. if (property_exists($this, $option)) {
  80. $this->$option = $options;
  81. unset($missingOptions[$option]);
  82. } else {
  83. $invalidOptions[] = $option;
  84. }
  85. }
  86. if (count($invalidOptions) > 0) {
  87. throw new InvalidOptionsException(
  88. sprintf('The options "%s" do not exist in constraint %s', implode('", "', $invalidOptions), get_class($this)),
  89. $invalidOptions
  90. );
  91. }
  92. if (count($missingOptions) > 0) {
  93. throw new MissingOptionsException(
  94. sprintf('The options "%s" must be set for constraint %s', implode('", "', array_keys($missingOptions)), get_class($this)),
  95. array_keys($missingOptions)
  96. );
  97. }
  98. $this->groups = (array)$this->groups;
  99. }
  100. /**
  101. * Unsupported operation.
  102. */
  103. public function __set($option, $value)
  104. {
  105. throw new InvalidOptionsException(sprintf('The option "%s" does not exist in constraint %s', $option, get_class($this)), array($option));
  106. }
  107. /**
  108. * Adds the given group if this constraint is in the Default group
  109. *
  110. * @param string $group
  111. */
  112. public function addImplicitGroupName($group)
  113. {
  114. if (in_array(Constraint::DEFAULT_GROUP, $this->groups) && !in_array($group, $this->groups)) {
  115. $this->groups[] = $group;
  116. }
  117. }
  118. /**
  119. * Returns the name of the default option
  120. *
  121. * Override this method to define a default option.
  122. *
  123. * @return string
  124. * @see __construct()
  125. */
  126. public function defaultOption()
  127. {
  128. return null;
  129. }
  130. /**
  131. * Returns the name of the required options
  132. *
  133. * Override this method if you want to define required options.
  134. *
  135. * @return array
  136. * @see __construct()
  137. */
  138. public function requiredOptions()
  139. {
  140. return array();
  141. }
  142. /**
  143. * Returns the name of the class that validates this constraint
  144. *
  145. * By default, this is the fully qualified name of the constraint class
  146. * suffixed with "Validator". You can override this method to change that
  147. * behaviour.
  148. *
  149. * @return string
  150. */
  151. public function validatedBy()
  152. {
  153. return get_class($this) . 'Validator';
  154. }
  155. }