Skip to content
Snippets Groups Projects
Commit 578a7ba1 authored by catch's avatar catch
Browse files

Issue #2002174 by Wim Leers, xjm, fago, effulgentsia, catch, smustgrave: Allow...

Issue #2002174 by Wim Leers, xjm, fago, effulgentsia, catch, smustgrave: Allow vocabularies to be validated via the API, not just during form submissions

(cherry picked from commit 1be0f07e)
parent d95dc67e
No related branches found
Tags 8.x-1.0-alpha2
26 merge requests!11185Issue #3477324 by andypost, alexpott: Fix usage of str_getcsv() and fgetcsv() for PHP 8.4,!10602Issue #3438769 by vinmayiswamy, antonnavi, michelle, amateescu: Sub workspace does not clear,!10301Issue #3469309 by mstrelan, smustgrave, moshe weitzman: Use one-time login...,!10187Issue #3487488 by dakwamine: ExtensionMimeTypeGuesser::guessMimeType must support file names with "0" (zero) like foo.0.zip,!9944Issue #3483353: Consider making the createCopy config action optionally fail...,!9929Issue #3445469 by pooja_sharma, smustgrave: Add additional test coverage for...,!9787Resolve issue 3479427 - bootstrap barrio issue under Windows,!9742Issue #3463908 by catch, quietone: Split OptionsFieldUiTest into two,!9526Issue #3458177 by mondrake, catch, quietone, godotislate, longwave, larowlan,...,!8738Issue #3424162 by camilledavis, dineshkumarbollu, smustgrave: Claro...,!8704Make greek characters available in ckeditor5,!8597Draft: Issue #3442259 by catch, quietone, dww: Reduce time of Migrate Upgrade tests...,!8533Issue #3446962 by kim.pepper: Remove incorrectly added...,!8517Issue #3443748 by NexusNovaz, smustgrave: Testcase creates false positive,!8325Update file Sort.php,!8095Expose document root on install,!7930Resolve #3427374 "Taxonomytid viewsargumentdefault plugin",!7627Issue #3439440 by nicxvan, Binoli Lalani, longwave: Remove country support from DateFormatter,!7445Issue #3440169: When using drupalGet(), provide an associative array for $headers,!7401#3271894 Fix documented StreamWrapperInterface return types for realpath() and dirname(),!7384Add constraints to system.advisories,!7078Issue #3320569 by Spokje, mondrake, smustgrave, longwave, quietone, Lendude,...,!6622Issue #2559833 by piggito, mohit_aghera, larowlan, guptahemant, vakulrai,...,!6502Draft: Resolve #2938524 "Plach testing issue",!38582585169-10.1.x,!3226Issue #2987537: Custom menu link entity type should not declare "bundle" entity key
Pipeline #104332 passed
+1
Showing
with 175 additions and 13 deletions
......@@ -1323,3 +1323,18 @@ function node_comment_delete($comment) {
function node_config_translation_info_alter(&$info) {
$info['node_type']['class'] = 'Drupal\node\ConfigTranslation\NodeTypeMapper';
}
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function node_node_type_presave(NodeTypeInterface $node_type) {
// Content types' `help` and `description` fields must be stored as NULL
// at the config level if they are empty.
// @see node_post_update_set_node_type_description_and_help_to_null()
if (trim($node_type->getDescription()) === '') {
$node_type->set('description', NULL);
}
if (trim($node_type->getHelp()) === '') {
$node_type->set('help', NULL);
}
}
......@@ -14,15 +14,8 @@
function node_post_update_set_node_type_description_and_help_to_null(array &$sandbox): void {
\Drupal::classResolver(ConfigEntityUpdater::class)
->update($sandbox, 'node_type', function (NodeTypeInterface $node_type): bool {
// Content types' `help` and `description` fields must be stored as NULL
// at the config level if they are empty.
if (trim($node_type->getDescription()) === '') {
$node_type->set('description', NULL);
}
if (trim($node_type->getHelp()) === '') {
$node_type->set('help', NULL);
}
return TRUE;
// @see node_node_type_presave()
return trim($node_type->getDescription()) === '' || trim($node_type->getHelp()) === '';
});
}
......
......@@ -22,6 +22,8 @@ taxonomy.settings:
taxonomy.vocabulary.*:
type: config_entity
label: 'Vocabulary'
constraints:
FullyValidatable: ~
mapping:
name:
type: required_label
......@@ -35,11 +37,18 @@ taxonomy.vocabulary.*:
Length:
max: 32
description:
type: label
type: text
label: 'Description'
nullable: true
constraints:
NotBlank:
allowNull: true
weight:
type: integer
label: 'Weight'
# A weight can be any integer, positive or negative.
constraints:
NotNull: []
new_revision:
type: boolean
label: 'Whether a new revision should be created by default'
......
......@@ -80,9 +80,9 @@ class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
/**
* Description of the vocabulary.
*
* @var string
* @var string|null
*/
protected $description;
protected $description = NULL;
/**
* The weight of this vocabulary in relation to other vocabularies.
......@@ -102,7 +102,7 @@ public function id() {
* {@inheritdoc}
*/
public function getDescription() {
return $this->description;
return $this->description ?? '';
}
/**
......
<?php
declare(strict_types=1);
namespace Drupal\taxonomy\Plugin\migrate\destination;
use Drupal\migrate\Plugin\migrate\destination\EntityConfigBase;
use Drupal\migrate\Row;
/**
* @MigrateDestination(
* id = "entity:taxonomy_vocabulary"
* )
*/
class EntityTaxonomyVocabulary extends EntityConfigBase {
/**
* {@inheritdoc}
*/
public function getEntity(Row $row, array $old_destination_id_values) {
/** @var \Drupal\taxonomy\VocabularyInterface $vocabulary */
$vocabulary = parent::getEntity($row, $old_destination_id_values);
// Config schema does not allow description to be empty.
if (trim($vocabulary->getDescription()) === '') {
$vocabulary->set('description', NULL);
}
return $vocabulary;
}
}
......@@ -42,6 +42,21 @@ public static function create(ContainerInterface $container) {
);
}
/**
* {@inheritdoc}
*/
public function buildEntity(array $form, FormStateInterface $form_state) {
/** @var \Drupal\taxonomy\VocabularyInterface $entity */
$entity = parent::buildEntity($form, $form_state);
// The description cannot be an empty string.
if (trim($form_state->getValue('description')) === '') {
$entity->set('description', NULL);
}
return $entity;
}
/**
* {@inheritdoc}
*/
......
......@@ -11,6 +11,7 @@
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\VocabularyInterface;
/**
* Implements hook_help().
......@@ -279,3 +280,15 @@ function taxonomy_taxonomy_term_delete(Term $term) {
/**
* @} End of "defgroup taxonomy_index".
*/
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function taxonomy_taxonomy_vocabulary_presave(VocabularyInterface $vocabulary) {
// Vocabularies' `description` field must be stored as NULL at the config
// level if it is empty.
// @see taxonomy_post_update_set_vocabulary_description_to_null()
if (trim($vocabulary->getDescription()) === '') {
$vocabulary->set('description', NULL);
}
}
......@@ -6,6 +6,7 @@
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\taxonomy\VocabularyInterface;
/**
* Implements hook_removed_post_updates().
......@@ -31,3 +32,14 @@ function taxonomy_post_update_set_new_revision(&$sandbox = NULL) {
return TRUE;
});
}
/**
* Converts empty `description` in vocabularies to NULL.
*/
function taxonomy_post_update_set_vocabulary_description_to_null(array &$sandbox): void {
\Drupal::classResolver(ConfigEntityUpdater::class)
->update($sandbox, 'taxonomy_vocabulary', function (VocabularyInterface $vocabulary): bool {
// @see taxonomy_taxonomy_vocabulary_presave()
return trim($vocabulary->getDescription()) === '';
});
}
<?php
/**
* @file
* Empties the description of the `tags` vocabulary.
*/
use Drupal\Core\Database\Database;
$connection = Database::getConnection();
$data = $connection->select('config')
->condition('name', 'taxonomy.vocabulary.tags')
->fields('config', ['data'])
->execute()
->fetchField();
$data = unserialize($data);
$data['description'] = "\n";
$connection->update('config')
->condition('name', 'taxonomy.vocabulary.tags')
->fields([
'data' => serialize($data),
])
->execute();
<?php
declare(strict_types=1);
namespace Drupal\Tests\taxonomy\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests the upgrade path for making vocabularies' description NULL.
*
* @group taxonomy
* @see taxonomy_post_update_set_vocabulary_description_to_null()
*/
class NullDescriptionTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-9.4.0.filled.standard.php.gz',
__DIR__ . '/../../../fixtures/update/remove-description-from-tags-vocabulary.php',
];
}
/**
* Tests the upgrade path for updating empty description to NULL.
*/
public function testRunUpdates(): void {
$vocabulary = Vocabulary::load('tags');
$this->assertInstanceOf(Vocabulary::class, $vocabulary);
$this->assertSame("\n", $vocabulary->get('description'));
$this->runUpdates();
$vocabulary = Vocabulary::load('tags');
$this->assertInstanceOf(Vocabulary::class, $vocabulary);
$this->assertNull($vocabulary->get('description'));
$this->assertSame('', $vocabulary->getDescription());
}
}
......@@ -12,6 +12,11 @@
*/
class VocabularyValidationTest extends ConfigEntityValidationTestBase {
/**
* {@inheritdoc}
*/
protected static array $propertiesWithOptionalValues = ['description'];
/**
* {@inheritdoc}
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment