Issue #3377030 by Wim Leers, borisson_, smustgrave: Add validation constraint to `type: label`: disallow multiple lines
parent
4cb10842ee
commit
b7ee3dcfce
|
@ -62,6 +62,15 @@ label:
|
|||
type: string
|
||||
label: 'Label'
|
||||
translatable: true
|
||||
constraints:
|
||||
Regex:
|
||||
# Forbid any kind of line ending:
|
||||
# - Windows: `\r\n`
|
||||
# - old macOS: `\r`
|
||||
# - *nix: `\n`
|
||||
pattern: '/(\r\n|\r|\n)/'
|
||||
match: false
|
||||
message: 'Labels are not allowed to span multiple lines.'
|
||||
|
||||
# String containing plural variants, separated by EXT.
|
||||
plural_label:
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\Tests\block\Kernel;
|
||||
|
||||
use Drupal\block\Entity\Block;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
|
||||
/**
|
||||
|
@ -27,6 +28,9 @@ class BlockValidationTest extends ConfigEntityValidationTestBase {
|
|||
'id' => 'test_block',
|
||||
'theme' => 'stark',
|
||||
'plugin' => 'system_powered_by_block',
|
||||
'settings' => [
|
||||
'label' => 'Powered by Drupal 🚀',
|
||||
],
|
||||
]);
|
||||
$this->entity->save();
|
||||
}
|
||||
|
@ -62,4 +66,27 @@ class BlockValidationTest extends ConfigEntityValidationTestBase {
|
|||
return $cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static function setLabel(ConfigEntityInterface $block, string $label): void {
|
||||
static::assertInstanceOf(Block::class, $block);
|
||||
$settings = $block->get('settings');
|
||||
static::assertNotEmpty($settings['label']);
|
||||
$settings['label'] = $label;
|
||||
$block->set('settings', $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testLabelValidation(): void {
|
||||
static::setLabel($this->entity, "Multi\nLine");
|
||||
// TRICKY: because the Block config entity type does not specify a `label`
|
||||
// key, it is impossible for the generic ::testLabelValidation()
|
||||
// implementation in the base class to know at which property to expect a
|
||||
// validation error. Hence it is hardcoded in this case.
|
||||
$this->assertValidationErrors(['settings.label' => "Labels are not allowed to span multiple lines."]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ contact.form.*:
|
|||
type: integer
|
||||
label: 'Weight'
|
||||
message:
|
||||
type: label
|
||||
type: text
|
||||
label: 'Message displayed to user on submission'
|
||||
redirect:
|
||||
type: path
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Drupal\Tests\contact\Kernel;
|
||||
|
||||
use Drupal\contact\ContactFormInterface;
|
||||
use Drupal\contact\Entity\ContactForm;
|
||||
use Drupal\KernelTests\Core\Config\ConfigEntityValidationTestBase;
|
||||
|
||||
|
@ -30,4 +31,14 @@ class ContactFormValidationTest extends ConfigEntityValidationTestBase {
|
|||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validation of message.
|
||||
*/
|
||||
public function testMessageValidation(): void {
|
||||
assert($this->entity instanceof ContactFormInterface);
|
||||
// Messages should be able to span multiple lines.
|
||||
$this->entity->setMessage("Multi\nLine");
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -70,4 +70,13 @@ class EditorValidationTest extends ConfigEntityValidationTestBase {
|
|||
$this->assertValidationErrors(['editor' => "The 'non_existent' plugin does not exist."]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testLabelValidation(): void {
|
||||
// @todo Remove this override in https://www.drupal.org/i/3231354. The label of Editor entities is dynamically computed: it's retrieved from the associated FilterFormat entity. That issue will change this.
|
||||
// @see \Drupal\editor\Entity\Editor::label()
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Drupal\Tests\field\Kernel\Entity;
|
||||
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests validation of field_config entities.
|
||||
|
@ -53,4 +54,36 @@ class FieldConfigValidationTest extends FieldStorageConfigValidationTest {
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validation of a field_config's default value.
|
||||
*/
|
||||
public function testMultilineTextFieldDefaultValue(): void {
|
||||
// First, create a field storage for which a complex default value exists.
|
||||
$this->enableModules(['text']);
|
||||
$text_field_storage_config = FieldStorageConfig::create([
|
||||
'type' => 'text_with_summary',
|
||||
'field_name' => 'novel',
|
||||
'entity_type' => 'user',
|
||||
]);
|
||||
$text_field_storage_config->save();
|
||||
|
||||
$this->entity = FieldConfig::create([
|
||||
'field_storage' => $text_field_storage_config,
|
||||
'bundle' => 'user',
|
||||
'default_value' => [
|
||||
0 => [
|
||||
'value' => "Multi\nLine",
|
||||
'summary' => '',
|
||||
'format' => 'basic_html',
|
||||
],
|
||||
],
|
||||
'dependencies' => [
|
||||
'config' => [
|
||||
$text_field_storage_config->getConfigDependencyName(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class FieldStorageConfigValidationTest extends ConfigEntityValidationTestBase {
|
|||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->installEntitySchema('user');
|
||||
|
||||
$this->entity = FieldStorageConfig::create([
|
||||
'type' => 'boolean',
|
||||
|
|
|
@ -17,6 +17,11 @@ class ContentLanguageSettingsValidationTest extends ConfigEntityValidationTestBa
|
|||
*/
|
||||
protected static $modules = ['language', 'user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected bool $hasLabel = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -39,4 +39,13 @@ class LayoutBuilderEntityViewDisplayValidationTest extends ConfigEntityValidatio
|
|||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function testLabelValidation(): void {
|
||||
// @todo Remove this override in https://www.drupal.org/i/2939931. The label of Layout Builder's EntityViewDisplay override is computed dynamically, that issue will change this.
|
||||
// @see \Drupal\layout_builder\Entity\LayoutBuilderEntityViewDisplay::label()
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@ class RestResourceConfigValidationTest extends ConfigEntityValidationTestBase {
|
|||
*/
|
||||
protected static $modules = ['rest', 'serialization'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected bool $hasLabel = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
|
|
@ -138,7 +138,7 @@ field.widget.settings.text_textarea_with_summary:
|
|||
type: integer
|
||||
label: 'Number of summary rows'
|
||||
placeholder:
|
||||
type: label
|
||||
type: text
|
||||
label: 'Placeholder'
|
||||
show_summary:
|
||||
type: boolean
|
||||
|
|
|
@ -30,6 +30,20 @@ abstract class ConfigEntityValidationTestBase extends KernelTestBase {
|
|||
*/
|
||||
protected ConfigEntityInterface $entity;
|
||||
|
||||
/**
|
||||
* Whether a config entity of this type has a label.
|
||||
*
|
||||
* Most config entity types ensure their entities have a label. But a few do
|
||||
* not, typically highly abstract/very low level config entities without a
|
||||
* strong UI presence. For example: REST resource configuration entities and
|
||||
* entity view displays.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::label()
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $hasLabel = TRUE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -288,6 +302,44 @@ abstract class ConfigEntityValidationTestBase extends KernelTestBase {
|
|||
$this->assertValidationErrors($expected_enforced_messages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validation of config entity's label.
|
||||
*
|
||||
* @see \Drupal\Core\Entity\EntityInterface::label()
|
||||
* @see \Drupal\Core\Entity\EntityBase::label()
|
||||
*/
|
||||
public function testLabelValidation(): void {
|
||||
// Some entity types do not have a label.
|
||||
if (!$this->hasLabel) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
if ($this->entity->getEntityType()->getKey('label') === $this->entity->getEntityType()->getKey('id')) {
|
||||
$this->markTestSkipped('This entity type uses the ID as the label; an entity without a label is hence impossible.');
|
||||
}
|
||||
|
||||
static::setLabel($this->entity, "Multi\nLine");
|
||||
$this->assertValidationErrors([$this->entity->getEntityType()->getKey('label') => "Labels are not allowed to span multiple lines."]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the label of the given config entity.
|
||||
*
|
||||
* @param \Drupal\Core\Config\Entity\ConfigEntityInterface $entity
|
||||
* The config entity to modify.
|
||||
* @param string $label
|
||||
* The label to set.
|
||||
*
|
||||
* @see ::testLabelValidation()
|
||||
*/
|
||||
protected static function setLabel(ConfigEntityInterface $entity, string $label): void {
|
||||
$label_property = $entity->getEntityType()->getKey('label');
|
||||
if ($label_property === FALSE) {
|
||||
throw new \LogicException(sprintf('Override %s to allow testing a %s without a label.', __METHOD__, (string) $entity->getEntityType()->getSingularLabel()));
|
||||
}
|
||||
|
||||
$entity->set($label_property, $label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts a set of validation errors is raised when the entity is validated.
|
||||
*
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
namespace Drupal\KernelTests\Core\Entity;
|
||||
|
||||
use Drupal\Core\Entity\Display\EntityFormDisplayInterface;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\field\Entity\FieldStorageConfig;
|
||||
|
||||
/**
|
||||
* Tests validation of entity_form_display entities.
|
||||
|
@ -12,6 +15,11 @@ use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
|||
*/
|
||||
class EntityFormDisplayValidationTest extends EntityFormModeValidationTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected bool $hasLabel = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -19,7 +27,6 @@ class EntityFormDisplayValidationTest extends EntityFormModeValidationTest {
|
|||
parent::setUp();
|
||||
|
||||
$this->entity = EntityFormDisplay::create([
|
||||
'label' => 'Test',
|
||||
'targetEntityType' => 'user',
|
||||
'bundle' => 'user',
|
||||
// The mode was created by the parent class.
|
||||
|
@ -28,4 +35,45 @@ class EntityFormDisplayValidationTest extends EntityFormModeValidationTest {
|
|||
$this->entity->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests validation of entity form display component's widget settings.
|
||||
*/
|
||||
public function testMultilineTextFieldWidgetPlaceholder(): void {
|
||||
// First, create a field for which widget settings exist.
|
||||
$this->enableModules(['field', 'text']);
|
||||
$text_field_storage_config = FieldStorageConfig::create([
|
||||
'type' => 'text_with_summary',
|
||||
'field_name' => 'novel',
|
||||
'entity_type' => 'user',
|
||||
]);
|
||||
$text_field_storage_config->save();
|
||||
|
||||
$text_field_config = FieldConfig::create([
|
||||
'field_storage' => $text_field_storage_config,
|
||||
'bundle' => 'user',
|
||||
'dependencies' => [
|
||||
'config' => [
|
||||
$text_field_storage_config->getConfigDependencyName(),
|
||||
],
|
||||
],
|
||||
]);
|
||||
$text_field_config->save();
|
||||
|
||||
// Then, configure a form display widget for this field.
|
||||
assert($this->entity instanceof EntityFormDisplayInterface);
|
||||
$this->entity->setComponent('novel', [
|
||||
'type' => 'text_textarea_with_summary',
|
||||
'region' => 'content',
|
||||
'settings' => [
|
||||
'rows' => 9,
|
||||
'summary_rows' => 3,
|
||||
'placeholder' => "Multi\nLine",
|
||||
'show_summary' => FALSE,
|
||||
],
|
||||
'third_party_settings' => [],
|
||||
]);
|
||||
|
||||
$this->assertValidationErrors([]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
|||
*/
|
||||
class EntityViewDisplayValidationTest extends EntityViewModeValidationTest {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected bool $hasLabel = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -19,7 +24,6 @@ class EntityViewDisplayValidationTest extends EntityViewModeValidationTest {
|
|||
parent::setUp();
|
||||
|
||||
$this->entity = EntityViewDisplay::create([
|
||||
'label' => 'Test',
|
||||
'targetEntityType' => 'user',
|
||||
'bundle' => 'user',
|
||||
// The mode was created by the parent class.
|
||||
|
|
Loading…
Reference in New Issue