ConstraintManager.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. namespace Drupal\Core\Validation;
  3. use Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator;
  4. use Drupal\Core\Cache\CacheBackendInterface;
  5. use Drupal\Core\Extension\ModuleHandlerInterface;
  6. use Drupal\Core\Plugin\DefaultPluginManager;
  7. use Drupal\Core\StringTranslation\TranslatableMarkup;
  8. /**
  9. * Constraint plugin manager.
  10. *
  11. * Manages validation constraints based upon
  12. * \Symfony\Component\Validator\Constraint, whereas Symfony constraints are
  13. * added in manually during construction. Constraint options are passed on as
  14. * plugin configuration during plugin instantiation.
  15. *
  16. * While core does not prefix constraint plugins, modules have to prefix them
  17. * with the module name in order to avoid any naming conflicts; for example, a
  18. * "profile" module would have to prefix any constraints with "Profile".
  19. *
  20. * Constraint plugins may specify data types to which support is limited via the
  21. * 'type' key of plugin definitions. See
  22. * \Drupal\Core\Validation\Annotation\Constraint for details.
  23. *
  24. * @see \Drupal\Core\Validation\Annotation\Constraint
  25. */
  26. class ConstraintManager extends DefaultPluginManager {
  27. /**
  28. * Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
  29. *
  30. * @param \Traversable $namespaces
  31. * An object that implements \Traversable which contains the root paths
  32. * keyed by the corresponding namespace to look for plugin implementations.
  33. * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
  34. * Cache backend instance to use.
  35. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  36. * The module handler to invoke the alter hook with.
  37. */
  38. public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
  39. parent::__construct('Plugin/Validation/Constraint', $namespaces, $module_handler, NULL, 'Drupal\Core\Validation\Annotation\Constraint');
  40. $this->alterInfo('validation_constraint');
  41. $this->setCacheBackend($cache_backend, 'validation_constraint_plugins');
  42. }
  43. /**
  44. * {@inheritdoc}
  45. */
  46. protected function getDiscovery() {
  47. if (!isset($this->discovery)) {
  48. $this->discovery = parent::getDiscovery();
  49. $this->discovery = new StaticDiscoveryDecorator($this->discovery, [$this, 'registerDefinitions']);
  50. }
  51. return $this->discovery;
  52. }
  53. /**
  54. * Creates a validation constraint.
  55. *
  56. * @param string $name
  57. * The name or plugin id of the constraint.
  58. * @param mixed $options
  59. * The options to pass to the constraint class. Required and supported
  60. * options depend on the constraint class.
  61. *
  62. * @return \Symfony\Component\Validator\Constraint
  63. * A validation constraint plugin.
  64. */
  65. public function create($name, $options) {
  66. if (!is_array($options)) {
  67. // Plugins need an array as configuration, so make sure we have one.
  68. // The constraint classes support passing the options as part of the
  69. // 'value' key also.
  70. $options = isset($options) ? ['value' => $options] : [];
  71. }
  72. return $this->createInstance($name, $options);
  73. }
  74. /**
  75. * Callback for registering definitions for constraints shipped with Symfony.
  76. *
  77. * @see ConstraintManager::__construct()
  78. */
  79. public function registerDefinitions() {
  80. $this->getDiscovery()->setDefinition('Callback', [
  81. 'label' => new TranslatableMarkup('Callback'),
  82. 'class' => '\Symfony\Component\Validator\Constraints\Callback',
  83. 'type' => FALSE,
  84. ]);
  85. $this->getDiscovery()->setDefinition('Blank', [
  86. 'label' => new TranslatableMarkup('Blank'),
  87. 'class' => '\Symfony\Component\Validator\Constraints\Blank',
  88. 'type' => FALSE,
  89. ]);
  90. $this->getDiscovery()->setDefinition('NotBlank', [
  91. 'label' => new TranslatableMarkup('Not blank'),
  92. 'class' => '\Symfony\Component\Validator\Constraints\NotBlank',
  93. 'type' => FALSE,
  94. ]);
  95. $this->getDiscovery()->setDefinition('Email', [
  96. 'label' => new TranslatableMarkup('Email'),
  97. 'class' => '\Drupal\Core\Validation\Plugin\Validation\Constraint\EmailConstraint',
  98. 'type' => ['string'],
  99. ]);
  100. }
  101. /**
  102. * {@inheritdoc}
  103. */
  104. public function processDefinition(&$definition, $plugin_id) {
  105. // Make sure 'type' is set and either an array or FALSE.
  106. if ($definition['type'] !== FALSE && !is_array($definition['type'])) {
  107. $definition['type'] = [$definition['type']];
  108. }
  109. }
  110. /**
  111. * Returns a list of constraints that support the given type.
  112. *
  113. * @param string $type
  114. * The type to filter on.
  115. *
  116. * @return array
  117. * An array of constraint plugin definitions supporting the given type,
  118. * keyed by constraint name (plugin ID).
  119. */
  120. public function getDefinitionsByType($type) {
  121. $definitions = [];
  122. foreach ($this->getDefinitions() as $plugin_id => $definition) {
  123. if ($definition['type'] === FALSE || in_array($type, $definition['type'])) {
  124. $definitions[$plugin_id] = $definition;
  125. }
  126. }
  127. return $definitions;
  128. }
  129. }