Issue #2957381 by amateescu, GaëlG, alexpott, douggreen, jibran, catch: Data model problems with Vocabulary hierarchy
parent
9444c6a26a
commit
70e40101ec
|
@ -7,5 +7,4 @@ dependencies:
|
||||||
name: Forums
|
name: Forums
|
||||||
vid: forums
|
vid: forums
|
||||||
description: 'Forum navigation vocabulary'
|
description: 'Forum navigation vocabulary'
|
||||||
hierarchy: 1
|
|
||||||
weight: -10
|
weight: -10
|
||||||
|
|
|
@ -27,9 +27,6 @@ taxonomy.vocabulary.*:
|
||||||
description:
|
description:
|
||||||
type: label
|
type: label
|
||||||
label: 'Description'
|
label: 'Description'
|
||||||
hierarchy:
|
|
||||||
type: integer
|
|
||||||
label: 'Hierarchy'
|
|
||||||
weight:
|
weight:
|
||||||
type: integer
|
type: integer
|
||||||
label: 'Weight'
|
label: 'Weight'
|
||||||
|
|
|
@ -25,7 +25,6 @@ process:
|
||||||
label: name
|
label: name
|
||||||
name: name
|
name: name
|
||||||
description: description
|
description: description
|
||||||
hierarchy: hierarchy
|
|
||||||
weight: weight
|
weight: weight
|
||||||
destination:
|
destination:
|
||||||
plugin: entity:taxonomy_vocabulary
|
plugin: entity:taxonomy_vocabulary
|
||||||
|
|
|
@ -23,7 +23,6 @@ process:
|
||||||
label: name
|
label: name
|
||||||
name: name
|
name: name
|
||||||
description: description
|
description: description
|
||||||
hierarchy: hierarchy
|
|
||||||
weight: weight
|
weight: weight
|
||||||
destination:
|
destination:
|
||||||
plugin: entity:taxonomy_vocabulary
|
plugin: entity:taxonomy_vocabulary
|
||||||
|
|
|
@ -53,7 +53,6 @@ use Drupal\taxonomy\VocabularyInterface;
|
||||||
* "name",
|
* "name",
|
||||||
* "vid",
|
* "vid",
|
||||||
* "description",
|
* "description",
|
||||||
* "hierarchy",
|
|
||||||
* "weight",
|
* "weight",
|
||||||
* }
|
* }
|
||||||
* )
|
* )
|
||||||
|
@ -81,18 +80,6 @@ class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
|
||||||
*/
|
*/
|
||||||
protected $description;
|
protected $description;
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of hierarchy allowed within the vocabulary.
|
|
||||||
*
|
|
||||||
* Possible values:
|
|
||||||
* - VocabularyInterface::HIERARCHY_DISABLED: No parents.
|
|
||||||
* - VocabularyInterface::HIERARCHY_SINGLE: Single parent.
|
|
||||||
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
|
||||||
*
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $hierarchy = VocabularyInterface::HIERARCHY_DISABLED;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The weight of this vocabulary in relation to other vocabularies.
|
* The weight of this vocabulary in relation to other vocabularies.
|
||||||
*
|
*
|
||||||
|
@ -104,14 +91,16 @@ class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getHierarchy() {
|
public function getHierarchy() {
|
||||||
return $this->hierarchy;
|
@trigger_error('\Drupal\taxonomy\VocabularyInterface::getHierarchy() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.x. Use \Drupal\taxonomy\TermStorage::getVocabularyHierarchyType() instead.', E_USER_DEPRECATED);
|
||||||
|
return $this->entityTypeManager()->getStorage('taxonomy_term')->getVocabularyHierarchyType($this->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function setHierarchy($hierarchy) {
|
public function setHierarchy($hierarchy) {
|
||||||
$this->hierarchy = $hierarchy;
|
@trigger_error('\Drupal\taxonomy\VocabularyInterface::setHierarchy() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.x. Reset the cache of the taxonomy_term storage controller instead.', E_USER_DEPRECATED);
|
||||||
|
$this->entityTypeManager()->getStorage('taxonomy_term')->resetCache();
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,7 @@ class OverviewTerms extends FormBase {
|
||||||
global $pager_page_array, $pager_total, $pager_total_items;
|
global $pager_page_array, $pager_total, $pager_total_items;
|
||||||
|
|
||||||
$form_state->set(['taxonomy', 'vocabulary'], $taxonomy_vocabulary);
|
$form_state->set(['taxonomy', 'vocabulary'], $taxonomy_vocabulary);
|
||||||
|
$vocabulary_hierarchy = $this->storageController->getVocabularyHierarchyType($taxonomy_vocabulary->id());
|
||||||
$parent_fields = FALSE;
|
$parent_fields = FALSE;
|
||||||
|
|
||||||
$page = $this->getRequest()->query->get('page') ?: 0;
|
$page = $this->getRequest()->query->get('page') ?: 0;
|
||||||
|
@ -277,7 +278,7 @@ class OverviewTerms extends FormBase {
|
||||||
'#title' => $term->getName(),
|
'#title' => $term->getName(),
|
||||||
'#url' => $term->urlInfo(),
|
'#url' => $term->urlInfo(),
|
||||||
];
|
];
|
||||||
if ($taxonomy_vocabulary->getHierarchy() != VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) {
|
if ($vocabulary_hierarchy != VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) {
|
||||||
$parent_fields = TRUE;
|
$parent_fields = TRUE;
|
||||||
$form['terms'][$key]['term']['tid'] = [
|
$form['terms'][$key]['term']['tid'] = [
|
||||||
'#type' => 'hidden',
|
'#type' => 'hidden',
|
||||||
|
@ -384,7 +385,7 @@ class OverviewTerms extends FormBase {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($taxonomy_vocabulary->getHierarchy() !== VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) && $change_weight_access->isAllowed()) {
|
if (($vocabulary_hierarchy !== VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) && $change_weight_access->isAllowed()) {
|
||||||
$form['actions'] = ['#type' => 'actions', '#tree' => FALSE];
|
$form['actions'] = ['#type' => 'actions', '#tree' => FALSE];
|
||||||
$form['actions']['submit'] = [
|
$form['actions']['submit'] = [
|
||||||
'#type' => 'submit',
|
'#type' => 'submit',
|
||||||
|
@ -425,9 +426,6 @@ class OverviewTerms extends FormBase {
|
||||||
uasort($form_state->getValue('terms'), ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
uasort($form_state->getValue('terms'), ['Drupal\Component\Utility\SortArray', 'sortByWeightElement']);
|
||||||
|
|
||||||
$vocabulary = $form_state->get(['taxonomy', 'vocabulary']);
|
$vocabulary = $form_state->get(['taxonomy', 'vocabulary']);
|
||||||
// Update the current hierarchy type as we go.
|
|
||||||
$hierarchy = VocabularyInterface::HIERARCHY_DISABLED;
|
|
||||||
|
|
||||||
$changed_terms = [];
|
$changed_terms = [];
|
||||||
$tree = $this->storageController->loadTree($vocabulary->id(), 0, NULL, TRUE);
|
$tree = $this->storageController->loadTree($vocabulary->id(), 0, NULL, TRUE);
|
||||||
|
|
||||||
|
@ -444,7 +442,6 @@ class OverviewTerms extends FormBase {
|
||||||
$changed_terms[$term->id()] = $term;
|
$changed_terms[$term->id()] = $term;
|
||||||
}
|
}
|
||||||
$weight++;
|
$weight++;
|
||||||
$hierarchy = $term->parents[0] != 0 ? VocabularyInterface::HIERARCHY_SINGLE : $hierarchy;
|
|
||||||
$term = $tree[$weight];
|
$term = $tree[$weight];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,7 +468,6 @@ class OverviewTerms extends FormBase {
|
||||||
$term->parent->target_id = $values['term']['parent'];
|
$term->parent->target_id = $values['term']['parent'];
|
||||||
$changed_terms[$term->id()] = $term;
|
$changed_terms[$term->id()] = $term;
|
||||||
}
|
}
|
||||||
$hierarchy = $term->parents[0] != 0 ? VocabularyInterface::HIERARCHY_SINGLE : $hierarchy;
|
|
||||||
$weight++;
|
$weight++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -484,7 +480,6 @@ class OverviewTerms extends FormBase {
|
||||||
$term->setWeight($weight);
|
$term->setWeight($weight);
|
||||||
$changed_terms[$term->id()] = $term;
|
$changed_terms[$term->id()] = $term;
|
||||||
}
|
}
|
||||||
$hierarchy = $term->parents[0] != 0 ? VocabularyInterface::HIERARCHY_SINGLE : $hierarchy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save all updated terms.
|
// Save all updated terms.
|
||||||
|
@ -492,11 +487,6 @@ class OverviewTerms extends FormBase {
|
||||||
$term->save();
|
$term->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the vocabulary hierarchy to flat or single hierarchy.
|
|
||||||
if ($vocabulary->getHierarchy() != $hierarchy) {
|
|
||||||
$vocabulary->setHierarchy($hierarchy);
|
|
||||||
$vocabulary->save();
|
|
||||||
}
|
|
||||||
$this->messenger()->addStatus($this->t('The configuration options have been saved.'));
|
$this->messenger()->addStatus($this->t('The configuration options have been saved.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
namespace Drupal\taxonomy\Form;
|
namespace Drupal\taxonomy\Form;
|
||||||
|
|
||||||
use Drupal\Core\Form\FormStateInterface;
|
|
||||||
use Drupal\Core\Entity\ContentEntityDeleteForm;
|
use Drupal\Core\Entity\ContentEntityDeleteForm;
|
||||||
use Drupal\Core\Url;
|
use Drupal\Core\Url;
|
||||||
|
|
||||||
|
@ -43,21 +42,4 @@ class TermDeleteForm extends ContentEntityDeleteForm {
|
||||||
return $this->t('Deleted term %name.', ['%name' => $this->entity->label()]);
|
return $this->t('Deleted term %name.', ['%name' => $this->entity->label()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
|
||||||
parent::submitForm($form, $form_state);
|
|
||||||
|
|
||||||
/** @var \Drupal\Core\Entity\ContentEntityInterface $term */
|
|
||||||
$term = $this->getEntity();
|
|
||||||
if ($term->isDefaultTranslation()) {
|
|
||||||
$storage = $this->entityManager->getStorage('taxonomy_vocabulary');
|
|
||||||
$vocabulary = $storage->load($this->entity->bundle());
|
|
||||||
|
|
||||||
// @todo Move to storage http://drupal.org/node/1988712
|
|
||||||
taxonomy_check_vocabulary_hierarchy($vocabulary, ['tid' => $term->id()]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ class TermForm extends ContentEntityForm {
|
||||||
public function form(array $form, FormStateInterface $form_state) {
|
public function form(array $form, FormStateInterface $form_state) {
|
||||||
$term = $this->entity;
|
$term = $this->entity;
|
||||||
$vocab_storage = $this->entityManager->getStorage('taxonomy_vocabulary');
|
$vocab_storage = $this->entityManager->getStorage('taxonomy_vocabulary');
|
||||||
|
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
|
||||||
$taxonomy_storage = $this->entityManager->getStorage('taxonomy_term');
|
$taxonomy_storage = $this->entityManager->getStorage('taxonomy_term');
|
||||||
$vocabulary = $vocab_storage->load($term->bundle());
|
$vocabulary = $vocab_storage->load($term->bundle());
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ class TermForm extends ContentEntityForm {
|
||||||
$form['relations'] = [
|
$form['relations'] = [
|
||||||
'#type' => 'details',
|
'#type' => 'details',
|
||||||
'#title' => $this->t('Relations'),
|
'#title' => $this->t('Relations'),
|
||||||
'#open' => $vocabulary->getHierarchy() == VocabularyInterface::HIERARCHY_MULTIPLE,
|
'#open' => $taxonomy_storage->getVocabularyHierarchyType($vocabulary->id()) == VocabularyInterface::HIERARCHY_MULTIPLE,
|
||||||
'#weight' => 10,
|
'#weight' => 10,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -142,26 +143,11 @@ class TermForm extends ContentEntityForm {
|
||||||
}
|
}
|
||||||
|
|
||||||
$current_parent_count = count($form_state->getValue('parent'));
|
$current_parent_count = count($form_state->getValue('parent'));
|
||||||
$previous_parent_count = count($form_state->get(['taxonomy', 'parent']));
|
|
||||||
// Root doesn't count if it's the only parent.
|
// Root doesn't count if it's the only parent.
|
||||||
if ($current_parent_count == 1 && $form_state->hasValue(['parent', 0])) {
|
if ($current_parent_count == 1 && $form_state->hasValue(['parent', 0])) {
|
||||||
$current_parent_count = 0;
|
|
||||||
$form_state->setValue('parent', []);
|
$form_state->setValue('parent', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the number of parents has been reduced to one or none, do a check on the
|
|
||||||
// parents of every term in the vocabulary value.
|
|
||||||
$vocabulary = $form_state->get(['taxonomy', 'vocabulary']);
|
|
||||||
if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
|
|
||||||
taxonomy_check_vocabulary_hierarchy($vocabulary, $form_state->getValues());
|
|
||||||
}
|
|
||||||
// If we've increased the number of parents and this is a single or flat
|
|
||||||
// hierarchy, update the vocabulary immediately.
|
|
||||||
elseif ($current_parent_count > $previous_parent_count && $vocabulary->getHierarchy() != VocabularyInterface::HIERARCHY_MULTIPLE) {
|
|
||||||
$vocabulary->setHierarchy($current_parent_count == 1 ? VocabularyInterface::HIERARCHY_SINGLE : VocabularyInterface::HIERARCHY_MULTIPLE);
|
|
||||||
$vocabulary->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$form_state->setValue('tid', $term->id());
|
$form_state->setValue('tid', $term->id());
|
||||||
$form_state->set('tid', $term->id());
|
$form_state->set('tid', $term->id());
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Drupal\taxonomy;
|
||||||
|
|
||||||
use Drupal\Core\Entity\EntityInterface;
|
use Drupal\Core\Entity\EntityInterface;
|
||||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||||
|
use Drupal\Core\Entity\Sql\TableMappingInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a Controller class for taxonomy terms.
|
* Defines a Controller class for taxonomy terms.
|
||||||
|
@ -46,6 +47,19 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||||
*/
|
*/
|
||||||
protected $ancestors;
|
protected $ancestors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of hierarchy allowed within a vocabulary.
|
||||||
|
*
|
||||||
|
* Possible values:
|
||||||
|
* - VocabularyInterface::HIERARCHY_DISABLED: No parents.
|
||||||
|
* - VocabularyInterface::HIERARCHY_SINGLE: Single parent.
|
||||||
|
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
||||||
|
*
|
||||||
|
* @var int[]
|
||||||
|
* An array of one the possible values above, keyed by vocabulary ID.
|
||||||
|
*/
|
||||||
|
protected $vocabularyHierarchyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
|
@ -72,6 +86,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||||
$this->treeParents = [];
|
$this->treeParents = [];
|
||||||
$this->treeTerms = [];
|
$this->treeTerms = [];
|
||||||
$this->trees = [];
|
$this->trees = [];
|
||||||
|
$this->vocabularyHierarchyType = [];
|
||||||
parent::resetCache($ids);
|
parent::resetCache($ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,13 +372,50 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||||
return $terms;
|
return $terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getVocabularyHierarchyType($vid) {
|
||||||
|
// Return early if we already computed this value.
|
||||||
|
if (isset($this->vocabularyHierarchyType[$vid])) {
|
||||||
|
return $this->vocabularyHierarchyType[$vid];
|
||||||
|
}
|
||||||
|
|
||||||
|
$parent_field_storage = $this->entityManager->getFieldStorageDefinitions($this->entityTypeId)['parent'];
|
||||||
|
$table_mapping = $this->getTableMapping();
|
||||||
|
|
||||||
|
$target_id_column = $table_mapping->getFieldColumnName($parent_field_storage, 'target_id');
|
||||||
|
$delta_column = $table_mapping->getFieldColumnName($parent_field_storage, TableMappingInterface::DELTA);
|
||||||
|
|
||||||
|
$query = $this->database->select($table_mapping->getFieldTableName('parent'), 'p');
|
||||||
|
$query->addExpression("MAX($target_id_column)", 'max_parent_id');
|
||||||
|
$query->addExpression("MAX($delta_column)", 'max_delta');
|
||||||
|
$query->condition('bundle', $vid);
|
||||||
|
|
||||||
|
$result = $query->execute()->fetchAll();
|
||||||
|
|
||||||
|
// If all the terms have the same parent, the parent can only be root (0).
|
||||||
|
if ((int) $result[0]->max_parent_id === 0) {
|
||||||
|
$this->vocabularyHierarchyType[$vid] = VocabularyInterface::HIERARCHY_DISABLED;
|
||||||
|
}
|
||||||
|
// If no term has a delta higher than 0, no term has multiple parents.
|
||||||
|
elseif ((int) $result[0]->max_delta === 0) {
|
||||||
|
$this->vocabularyHierarchyType[$vid] = VocabularyInterface::HIERARCHY_SINGLE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->vocabularyHierarchyType[$vid] = VocabularyInterface::HIERARCHY_MULTIPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->vocabularyHierarchyType[$vid];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function __sleep() {
|
public function __sleep() {
|
||||||
$vars = parent::__sleep();
|
$vars = parent::__sleep();
|
||||||
// Do not serialize static cache.
|
// Do not serialize static cache.
|
||||||
unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
|
unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees'], $vars['vocabularyHierarchyType']);
|
||||||
return $vars;
|
return $vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,6 +430,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||||
$this->treeParents = [];
|
$this->treeParents = [];
|
||||||
$this->treeTerms = [];
|
$this->treeTerms = [];
|
||||||
$this->trees = [];
|
$this->trees = [];
|
||||||
|
$this->vocabularyHierarchyType = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,4 +126,19 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
||||||
*/
|
*/
|
||||||
public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL);
|
public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hierarchy type for a specific vocabulary ID.
|
||||||
|
*
|
||||||
|
* @param string $vid
|
||||||
|
* Vocabulary ID to retrieve the hierarchy type for.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
* The vocabulary hierarchy.
|
||||||
|
* Possible values:
|
||||||
|
* - VocabularyInterface::HIERARCHY_DISABLED: No parents.
|
||||||
|
* - VocabularyInterface::HIERARCHY_SINGLE: Single parent.
|
||||||
|
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
||||||
|
*/
|
||||||
|
public function getVocabularyHierarchyType($vid);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,4 +108,29 @@ class TermStorageSchema extends SqlContentEntityStorageSchema {
|
||||||
return $schema;
|
return $schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected function getDedicatedTableSchema(FieldStorageDefinitionInterface $storage_definition, ContentEntityTypeInterface $entity_type = NULL) {
|
||||||
|
$dedicated_table_schema = parent::getDedicatedTableSchema($storage_definition, $entity_type);
|
||||||
|
|
||||||
|
// Add an index on 'bundle', 'delta' and 'parent_target_id' columns to
|
||||||
|
// increase the performance of the query from
|
||||||
|
// \Drupal\taxonomy\TermStorage::getVocabularyHierarchyType().
|
||||||
|
if ($storage_definition->getName() === 'parent') {
|
||||||
|
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
|
||||||
|
$table_mapping = $this->storage->getTableMapping();
|
||||||
|
$dedicated_table_name = $table_mapping->getDedicatedDataTableName($storage_definition);
|
||||||
|
|
||||||
|
unset($dedicated_table_schema[$dedicated_table_name]['indexes']['bundle']);
|
||||||
|
$dedicated_table_schema[$dedicated_table_name]['indexes']['bundle_delta_target_id'] = [
|
||||||
|
'bundle',
|
||||||
|
'delta',
|
||||||
|
$table_mapping->getFieldColumnName($storage_definition, 'target_id'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $dedicated_table_schema;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ interface VocabularyInterface extends ConfigEntityInterface {
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
* The vocabulary hierarchy.
|
* The vocabulary hierarchy.
|
||||||
|
*
|
||||||
|
* @deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.x. Use
|
||||||
|
* \Drupal\taxonomy\TermStorage::getVocabularyHierarchyType() instead.
|
||||||
*/
|
*/
|
||||||
public function getHierarchy();
|
public function getHierarchy();
|
||||||
|
|
||||||
|
@ -43,6 +46,9 @@ interface VocabularyInterface extends ConfigEntityInterface {
|
||||||
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
* - VocabularyInterface::HIERARCHY_MULTIPLE: Multiple parents.
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
|
*
|
||||||
|
* @deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.x. Reset
|
||||||
|
* the cache of the taxonomy_term storage handler instead.
|
||||||
*/
|
*/
|
||||||
public function setHierarchy($hierarchy);
|
public function setHierarchy($hierarchy);
|
||||||
|
|
||||||
|
|
|
@ -186,3 +186,12 @@ function taxonomy_update_8601() {
|
||||||
|
|
||||||
return t('The publishing status field has been added to taxonomy terms.');
|
return t('The publishing status field has been added to taxonomy terms.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an index on the 'taxonomy_term__parent' field table.
|
||||||
|
*/
|
||||||
|
function taxonomy_update_8701() {
|
||||||
|
$entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
|
||||||
|
$storage_definition = $entity_definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term');
|
||||||
|
$entity_definition_update_manager->updateFieldStorageDefinition($storage_definition);
|
||||||
|
}
|
||||||
|
|
|
@ -81,8 +81,9 @@ function taxonomy_help($route_name, RouteMatchInterface $route_match) {
|
||||||
|
|
||||||
case 'entity.taxonomy_vocabulary.overview_form':
|
case 'entity.taxonomy_vocabulary.overview_form':
|
||||||
$vocabulary = $route_match->getParameter('taxonomy_vocabulary');
|
$vocabulary = $route_match->getParameter('taxonomy_vocabulary');
|
||||||
|
$vocabulary_hierarchy = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->getVocabularyHierarchyType($vocabulary->id());
|
||||||
if (\Drupal::currentUser()->hasPermission('administer taxonomy') || \Drupal::currentUser()->hasPermission('edit terms in ' . $vocabulary->id())) {
|
if (\Drupal::currentUser()->hasPermission('administer taxonomy') || \Drupal::currentUser()->hasPermission('edit terms in ' . $vocabulary->id())) {
|
||||||
switch ($vocabulary->getHierarchy()) {
|
switch ($vocabulary_hierarchy) {
|
||||||
case VocabularyInterface::HIERARCHY_DISABLED:
|
case VocabularyInterface::HIERARCHY_DISABLED:
|
||||||
return '<p>' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
return '<p>' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', ['%capital_name' => Unicode::ucfirst($vocabulary->label()), '%name' => $vocabulary->label()]) . '</p>';
|
||||||
case VocabularyInterface::HIERARCHY_SINGLE:
|
case VocabularyInterface::HIERARCHY_SINGLE:
|
||||||
|
@ -92,7 +93,7 @@ function taxonomy_help($route_name, RouteMatchInterface $route_match) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
switch ($vocabulary->getHierarchy()) {
|
switch ($vocabulary_hierarchy) {
|
||||||
case VocabularyInterface::HIERARCHY_DISABLED:
|
case VocabularyInterface::HIERARCHY_DISABLED:
|
||||||
return '<p>' . t('%capital_name contains the following terms.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
return '<p>' . t('%capital_name contains the following terms.', ['%capital_name' => Unicode::ucfirst($vocabulary->label())]) . '</p>';
|
||||||
case VocabularyInterface::HIERARCHY_SINGLE:
|
case VocabularyInterface::HIERARCHY_SINGLE:
|
||||||
|
@ -156,11 +157,10 @@ function taxonomy_theme() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks and updates the hierarchy flag of a vocabulary.
|
* Checks the hierarchy flag of a vocabulary.
|
||||||
*
|
*
|
||||||
* Checks the current parents of all terms in a vocabulary and updates the
|
* Checks the current parents of all terms in a vocabulary. If no term has
|
||||||
* vocabulary's hierarchy setting to the lowest possible level. If no term
|
* parent terms then the vocabulary will be given a hierarchy of
|
||||||
* has parent terms then the vocabulary will be given a hierarchy of
|
|
||||||
* VocabularyInterface::HIERARCHY_DISABLED. If any term has a single parent then
|
* VocabularyInterface::HIERARCHY_DISABLED. If any term has a single parent then
|
||||||
* the vocabulary will be given a hierarchy of
|
* the vocabulary will be given a hierarchy of
|
||||||
* VocabularyInterface::HIERARCHY_SINGLE. If any term has multiple parents then
|
* VocabularyInterface::HIERARCHY_SINGLE. If any term has multiple parents then
|
||||||
|
@ -172,33 +172,15 @@ function taxonomy_theme() {
|
||||||
* @param $changed_term
|
* @param $changed_term
|
||||||
* An array of the term structure that was updated.
|
* An array of the term structure that was updated.
|
||||||
*
|
*
|
||||||
* @return
|
* @return int
|
||||||
* An integer that represents the level of the vocabulary's hierarchy.
|
* An integer that represents the level of the vocabulary's hierarchy.
|
||||||
|
*
|
||||||
|
* @deprecated in Drupal 8.7.x. Will be removed before Drupal 9.0.0. Use
|
||||||
|
* \Drupal\taxonomy\TermStorage::getVocabularyHierarchyType() instead.
|
||||||
*/
|
*/
|
||||||
function taxonomy_check_vocabulary_hierarchy(VocabularyInterface $vocabulary, $changed_term) {
|
function taxonomy_check_vocabulary_hierarchy(VocabularyInterface $vocabulary, $changed_term) {
|
||||||
$tree = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($vocabulary->id());
|
@trigger_error('taxonomy_check_vocabulary_hierarchy() is deprecated in Drupal 8.7.x and will be removed before Drupal 9.0.x. Use \Drupal\taxonomy\TermStorage::getVocabularyHierarchyType() instead.', E_USER_DEPRECATED);
|
||||||
$hierarchy = VocabularyInterface::HIERARCHY_DISABLED;
|
return \Drupal::entityTypeManager()->getStorage('taxonomy_term')->getVocabularyHierarchyType($vocabulary->id());
|
||||||
foreach ($tree as $term) {
|
|
||||||
// Update the changed term with the new parent value before comparison.
|
|
||||||
if ($term->tid == $changed_term['tid']) {
|
|
||||||
$term = (object) $changed_term;
|
|
||||||
$term->parents = $term->parent;
|
|
||||||
}
|
|
||||||
// Check this term's parent count.
|
|
||||||
if (count($term->parents) > 1) {
|
|
||||||
$hierarchy = VocabularyInterface::HIERARCHY_MULTIPLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
elseif (count($term->parents) == 1 && !isset($term->parents[0])) {
|
|
||||||
$hierarchy = VocabularyInterface::HIERARCHY_SINGLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($hierarchy != $vocabulary->getHierarchy()) {
|
|
||||||
$vocabulary->setHierarchy($hierarchy);
|
|
||||||
$vocabulary->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $hierarchy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -125,3 +125,12 @@ function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandb
|
||||||
return TRUE;
|
return TRUE;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the 'hierarchy' property from vocabularies.
|
||||||
|
*/
|
||||||
|
function taxonomy_post_update_remove_hierarchy_from_vocabularies(&$sandbox = NULL) {
|
||||||
|
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'taxonomy_vocabulary', function () {
|
||||||
|
return TRUE;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -54,7 +54,6 @@ abstract class VocabularyResourceTestBase extends EntityResourceTestBase {
|
||||||
'dependencies' => [],
|
'dependencies' => [],
|
||||||
'name' => 'Llama',
|
'name' => 'Llama',
|
||||||
'description' => NULL,
|
'description' => NULL,
|
||||||
'hierarchy' => 0,
|
|
||||||
'weight' => 0,
|
'weight' => 0,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,11 +90,11 @@ class TermTest extends TaxonomyTestBase {
|
||||||
$term2 = $this->createTerm($this->vocabulary);
|
$term2 = $this->createTerm($this->vocabulary);
|
||||||
|
|
||||||
// Get the taxonomy storage.
|
// Get the taxonomy storage.
|
||||||
$taxonomy_storage = $this->container->get('entity.manager')->getStorage('taxonomy_term');
|
/** @var \Drupal\taxonomy\TermStorageInterface $taxonomy_storage */
|
||||||
|
$taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
|
||||||
|
|
||||||
// Check that hierarchy is flat.
|
// Check that hierarchy is flat.
|
||||||
$vocabulary = Vocabulary::load($this->vocabulary->id());
|
$this->assertEquals(0, $taxonomy_storage->getVocabularyHierarchyType($this->vocabulary->id()), 'Vocabulary is flat.');
|
||||||
$this->assertEqual(0, $vocabulary->getHierarchy(), 'Vocabulary is flat.');
|
|
||||||
|
|
||||||
// Edit $term2, setting $term1 as parent.
|
// Edit $term2, setting $term1 as parent.
|
||||||
$edit = [];
|
$edit = [];
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\Tests\taxonomy\Functional\Update;
|
||||||
|
|
||||||
|
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the 'hierarchy' property is removed from vocabularies.
|
||||||
|
*
|
||||||
|
* @group taxonomy
|
||||||
|
* @group Update
|
||||||
|
* @group legacy
|
||||||
|
*/
|
||||||
|
class TaxonomyVocabularyHierarchyUpdateTest extends UpdatePathTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setDatabaseDumpFiles() {
|
||||||
|
$this->databaseDumpFiles = [
|
||||||
|
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.filled.standard.php.gz',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the 'hierarchy' property is removed from vocabularies.
|
||||||
|
*
|
||||||
|
* @see taxonomy_post_update_remove_hierarchy_from_vocabularies()
|
||||||
|
* @see taxonomy_update_8701()
|
||||||
|
*/
|
||||||
|
public function testTaxonomyUpdateParents() {
|
||||||
|
$hierarchy = \Drupal::config('taxonomy.vocabulary.test_vocabulary')->get('hierarchy');
|
||||||
|
$this->assertSame(1, $hierarchy);
|
||||||
|
|
||||||
|
// Run updates.
|
||||||
|
$this->runUpdates();
|
||||||
|
|
||||||
|
$hierarchy = \Drupal::config('taxonomy.vocabulary.test_vocabulary')->get('hierarchy');
|
||||||
|
$this->assertNull($hierarchy);
|
||||||
|
|
||||||
|
$database = \Drupal::database();
|
||||||
|
$this->assertFalse($database->schema()->indexExists('taxonomy_term__parent', 'bundle'));
|
||||||
|
$this->assertTrue($database->schema()->indexExists('taxonomy_term__parent', 'bundle_delta_target_id'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -35,13 +35,11 @@ class MigrateTaxonomyVocabularyTest extends MigrateDrupal6TestBase {
|
||||||
$this->assertSame($this->getMigration('d6_taxonomy_vocabulary')->getIdMap()->lookupDestinationId([$j]), [$vocabulary->id()]);
|
$this->assertSame($this->getMigration('d6_taxonomy_vocabulary')->getIdMap()->lookupDestinationId([$j]), [$vocabulary->id()]);
|
||||||
$this->assertSame("vocabulary $j (i=$i)", $vocabulary->label());
|
$this->assertSame("vocabulary $j (i=$i)", $vocabulary->label());
|
||||||
$this->assertSame("description of vocabulary $j (i=$i)", $vocabulary->getDescription());
|
$this->assertSame("description of vocabulary $j (i=$i)", $vocabulary->getDescription());
|
||||||
$this->assertSame($i, $vocabulary->getHierarchy());
|
|
||||||
$this->assertSame(4 + $i, $vocabulary->get('weight'));
|
$this->assertSame(4 + $i, $vocabulary->get('weight'));
|
||||||
}
|
}
|
||||||
$vocabulary = Vocabulary::load('vocabulary_name_much_longer_than');
|
$vocabulary = Vocabulary::load('vocabulary_name_much_longer_than');
|
||||||
$this->assertSame('vocabulary name much longer than thirty two characters', $vocabulary->label());
|
$this->assertSame('vocabulary name much longer than thirty two characters', $vocabulary->label());
|
||||||
$this->assertSame('description of vocabulary name much longer than thirty two characters', $vocabulary->getDescription());
|
$this->assertSame('description of vocabulary name much longer than thirty two characters', $vocabulary->getDescription());
|
||||||
$this->assertSame(3, $vocabulary->getHierarchy());
|
|
||||||
$this->assertSame(7, $vocabulary->get('weight'));
|
$this->assertSame(7, $vocabulary->get('weight'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,18 +35,15 @@ class MigrateTaxonomyVocabularyTest extends MigrateDrupal7TestBase {
|
||||||
* The label the migrated entity should have.
|
* The label the migrated entity should have.
|
||||||
* @param $expected_description
|
* @param $expected_description
|
||||||
* The description the migrated entity should have.
|
* The description the migrated entity should have.
|
||||||
* @param $expected_hierarchy
|
|
||||||
* The hierarchy setting the migrated entity should have.
|
|
||||||
* @param $expected_weight
|
* @param $expected_weight
|
||||||
* The weight the migrated entity should have.
|
* The weight the migrated entity should have.
|
||||||
*/
|
*/
|
||||||
protected function assertEntity($id, $expected_label, $expected_description, $expected_hierarchy, $expected_weight) {
|
protected function assertEntity($id, $expected_label, $expected_description, $expected_weight) {
|
||||||
/** @var \Drupal\taxonomy\VocabularyInterface $entity */
|
/** @var \Drupal\taxonomy\VocabularyInterface $entity */
|
||||||
$entity = Vocabulary::load($id);
|
$entity = Vocabulary::load($id);
|
||||||
$this->assertTrue($entity instanceof VocabularyInterface);
|
$this->assertTrue($entity instanceof VocabularyInterface);
|
||||||
$this->assertIdentical($expected_label, $entity->label());
|
$this->assertIdentical($expected_label, $entity->label());
|
||||||
$this->assertIdentical($expected_description, $entity->getDescription());
|
$this->assertIdentical($expected_description, $entity->getDescription());
|
||||||
$this->assertIdentical($expected_hierarchy, $entity->getHierarchy());
|
|
||||||
$this->assertIdentical($expected_weight, $entity->get('weight'));
|
$this->assertIdentical($expected_weight, $entity->get('weight'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +51,10 @@ class MigrateTaxonomyVocabularyTest extends MigrateDrupal7TestBase {
|
||||||
* Tests the Drupal 7 taxonomy vocabularies to Drupal 8 migration.
|
* Tests the Drupal 7 taxonomy vocabularies to Drupal 8 migration.
|
||||||
*/
|
*/
|
||||||
public function testTaxonomyVocabulary() {
|
public function testTaxonomyVocabulary() {
|
||||||
$this->assertEntity('tags', 'Tags', 'Use tags to group articles on similar topics into categories.', VocabularyInterface::HIERARCHY_DISABLED, 0);
|
$this->assertEntity('tags', 'Tags', 'Use tags to group articles on similar topics into categories.', 0);
|
||||||
$this->assertEntity('forums', 'Sujet de discussion', 'Forum navigation vocabulary', VocabularyInterface::HIERARCHY_SINGLE, -10);
|
$this->assertEntity('forums', 'Sujet de discussion', 'Forum navigation vocabulary', -10);
|
||||||
$this->assertEntity('test_vocabulary', 'Test Vocabulary', 'This is the vocabulary description', VocabularyInterface::HIERARCHY_SINGLE, 0);
|
$this->assertEntity('test_vocabulary', 'Test Vocabulary', 'This is the vocabulary description', 0);
|
||||||
$this->assertEntity('vocabulary_name_much_longer_than', 'vocabulary name clearly different than machine name and much longer than thirty two characters', 'description of vocabulary name much longer than thirty two characters', VocabularyInterface::HIERARCHY_SINGLE, 0);
|
$this->assertEntity('vocabulary_name_much_longer_than', 'vocabulary name clearly different than machine name and much longer than thirty two characters', 'description of vocabulary name much longer than thirty two characters', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,4 @@ dependencies: { }
|
||||||
name: 'Recipe category'
|
name: 'Recipe category'
|
||||||
vid: recipe_category
|
vid: recipe_category
|
||||||
description: 'Use this taxonomy to group recipes of the same type together.'
|
description: 'Use this taxonomy to group recipes of the same type together.'
|
||||||
hierarchy: 0
|
|
||||||
weight: 0
|
weight: 0
|
||||||
|
|
|
@ -4,5 +4,4 @@ dependencies: { }
|
||||||
name: Tags
|
name: Tags
|
||||||
vid: tags
|
vid: tags
|
||||||
description: 'Use tags to group articles on similar topics into categories.'
|
description: 'Use tags to group articles on similar topics into categories.'
|
||||||
hierarchy: 0
|
|
||||||
weight: 0
|
weight: 0
|
||||||
|
|
|
@ -4,5 +4,4 @@ dependencies: { }
|
||||||
name: Tags
|
name: Tags
|
||||||
vid: tags
|
vid: tags
|
||||||
description: 'Use tags to group articles on similar topics into categories.'
|
description: 'Use tags to group articles on similar topics into categories.'
|
||||||
hierarchy: 0
|
|
||||||
weight: 0
|
weight: 0
|
||||||
|
|
Loading…
Reference in New Issue