diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php index d2b1741a3a..993d5ec998 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/UniqueFieldValueValidator.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Validation\Plugin\Validation\Constraint; +use Drupal\Core\Field\FieldItemListInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -17,6 +18,29 @@ public function validate($items, Constraint $constraint) { if (!$item = $items->first()) { return; } + $value_taken = (bool) $this->getEntityQuery($items)->execute(); + + if ($value_taken) { + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = $items->getEntity(); + $this->context->addViolation($constraint->message, [ + '%value' => $item->value, + '@entity_type' => $entity->getEntityType()->getSingularLabel(), + '@field_name' => mb_strtolower($items->getFieldDefinition()->getLabel()), + ]); + } + } + + /** + * Gets the entity query to determine if the value is unique. + * + * @param \Drupal\Core\Field\FieldItemListInterface $items + * The field item list. + * + * @return \Drupal\Core\Entity\Query\QueryInterface + * The entity query. + */ + protected function getEntityQuery(FieldItemListInterface $items) { $field_name = $items->getFieldDefinition()->getName(); /** @var \Drupal\Core\Entity\EntityInterface $entity */ $entity = $items->getEntity(); @@ -31,20 +55,11 @@ public function validate($items, Constraint $constraint) { if (isset($entity_id)) { $query->condition($id_key, $entity_id, '<>'); } - - $value_taken = (bool) $query - ->condition($field_name, $item->value) + $query + ->condition($field_name, $items->first()->value) ->range(0, 1) - ->count() - ->execute(); - - if ($value_taken) { - $this->context->addViolation($constraint->message, [ - '%value' => $item->value, - '@entity_type' => $entity->getEntityType()->getSingularLabel(), - '@field_name' => mb_strtolower($items->getFieldDefinition()->getLabel()), - ]); - } + ->count(); + return $query; } } diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php index 95ba40da6d..b36d2ebab7 100644 --- a/core/modules/block_content/src/Entity/BlockContent.php +++ b/core/modules/block_content/src/Entity/BlockContent.php @@ -204,7 +204,7 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) { 'weight' => -5, ]) ->setDisplayConfigurable('form', TRUE) - ->addConstraint('UniqueField', []); + ->addConstraint('UniqueBlockContentLabel', []); $fields['changed'] = BaseFieldDefinition::create('changed') ->setLabel(t('Changed')) diff --git a/core/modules/block_content/src/Plugin/Validation/Constraint/UniqueBlockContentLabel.php b/core/modules/block_content/src/Plugin/Validation/Constraint/UniqueBlockContentLabel.php new file mode 100644 index 0000000000..48aa3ce58c --- /dev/null +++ b/core/modules/block_content/src/Plugin/Validation/Constraint/UniqueBlockContentLabel.php @@ -0,0 +1,24 @@ +getValue(); + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = $items->getEntity(); + if ($entity->getEntityTypeId() !== 'block_content') { + throw new \InvalidArgumentException("The UniqueBlockContentLabelValueValidator can only be used with entities of the type block_content. {$entity->getEntityTypeId()} provided"); + } + parent::initialize($context); + } + + /** + * {@inheritdoc} + */ + public function validate($items, Constraint $constraint) { + /** @var \Drupal\Core\Entity\EntityInterface $entity */ + $entity = $items->getEntity(); + + // Validate only if block is reusable. + if (!$entity->isReusable()) { + return; + } + + parent::validate($items, $constraint); + } + + /** + * @inheritDoc + */ + protected function getEntityQuery(FieldItemListInterface $items) { + $query = parent::getEntityQuery($items); + $query->condition('reusable', 1); + return $query; + } + + +} diff --git a/core/modules/block_content/tests/src/Functional/BlockContentValidationTest.php b/core/modules/block_content/tests/src/Functional/BlockContentValidationTest.php index 41a22d3d56..1d52fb3945 100644 --- a/core/modules/block_content/tests/src/Functional/BlockContentValidationTest.php +++ b/core/modules/block_content/tests/src/Functional/BlockContentValidationTest.php @@ -42,4 +42,27 @@ public function testValidation() { $this->assertEqual(new FormattableMarkup('A custom block with block description %value already exists.', ['%value' => $block->label()]), $violations[0]->getMessage()); } + /** + * Tests block label validation. + */ + public function testLabelValidation() { + $block = $this->createBlockContent('foo', 'basic'); + $block->setNonReusable(); + $block->save(); + + $block2 = $this->createBlockContent('foo', 'basic'); + + $violations = $block2->validate(); + // Make sure we have no violations. + $this->assertCount(0, $violations); + + $block2->save(); + + $block3 = $this->createBlockContent('foo', 'basic'); + $violations = $block3->validate(); + // Make sure we have 1 violation. + $this->assertCount(1, $violations); + $this->assertEquals('info', $violations[0]->getPropertyPath()); + } + }