Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
57
core/lib/Drupal/Core/Validation/Annotation/Constraint.php
Normal file
57
core/lib/Drupal/Core/Validation/Annotation/Constraint.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Annotation\Constraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines a validation constraint annotation object.
|
||||
*
|
||||
* Plugin Namespace: Plugin\Validation\Constraint
|
||||
*
|
||||
* For a working example, see
|
||||
* \Drupal\Core\Validation\Plugin\Validation\Constraint\LengthConstraint
|
||||
*
|
||||
* @see \Drupal\Core\Validation\ConstraintManager
|
||||
* @see \Symfony\Component\Validator\Constraint
|
||||
* @see hook_validation_constraint_alter()
|
||||
* @see plugin_api
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class Constraint extends Plugin {
|
||||
|
||||
/**
|
||||
* The constraint plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the constraint plugin.
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*
|
||||
* @var string|\Drupal\Core\Annotation\Translation
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* An array of DataType plugin IDs for which this constraint applies. Valid
|
||||
* values are any types registered by the typed data API, or an array of
|
||||
* multiple type names. For supporting all types, FALSE may be specified. The
|
||||
* key defaults to an empty array, which indicates no types are supported.
|
||||
*
|
||||
* @var string|string[]|false
|
||||
*
|
||||
* @see \Drupal\Core\TypedData\Annotation\DataType
|
||||
*/
|
||||
public $type = [];
|
||||
|
||||
}
|
144
core/lib/Drupal/Core/Validation/ConstraintManager.php
Normal file
144
core/lib/Drupal/Core/Validation/ConstraintManager.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\ConstraintManager.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Drupal\Component\Plugin\Discovery\StaticDiscoveryDecorator;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
|
||||
/**
|
||||
* Constraint plugin manager.
|
||||
*
|
||||
* Manages validation constraints based upon
|
||||
* \Symfony\Component\Validator\Constraint, whereas Symfony constraints are
|
||||
* added in manually during construction. Constraint options are passed on as
|
||||
* plugin configuration during plugin instantiation.
|
||||
*
|
||||
* While core does not prefix constraint plugins, modules have to prefix them
|
||||
* with the module name in order to avoid any naming conflicts. E.g. a "profile"
|
||||
* module would have to prefix any constraints with "Profile".
|
||||
*
|
||||
* Constraint plugins may specify data types to which support is limited via the
|
||||
* 'type' key of plugin definitions. See
|
||||
* \Drupal\Core\Validation\Annotation\Constraint for details.
|
||||
*
|
||||
* @see \Drupal\Core\Validation\Annotation\Constraint
|
||||
*/
|
||||
class ConstraintManager extends DefaultPluginManager {
|
||||
|
||||
/**
|
||||
* Overrides \Drupal\Component\Plugin\PluginManagerBase::__construct().
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/Validation/Constraint', $namespaces, $module_handler, NULL, 'Drupal\Core\Validation\Annotation\Constraint');
|
||||
$this->alterInfo('validation_constraint');
|
||||
$this->setCacheBackend($cache_backend, 'validation_constraint_plugins');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getDiscovery() {
|
||||
if (!isset($this->discovery)) {
|
||||
$this->discovery = parent::getDiscovery();
|
||||
$this->discovery = new StaticDiscoveryDecorator($this->discovery, [$this, 'registerDefinitions']);
|
||||
}
|
||||
return $this->discovery;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a validation constraint.
|
||||
*
|
||||
* @param string $name
|
||||
* The name or plugin id of the constraint.
|
||||
* @param mixed $options
|
||||
* The options to pass to the constraint class. Required and supported
|
||||
* options depend on the constraint class.
|
||||
*
|
||||
* @return \Symfony\Component\Validator\Constraint
|
||||
* A validation constraint plugin.
|
||||
*/
|
||||
public function create($name, $options) {
|
||||
if (!is_array($options)) {
|
||||
// Plugins need an array as configuration, so make sure we have one.
|
||||
// The constraint classes support passing the options as part of the
|
||||
// 'value' key also.
|
||||
$options = isset($options) ? array('value' => $options) : array();
|
||||
}
|
||||
return $this->createInstance($name, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for registering definitions for constraints shipped with Symfony.
|
||||
*
|
||||
* @see ConstraintManager::__construct()
|
||||
*/
|
||||
public function registerDefinitions() {
|
||||
$this->getDiscovery()->setDefinition('Callback', array(
|
||||
'label' => new TranslationWrapper('Callback'),
|
||||
'class' => '\Symfony\Component\Validator\Constraints\Callback',
|
||||
'type' => FALSE,
|
||||
));
|
||||
$this->getDiscovery()->setDefinition('Blank', array(
|
||||
'label' => new TranslationWrapper('Blank'),
|
||||
'class' => '\Symfony\Component\Validator\Constraints\Blank',
|
||||
'type' => FALSE,
|
||||
));
|
||||
$this->getDiscovery()->setDefinition('NotBlank', array(
|
||||
'label' => new TranslationWrapper('Not blank'),
|
||||
'class' => '\Symfony\Component\Validator\Constraints\NotBlank',
|
||||
'type' => FALSE,
|
||||
));
|
||||
$this->getDiscovery()->setDefinition('Email', array(
|
||||
'label' => new TranslationWrapper('Email'),
|
||||
'class' => '\Drupal\Core\Validation\Plugin\Validation\Constraint\EmailConstraint',
|
||||
'type' => array('string'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processDefinition(&$definition, $plugin_id) {
|
||||
// Make sure 'type' is set and either an array or FALSE.
|
||||
if ($definition['type'] !== FALSE && !is_array($definition['type'])) {
|
||||
$definition['type'] = array($definition['type']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of constraints that support the given type.
|
||||
*
|
||||
* @param string $type
|
||||
* The type to filter on.
|
||||
*
|
||||
* @return array
|
||||
* An array of constraint plugin definitions supporting the given type,
|
||||
* keyed by constraint name (plugin ID).
|
||||
*/
|
||||
public function getDefinitionsByType($type) {
|
||||
$definitions = array();
|
||||
foreach ($this->getDefinitions() as $plugin_id => $definition) {
|
||||
if ($definition['type'] === FALSE || in_array($type, $definition['type'])) {
|
||||
$definitions[$plugin_id] = $definition;
|
||||
}
|
||||
}
|
||||
return $definitions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\ConstraintValidatorFactory.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ClassResolverInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidatorFactory as BaseConstraintValidatorFactory;
|
||||
|
||||
/**
|
||||
* Defines a constraint validator factory that works with container injection.
|
||||
*/
|
||||
class ConstraintValidatorFactory extends BaseConstraintValidatorFactory {
|
||||
|
||||
/**
|
||||
* Constructs a new ConstraintValidatorFactory.
|
||||
*
|
||||
* @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
|
||||
*/
|
||||
public function __construct(ClassResolverInterface $class_resolver) {
|
||||
$this->classResolver = $class_resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInstance(Constraint $constraint) {
|
||||
$class_name = $constraint->validatedBy();
|
||||
|
||||
if (!isset($this->validators[$class_name])) {
|
||||
$this->validators[$class_name] = $this->classResolver->getInstanceFromDefinition($class_name);
|
||||
}
|
||||
|
||||
return $this->validators[$class_name];
|
||||
}
|
||||
|
||||
}
|
92
core/lib/Drupal/Core/Validation/DrupalTranslator.php
Normal file
92
core/lib/Drupal/Core/Validation/DrupalTranslator.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\DrupalTranslator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Translates strings using Drupal's translation system.
|
||||
*
|
||||
* This class is used by the Symfony validator to translate violation messages.
|
||||
*/
|
||||
class DrupalTranslator implements TranslatorInterface {
|
||||
|
||||
/**
|
||||
* The locale used for translating.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $locale;
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Translation\TranslatorInterface::trans().
|
||||
*/
|
||||
public function trans($id, array $parameters = array(), $domain = NULL, $locale = NULL) {
|
||||
|
||||
return t($id, $this->processParameters($parameters), $this->getOptions($domain, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Translation\TranslatorInterface::transChoice().
|
||||
*/
|
||||
public function transChoice($id, $number, array $parameters = array(), $domain = NULL, $locale = NULL) {
|
||||
// Violation messages can separated singular and plural versions by "|".
|
||||
$ids = explode('|', $id);
|
||||
|
||||
if (!isset($ids[1])) {
|
||||
throw new \InvalidArgumentException(sprintf('The message "%s" cannot be pluralized, because it is missing a plural (e.g. "There is one apple|There are @count apples").', $id));
|
||||
}
|
||||
return \Drupal::translation()->formatPlural($number, $ids[0], $ids[1], $this->processParameters($parameters), $this->getOptions($domain, $locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Translation\TranslatorInterface::setLocale().
|
||||
*/
|
||||
public function setLocale($locale) {
|
||||
$this->locale = $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Translation\TranslatorInterface::getLocale().
|
||||
*/
|
||||
public function getLocale() {
|
||||
return $this->locale ? $this->locale : \Drupal::languageManager()->getCurrentLanguage()->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the parameters array for use with t().
|
||||
*/
|
||||
protected function processParameters(array $parameters) {
|
||||
$return = array();
|
||||
foreach ($parameters as $key => $value) {
|
||||
if (is_object($value)) {
|
||||
// t() does not work will objects being passed as replacement strings.
|
||||
}
|
||||
// Check for symfony replacement patterns in the form "{{ name }}".
|
||||
elseif (strpos($key, '{{ ') === 0 && strrpos($key, ' }}') == strlen($key) - 3) {
|
||||
// Transform it into a Drupal pattern using the format %name.
|
||||
$key = '%' . substr($key, 3, strlen($key) - 6);
|
||||
$return[$key] = $value;
|
||||
}
|
||||
else {
|
||||
$return[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns options suitable for use with t().
|
||||
*/
|
||||
protected function getOptions($domain = NULL, $locale = NULL) {
|
||||
// We do not support domains, so we ignore this parameter.
|
||||
// If locale is left NULL, t() will default to the interface language.
|
||||
$locale = isset($locale) ? $locale : $this->locale;
|
||||
return array('langcode' => $locale);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\AllowedValuesConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Choice;
|
||||
|
||||
/**
|
||||
* Checks for the value being allowed.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "AllowedValues",
|
||||
* label = @Translation("Allowed values", context = "Validation")
|
||||
* )
|
||||
*
|
||||
* @see \Drupal\Core\TypedData\OptionsProviderInterface
|
||||
*/
|
||||
class AllowedValuesConstraint extends Choice {
|
||||
|
||||
public $minMessage = 'You must select at least %limit choice.|You must select at least %limit choices.';
|
||||
public $maxMessage = 'You must select at most %limit choice.|You must select at most %limit choices.';
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\AllowedValuesConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\TypedData\OptionsProviderInterface;
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\ChoiceValidator;
|
||||
|
||||
/**
|
||||
* Validates the AllowedValues constraint.
|
||||
*/
|
||||
class AllowedValuesConstraintValidator extends ChoiceValidator implements ContainerInjectionInterface {
|
||||
|
||||
use TypedDataAwareValidatorTrait;
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static($container->get('current_user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new AllowedValuesConstraintValidator.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*/
|
||||
public function __construct(AccountInterface $current_user) {
|
||||
$this->currentUser = $current_user;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
$typed_data = $this->getTypedData();
|
||||
if ($typed_data instanceof OptionsProviderInterface) {
|
||||
$allowed_values = $typed_data->getSettableValues($this->currentUser);
|
||||
$constraint->choices = $allowed_values;
|
||||
|
||||
// If the data is complex, we have to validate its main property.
|
||||
if ($typed_data instanceof ComplexDataInterface) {
|
||||
$name = $typed_data->getDataDefinition()->getMainPropertyName();
|
||||
if (!isset($name)) {
|
||||
throw new \LogicException('Cannot validate allowed values for complex data without a main property.');
|
||||
}
|
||||
$value = $typed_data->get($name)->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
// The parent implementation ignores values that are not set, but makes
|
||||
// sure some choices are available firstly. However, we want to support
|
||||
// empty choices for undefined values, e.g. if a term reference field
|
||||
// points to an empty vocabulary.
|
||||
if (!isset($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::validate($value, $constraint);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\ComplexDataConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Complex data constraint.
|
||||
*
|
||||
* Validates properties of complex data structures.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "ComplexData",
|
||||
* label = @Translation("Complex data", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class ComplexDataConstraint extends Constraint {
|
||||
|
||||
/**
|
||||
* An array of constraints for contained properties, keyed by property name.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $properties;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($options = NULL) {
|
||||
// Allow skipping the 'properties' key in the options.
|
||||
if (is_array($options) && !array_key_exists('properties', $options)) {
|
||||
$options = array('properties' => $options);
|
||||
}
|
||||
parent::__construct($options);
|
||||
$constraint_manager = \Drupal::service('validation.constraint');
|
||||
|
||||
// Instantiate constraint objects for array definitions.
|
||||
foreach ($this->properties as &$constraints) {
|
||||
foreach ($constraints as $id => $options) {
|
||||
if (!is_object($options)) {
|
||||
$constraints[$id] = $constraint_manager->create($id, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOption() {
|
||||
return 'properties';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRequiredOptions() {
|
||||
return array('properties');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\ComplexDataConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\TypedDataInterface;
|
||||
use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||
|
||||
/**
|
||||
* Validates complex data.
|
||||
*/
|
||||
class ComplexDataConstraintValidator extends ConstraintValidator {
|
||||
|
||||
use TypedDataAwareValidatorTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($data, Constraint $constraint) {
|
||||
|
||||
// If un-wrapped data has been passed, fetch the typed data object first.
|
||||
if (!$data instanceof TypedDataInterface) {
|
||||
$data = $this->getTypedData();
|
||||
}
|
||||
if (!$data instanceof ComplexDataInterface) {
|
||||
throw new UnexpectedTypeException($data, 'ComplexData');
|
||||
}
|
||||
|
||||
foreach ($constraint->properties as $name => $constraints) {
|
||||
$this->context->getValidator()
|
||||
->inContext($this->context)
|
||||
// Specifically pass along FALSE as $root_call, as we validate the data
|
||||
// as part of the typed data tree.
|
||||
->validate($data->get($name), $constraints, NULL, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\CountConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Count;
|
||||
|
||||
/**
|
||||
* Count constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to use Drupal-style replacement patterns.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "Count",
|
||||
* label = @Translation("Count", context = "Validation"),
|
||||
* type = { "list" }
|
||||
* )
|
||||
*/
|
||||
class CountConstraint extends Count {
|
||||
|
||||
public $minMessage = 'This collection should contain %limit element or more.|This collection should contain %limit elements or more.';
|
||||
public $maxMessage = 'This collection should contain %limit element or less.|This collection should contain %limit elements or less.';
|
||||
public $exactMessage = 'This collection should contain exactly %limit element.|This collection should contain exactly %limit elements.';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Symfony\Component\Validator\Constraints\CountValidator';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\EmailConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Email;
|
||||
|
||||
/**
|
||||
* Count constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to use the strict setting.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "Email",
|
||||
* label = @Translation("Email", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class EmailConstraint extends Email {
|
||||
|
||||
public $strict = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Symfony\Component\Validator\Constraints\EmailValidator';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\IsNullConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\IsNull;
|
||||
|
||||
/**
|
||||
* Null constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to handle empty Typed Data structures.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "Null",
|
||||
* label = @Translation("Null", context = "Validation"),
|
||||
* type = false
|
||||
* )
|
||||
*/
|
||||
class IsNullConstraint extends IsNull { }
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\IsNullConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\ListInterface;
|
||||
use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\IsNullValidator;
|
||||
|
||||
/**
|
||||
* Null constraint validator.
|
||||
*
|
||||
* Overrides the symfony validator to handle empty Typed Data structures.
|
||||
*/
|
||||
class IsNullConstraintValidator extends IsNullValidator {
|
||||
|
||||
use TypedDataAwareValidatorTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
$typed_data = $this->getTypedData();
|
||||
if (($typed_data instanceof ListInterface || $typed_data instanceof ComplexDataInterface) && $typed_data->isEmpty()) {
|
||||
$value = NULL;
|
||||
}
|
||||
parent::validate($value, $constraint);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\LengthConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
|
||||
/**
|
||||
* Length constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to use Drupal-style replacement patterns.
|
||||
*
|
||||
* @todo: Move this below the TypedData core component.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "Length",
|
||||
* label = @Translation("Length", context = "Validation"),
|
||||
* type = { "string" }
|
||||
* )
|
||||
*/
|
||||
class LengthConstraint extends Length {
|
||||
|
||||
public $maxMessage = 'This value is too long. It should have %limit character or less.|This value is too long. It should have %limit characters or less.';
|
||||
public $minMessage = 'This value is too short. It should have %limit character or more.|This value is too short. It should have %limit characters or more.';
|
||||
public $exactMessage = 'This value should have exactly %limit character.|This value should have exactly %limit characters.';
|
||||
|
||||
/**
|
||||
* Overrides Range::validatedBy().
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Symfony\Component\Validator\Constraints\LengthValidator';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\NotNull;
|
||||
|
||||
/**
|
||||
* NotNull constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to handle empty Typed Data structures.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "NotNull",
|
||||
* label = @Translation("NotNull", context = "Validation"),
|
||||
* type = false
|
||||
* )
|
||||
*/
|
||||
class NotNullConstraint extends NotNull { }
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\NotNullConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\TypedData\ComplexDataInterface;
|
||||
use Drupal\Core\TypedData\ListInterface;
|
||||
use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\Constraints\NotNullValidator;
|
||||
|
||||
/**
|
||||
* NotNull constraint validator.
|
||||
*
|
||||
* Overrides the symfony validator to handle empty Typed Data structures.
|
||||
*/
|
||||
class NotNullConstraintValidator extends NotNullValidator {
|
||||
|
||||
use TypedDataAwareValidatorTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
$typed_data = $this->getTypedData();
|
||||
if (($typed_data instanceof ListInterface || $typed_data instanceof ComplexDataInterface) && $typed_data->isEmpty()) {
|
||||
$value = NULL;
|
||||
}
|
||||
parent::validate($value, $constraint);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
|
||||
/**
|
||||
* Supports validating all primitive types.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "PrimitiveType",
|
||||
* label = @Translation("Primitive type", context = "Validation")
|
||||
* )
|
||||
*/
|
||||
class PrimitiveTypeConstraint extends Constraint {
|
||||
|
||||
public $message = 'This value should be of the correct primitive type.';
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraintValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Drupal\Core\TypedData\Type\BinaryInterface;
|
||||
use Drupal\Core\TypedData\Type\BooleanInterface;
|
||||
use Drupal\Core\TypedData\Type\DateTimeInterface;
|
||||
use Drupal\Core\TypedData\Type\DurationInterface;
|
||||
use Drupal\Core\TypedData\Type\FloatInterface;
|
||||
use Drupal\Core\TypedData\Type\IntegerInterface;
|
||||
use Drupal\Core\TypedData\Type\StringInterface;
|
||||
use Drupal\Core\TypedData\Type\UriInterface;
|
||||
use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait;
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Validates the PrimitiveType constraint.
|
||||
*/
|
||||
class PrimitiveTypeConstraintValidator extends ConstraintValidator {
|
||||
|
||||
use TypedDataAwareValidatorTrait;
|
||||
|
||||
/**
|
||||
* Implements \Symfony\Component\Validator\ConstraintValidatorInterface::validate().
|
||||
*/
|
||||
public function validate($value, Constraint $constraint) {
|
||||
|
||||
if (!isset($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$typed_data = $this->getTypedData();
|
||||
$valid = TRUE;
|
||||
if ($typed_data instanceof BinaryInterface && !is_resource($value)) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
if ($typed_data instanceof BooleanInterface && !(is_bool($value) || $value === 0 || $value === '0' || $value === 1 || $value == '1')) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
if ($typed_data instanceof FloatInterface && filter_var($value, FILTER_VALIDATE_FLOAT) === FALSE) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
if ($typed_data instanceof IntegerInterface && filter_var($value, FILTER_VALIDATE_INT) === FALSE) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
if ($typed_data instanceof StringInterface && !is_scalar($value)) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
// Ensure that URIs comply with http://tools.ietf.org/html/rfc3986, which
|
||||
// requires:
|
||||
// - That it is well formed (parse_url() returns FALSE if not).
|
||||
// - That it contains a scheme (parse_url(, PHP_URL_SCHEME) returns NULL if
|
||||
// not).
|
||||
if ($typed_data instanceof UriInterface && in_array(parse_url($value, PHP_URL_SCHEME), [NULL, FALSE], TRUE)) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
// @todo: Move those to separate constraint validators.
|
||||
try {
|
||||
if ($typed_data instanceof DateTimeInterface && $typed_data->getDateTime() && $typed_data->getDateTime()->hasErrors()) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
if ($typed_data instanceof DurationInterface && $typed_data->getDuration() && !($typed_data->getDuration() instanceof \DateInterval)) {
|
||||
$valid = FALSE;
|
||||
}
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// Invalid durations or dates might throw exceptions.
|
||||
$valid = FALSE;
|
||||
}
|
||||
|
||||
if (!$valid) {
|
||||
// @todo: Provide a good violation message for each problem.
|
||||
$this->context->addViolation($constraint->message, array(
|
||||
'%value' => is_object($value) ? get_class($value) : (is_array($value) ? 'Array' : (string) $value)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\RangeConstraint.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraints\Range;
|
||||
|
||||
/**
|
||||
* Range constraint.
|
||||
*
|
||||
* Overrides the symfony constraint to use Drupal-style replacement patterns.
|
||||
*
|
||||
* @todo: Move this below the TypedData core component.
|
||||
*
|
||||
* @Constraint(
|
||||
* id = "Range",
|
||||
* label = @Translation("Range", context = "Validation"),
|
||||
* type = { "integer", "float" }
|
||||
* )
|
||||
*/
|
||||
class RangeConstraint extends Range {
|
||||
|
||||
public $minMessage = 'This value should be %limit or more.';
|
||||
public $maxMessage = 'This value should be %limit or less.';
|
||||
|
||||
/**
|
||||
* Overrides Range::validatedBy().
|
||||
*/
|
||||
public function validatedBy() {
|
||||
return '\Symfony\Component\Validator\Constraints\RangeValidator';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Validation\Plugin\Validation\Constraint\UniqueFieldValueValidator.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Validation\Plugin\Validation\Constraint;
|
||||
|
||||
use Symfony\Component\Validator\Constraint;
|
||||
use Symfony\Component\Validator\ConstraintValidator;
|
||||
|
||||
/**
|
||||
* Validates that a field is unique for the given entity type.
|
||||
*/
|
||||
class UniqueFieldValueValidator extends ConstraintValidator {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate($items, Constraint $constraint) {
|
||||
if (!$item = $items->first()) {
|
||||
return;
|
||||
}
|
||||
$field_name = $items->getFieldDefinition()->getName();
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $entity */
|
||||
$entity = $items->getEntity();
|
||||
$entity_type_id = $entity->getEntityTypeId();
|
||||
$id_key = $entity->getEntityType()->getKey('id');
|
||||
|
||||
$value_taken = (bool) \Drupal::entityQuery($entity_type_id)
|
||||
// The id could be NULL, so we cast it to 0 in that case.
|
||||
->condition($id_key, (int) $items->getEntity()->id(), '<>')
|
||||
->condition($field_name, $item->value)
|
||||
->range(0, 1)
|
||||
->count()
|
||||
->execute();
|
||||
|
||||
if ($value_taken) {
|
||||
$this->context->addViolation($constraint->message, array("%value" => $item->value));
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue