updated core to 8.6.1 via composer
This commit is contained in:
@@ -4,10 +4,12 @@ namespace Drupal\taxonomy\Entity;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityBase;
|
||||
use Drupal\Core\Entity\EntityChangedTrait;
|
||||
use Drupal\Core\Entity\EntityPublishedTrait;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Field\BaseFieldDefinition;
|
||||
use Drupal\taxonomy\TermInterface;
|
||||
use Drupal\user\StatusItem;
|
||||
|
||||
/**
|
||||
* Defines the taxonomy term entity.
|
||||
@@ -15,6 +17,13 @@ use Drupal\taxonomy\TermInterface;
|
||||
* @ContentEntityType(
|
||||
* id = "taxonomy_term",
|
||||
* label = @Translation("Taxonomy term"),
|
||||
* label_collection = @Translation("Taxonomy terms"),
|
||||
* label_singular = @Translation("taxonomy term"),
|
||||
* label_plural = @Translation("taxonomy terms"),
|
||||
* label_count = @PluralTranslation(
|
||||
* singular = "@count taxonomy term",
|
||||
* plural = "@count taxonomy terms",
|
||||
* ),
|
||||
* bundle_label = @Translation("Vocabulary"),
|
||||
* handlers = {
|
||||
* "storage" = "Drupal\taxonomy\TermStorage",
|
||||
@@ -38,7 +47,8 @@ use Drupal\taxonomy\TermInterface;
|
||||
* "bundle" = "vid",
|
||||
* "label" = "name",
|
||||
* "langcode" = "langcode",
|
||||
* "uuid" = "uuid"
|
||||
* "uuid" = "uuid",
|
||||
* "published" = "status",
|
||||
* },
|
||||
* bundle_entity_type = "taxonomy_vocabulary",
|
||||
* field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
|
||||
@@ -55,6 +65,7 @@ use Drupal\taxonomy\TermInterface;
|
||||
class Term extends ContentEntityBase implements TermInterface {
|
||||
|
||||
use EntityChangedTrait;
|
||||
use EntityPublishedTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -64,22 +75,28 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
|
||||
// See if any of the term's children are about to be become orphans.
|
||||
$orphans = [];
|
||||
foreach (array_keys($entities) as $tid) {
|
||||
if ($children = $storage->loadChildren($tid)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
foreach ($entities as $tid => $term) {
|
||||
if ($children = $storage->getChildren($term)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $child */
|
||||
foreach ($children as $child) {
|
||||
$parent = $child->get('parent');
|
||||
// Update child parents item list.
|
||||
$parent->filter(function ($item) use ($tid) {
|
||||
return $item->target_id != $tid;
|
||||
});
|
||||
|
||||
// If the term has multiple parents, we don't delete it.
|
||||
$parents = $storage->loadParents($child->id());
|
||||
if (empty($parents)) {
|
||||
if ($parent->count()) {
|
||||
$child->save();
|
||||
}
|
||||
else {
|
||||
$orphans[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete term hierarchy information after looking up orphans but before
|
||||
// deleting them so that their children/parent information is consistent.
|
||||
$storage->deleteTermHierarchy(array_keys($entities));
|
||||
|
||||
if (!empty($orphans)) {
|
||||
$storage->delete($orphans);
|
||||
}
|
||||
@@ -88,14 +105,11 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
|
||||
parent::postSave($storage, $update);
|
||||
|
||||
// Only change the parents if a value is set, keep the existing values if
|
||||
// not.
|
||||
if (isset($this->parent->target_id)) {
|
||||
$storage->deleteTermHierarchy([$this->id()]);
|
||||
$storage->updateTermHierarchy($this);
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
// Terms with no parents are mandatory children of <root>.
|
||||
if (!$this->get('parent')->count()) {
|
||||
$this->parent->target_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +120,12 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
/** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
|
||||
$fields = parent::baseFieldDefinitions($entity_type);
|
||||
|
||||
// Add the published field.
|
||||
$fields += static::publishedBaseFieldDefinitions($entity_type);
|
||||
// @todo Remove the usage of StatusItem in
|
||||
// https://www.drupal.org/project/drupal/issues/2936864.
|
||||
$fields['status']->getItemDefinition()->setClass(StatusItem::class);
|
||||
|
||||
$fields['tid']->setLabel(t('Term ID'))
|
||||
->setDescription(t('The term ID.'));
|
||||
|
||||
@@ -156,8 +176,7 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
->setLabel(t('Term Parents'))
|
||||
->setDescription(t('The parents of this term.'))
|
||||
->setSetting('target_type', 'taxonomy_term')
|
||||
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED)
|
||||
->setCustomStorage(TRUE);
|
||||
->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED);
|
||||
|
||||
$fields['changed'] = BaseFieldDefinition::create('changed')
|
||||
->setLabel(t('Changed'))
|
||||
@@ -167,6 +186,16 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
|
||||
// Only terms in the same bundle can be a parent.
|
||||
$fields['parent'] = clone $base_field_definitions['parent'];
|
||||
$fields['parent']->setSetting('handler_settings', ['target_bundles' => [$bundle => $bundle]]);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -235,17 +264,4 @@ class Term extends ContentEntityBase implements TermInterface {
|
||||
return $this->bundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getFieldsToSkipFromTranslationChangesCheck() {
|
||||
// @todo the current implementation of the parent field makes it impossible
|
||||
// for ::hasTranslationChanges() to correctly check the field for changes,
|
||||
// so it is currently skipped from the comparision and has to be fixed by
|
||||
// https://www.drupal.org/node/2843060.
|
||||
$fields = parent::getFieldsToSkipFromTranslationChangesCheck();
|
||||
$fields[] = 'parent';
|
||||
return $fields;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -241,6 +241,11 @@ class OverviewTerms extends FormBase {
|
||||
$form['terms'] = [
|
||||
'#type' => 'table',
|
||||
'#empty' => $empty,
|
||||
'#header' => [
|
||||
'term' => $this->t('Name'),
|
||||
'operations' => $this->t('Operations'),
|
||||
'weight' => $this->t('Weight'),
|
||||
],
|
||||
'#attributes' => [
|
||||
'id' => 'taxonomy',
|
||||
],
|
||||
@@ -251,6 +256,11 @@ class OverviewTerms extends FormBase {
|
||||
// all terms.
|
||||
$change_weight_access = AccessResult::allowed();
|
||||
foreach ($current_page as $key => $term) {
|
||||
$form['terms'][$key] = [
|
||||
'term' => [],
|
||||
'operations' => [],
|
||||
'weight' => [],
|
||||
];
|
||||
/** @var $term \Drupal\Core\Entity\EntityInterface */
|
||||
$term = $this->entityManager->getTranslationFromContext($term);
|
||||
$form['terms'][$key]['#term'] = $term;
|
||||
@@ -344,11 +354,8 @@ class OverviewTerms extends FormBase {
|
||||
$row_position++;
|
||||
}
|
||||
|
||||
$form['terms']['#header'] = [$this->t('Name')];
|
||||
|
||||
$this->renderer->addCacheableDependency($form['terms'], $change_weight_access);
|
||||
if ($change_weight_access->isAllowed()) {
|
||||
$form['terms']['#header'][] = $this->t('Weight');
|
||||
if ($parent_fields) {
|
||||
$form['terms']['#tabledrag'][] = [
|
||||
'action' => 'match',
|
||||
@@ -377,8 +384,6 @@ class OverviewTerms extends FormBase {
|
||||
];
|
||||
}
|
||||
|
||||
$form['terms']['#header'][] = $this->t('Operations');
|
||||
|
||||
if (($taxonomy_vocabulary->getHierarchy() !== VocabularyInterface::HIERARCHY_MULTIPLE && count($tree) > 1) && $change_weight_access->isAllowed()) {
|
||||
$form['actions'] = ['#type' => 'actions', '#tree' => FALSE];
|
||||
$form['actions']['submit'] = [
|
||||
@@ -492,7 +497,7 @@ class OverviewTerms extends FormBase {
|
||||
$vocabulary->setHierarchy($hierarchy);
|
||||
$vocabulary->save();
|
||||
}
|
||||
drupal_set_message($this->t('The configuration options have been saved.'));
|
||||
$this->messenger()->addStatus($this->t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,7 +82,7 @@ class VocabularyResetForm extends EntityConfirmFormBase {
|
||||
parent::submitForm($form, $form_state);
|
||||
$this->termStorage->resetWeights($this->entity->id());
|
||||
|
||||
drupal_set_message($this->t('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]));
|
||||
$this->messenger()->addStatus($this->t('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]));
|
||||
$this->logger('taxonomy')->notice('Reset vocabulary %name to alphabetical order.', ['%name' => $this->entity->label()]);
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class TermSelection extends DefaultSelection {
|
||||
'sort' => [
|
||||
'field' => 'name',
|
||||
'direction' => 'asc',
|
||||
]
|
||||
],
|
||||
] + parent::defaultConfiguration();
|
||||
}
|
||||
|
||||
@@ -59,10 +59,17 @@ class TermSelection extends DefaultSelection {
|
||||
$bundles = $this->entityManager->getBundleInfo('taxonomy_term');
|
||||
$bundle_names = $this->getConfiguration()['target_bundles'] ?: array_keys($bundles);
|
||||
|
||||
$has_admin_access = $this->currentUser->hasPermission('administer taxonomy');
|
||||
$unpublished_terms = [];
|
||||
foreach ($bundle_names as $bundle) {
|
||||
if ($vocabulary = Vocabulary::load($bundle)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface[] $terms */
|
||||
if ($terms = $this->entityManager->getStorage('taxonomy_term')->loadTree($vocabulary->id(), 0, NULL, TRUE)) {
|
||||
foreach ($terms as $term) {
|
||||
if (!$has_admin_access && (!$term->isPublished() || in_array($term->parent->target_id, $unpublished_terms))) {
|
||||
$unpublished_terms[] = $term->id();
|
||||
continue;
|
||||
}
|
||||
$options[$vocabulary->id()][$term->id()] = str_repeat('-', $term->depth) . Html::escape($this->entityManager->getTranslationFromContext($term)->label());
|
||||
}
|
||||
}
|
||||
@@ -72,4 +79,63 @@ class TermSelection extends DefaultSelection {
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countReferenceableEntities($match = NULL, $match_operator = 'CONTAINS') {
|
||||
if ($match) {
|
||||
return parent::countReferenceableEntities($match, $match_operator);
|
||||
}
|
||||
|
||||
$total = 0;
|
||||
$referenceable_entities = $this->getReferenceableEntities($match, $match_operator, 0);
|
||||
foreach ($referenceable_entities as $bundle => $entities) {
|
||||
$total += count($entities);
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function buildEntityQuery($match = NULL, $match_operator = 'CONTAINS') {
|
||||
$query = parent::buildEntityQuery($match, $match_operator);
|
||||
|
||||
// Adding the 'taxonomy_term_access' tag is sadly insufficient for terms:
|
||||
// core requires us to also know about the concept of 'published' and
|
||||
// 'unpublished'.
|
||||
if (!$this->currentUser->hasPermission('administer taxonomy')) {
|
||||
$query->condition('status', 1);
|
||||
}
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createNewEntity($entity_type_id, $bundle, $label, $uid) {
|
||||
$term = parent::createNewEntity($entity_type_id, $bundle, $label, $uid);
|
||||
|
||||
// In order to create a referenceable term, it needs to published.
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
$term->setPublished();
|
||||
|
||||
return $term;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validateReferenceableNewEntities(array $entities) {
|
||||
$entities = parent::validateReferenceableNewEntities($entities);
|
||||
// Mirror the conditions checked in buildEntityQuery().
|
||||
if (!$this->currentUser->hasPermission('administer taxonomy')) {
|
||||
$entities = array_filter($entities, function ($term) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return $term->isPublished();
|
||||
});
|
||||
}
|
||||
return $entities;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ class D7TaxonomyTermDeriver extends DeriverBase implements ContainerDeriverInter
|
||||
$this->fieldPluginCache[$field_type] = $this->fieldPluginManager->createInstance($plugin_id, ['core' => 7], $migration);
|
||||
}
|
||||
$this->fieldPluginCache[$field_type]
|
||||
->processFieldValues($migration, $field_name, $info);
|
||||
->defineValueProcessPipeline($migration, $field_name, $info);
|
||||
}
|
||||
catch (PluginNotFoundException $ex) {
|
||||
try {
|
||||
|
||||
@@ -30,7 +30,7 @@ class TaxonomyTermReference extends FieldPluginBase {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function processFieldValues(MigrationInterface $migration, $field_name, $data) {
|
||||
public function defineValueProcessPipeline(MigrationInterface $migration, $field_name, $data) {
|
||||
$process = [
|
||||
'plugin' => 'sub_process',
|
||||
'source' => $field_name,
|
||||
|
||||
@@ -75,6 +75,20 @@ class Term extends FieldableEntity {
|
||||
$current_tid = $row->getSourceProperty('tid');
|
||||
$row->setSourceProperty('is_container', in_array($current_tid, $forum_container_tids));
|
||||
|
||||
// If the term name or term description were replaced by real fields using
|
||||
// the Drupal 7 Title module, use the fields value instead of the term name
|
||||
// or term description.
|
||||
if ($this->moduleExists('title')) {
|
||||
$name_field = $row->getSourceProperty('name_field');
|
||||
if (isset($name_field[0]['value'])) {
|
||||
$row->setSourceProperty('name', $name_field[0]['value']);
|
||||
}
|
||||
$description_field = $row->getSourceProperty('description_field');
|
||||
if (isset($description_field[0]['value'])) {
|
||||
$row->setSourceProperty('description', $description_field[0]['value']);
|
||||
}
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ class Vocabulary extends DrupalSqlBase {
|
||||
'hierarchy' => $this->t('The type of hierarchy allowed within the vocabulary. (0 = disabled, 1 = single, 2 = multiple)'),
|
||||
'module' => $this->t('Module responsible for the vocabulary.'),
|
||||
'weight' => $this->t('The weight of the vocabulary in relation to other vocabularies.'),
|
||||
'machine_name' => $this->t('Unique machine name of the vocabulary.')
|
||||
'machine_name' => $this->t('Unique machine name of the vocabulary.'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -111,18 +111,19 @@ class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPlugin
|
||||
$last = "tn";
|
||||
|
||||
if ($this->options['depth'] > 0) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', 'th', "th.tid = tn.tid");
|
||||
$subquery->leftJoin('taxonomy_term__parent', 'th', "th.entity_id = tn.tid");
|
||||
$last = "th";
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.parent = th$count.tid");
|
||||
$where->condition("th$count.tid", $tids, $operator);
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.parent_target_id = th$count.entity_id");
|
||||
$where->condition("th$count.entity_id", $tids, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
elseif ($this->options['depth'] < 0) {
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.tid = th$count.parent");
|
||||
$where->condition("th$count.tid", $tids, $operator);
|
||||
$field = $count == 1 ? 'tid' : 'entity_id';
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.$field = th$count.parent_target_id");
|
||||
$where->condition("th$count.entity_id", $tids, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class Tid extends ArgumentDefaultPluginBase implements CacheableDependencyInterf
|
||||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class TaxonomyIndexTid extends PrerenderList {
|
||||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ class TermName extends EntityField {
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -77,18 +77,19 @@ class TaxonomyIndexTidDepth extends TaxonomyIndexTid {
|
||||
$last = "tn";
|
||||
|
||||
if ($this->options['depth'] > 0) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', 'th', "th.tid = tn.tid");
|
||||
$subquery->leftJoin('taxonomy_term__parent', 'th', "th.entity_id = tn.tid");
|
||||
$last = "th";
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.parent = th$count.tid");
|
||||
$where->condition("th$count.tid", $this->value, $operator);
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.parent_target_id = th$count.entity_id");
|
||||
$where->condition("th$count.entity_id", $this->value, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
elseif ($this->options['depth'] < 0) {
|
||||
foreach (range(1, abs($this->options['depth'])) as $count) {
|
||||
$subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.tid = th$count.parent");
|
||||
$where->condition("th$count.tid", $this->value, $operator);
|
||||
$field = $count == 1 ? 'tid' : 'entity_id';
|
||||
$subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.$field = th$count.parent_target_id");
|
||||
$where->condition("th$count.entity_id", $this->value, $operator);
|
||||
$last = "th$count";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
|
||||
if ($account->hasPermission('administer taxonomy')) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
switch ($operation) {
|
||||
case 'view':
|
||||
return AccessResult::allowedIfHasPermission($account, 'access content');
|
||||
$access_result = AccessResult::allowedIf($account->hasPermission('access content') && $entity->isPublished())
|
||||
->cachePerPermissions()
|
||||
->addCacheableDependency($entity);
|
||||
if (!$access_result->isAllowed()) {
|
||||
$access_result->setReason("The 'access content' permission is required and the taxonomy term must be published.");
|
||||
}
|
||||
return $access_result;
|
||||
|
||||
case 'update':
|
||||
return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
|
||||
if ($account->hasPermission("edit terms in {$entity->bundle()}")) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in {$entity->bundle()}' OR 'administer taxonomy'.");
|
||||
|
||||
case 'delete':
|
||||
return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
|
||||
if ($account->hasPermission("delete terms in {$entity->bundle()}")) {
|
||||
return AccessResult::allowed()->cachePerPermissions();
|
||||
}
|
||||
|
||||
return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'.");
|
||||
|
||||
default:
|
||||
// No opinion.
|
||||
return AccessResult::neutral();
|
||||
return AccessResult::neutral()->cachePerPermissions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -132,11 +132,11 @@ class TermForm extends ContentEntityForm {
|
||||
$view_link = $term->link($term->getName());
|
||||
switch ($result) {
|
||||
case SAVED_NEW:
|
||||
drupal_set_message($this->t('Created new term %term.', ['%term' => $view_link]));
|
||||
$this->messenger()->addStatus($this->t('Created new term %term.', ['%term' => $view_link]));
|
||||
$this->logger('taxonomy')->notice('Created new term %term.', ['%term' => $term->getName(), 'link' => $edit_link]);
|
||||
break;
|
||||
case SAVED_UPDATED:
|
||||
drupal_set_message($this->t('Updated term %term.', ['%term' => $view_link]));
|
||||
$this->messenger()->addStatus($this->t('Updated term %term.', ['%term' => $view_link]));
|
||||
$this->logger('taxonomy')->notice('Updated term %term.', ['%term' => $term->getName(), 'link' => $edit_link]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ namespace Drupal\taxonomy;
|
||||
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityChangedInterface;
|
||||
use Drupal\Core\Entity\EntityPublishedInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a taxonomy term entity.
|
||||
*/
|
||||
interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
|
||||
interface TermInterface extends ContentEntityInterface, EntityChangedInterface, EntityPublishedInterface {
|
||||
|
||||
/**
|
||||
* Gets the term's description.
|
||||
@@ -57,7 +58,7 @@ interface TermInterface extends ContentEntityInterface, EntityChangedInterface {
|
||||
/**
|
||||
* Sets the name of the term.
|
||||
*
|
||||
* @param int $name
|
||||
* @param string $name
|
||||
* The term's name.
|
||||
*
|
||||
* @return $this
|
||||
|
||||
@@ -2,35 +2,14 @@
|
||||
|
||||
namespace Drupal\taxonomy;
|
||||
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
|
||||
|
||||
/**
|
||||
* Defines a Controller class for taxonomy terms.
|
||||
*/
|
||||
class TermStorage extends SqlContentEntityStorage implements TermStorageInterface {
|
||||
|
||||
/**
|
||||
* Array of loaded parents keyed by child term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parents = [];
|
||||
|
||||
/**
|
||||
* Array of all loaded term ancestry keyed by ancestor term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parentsAll = [];
|
||||
|
||||
/**
|
||||
* Array of child terms keyed by parent term ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $children = [];
|
||||
|
||||
/**
|
||||
* Array of term parents keyed by vocabulary ID and child term ID.
|
||||
*
|
||||
@@ -59,6 +38,14 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
*/
|
||||
protected $trees = [];
|
||||
|
||||
/**
|
||||
* Array of all loaded term ancestry keyed by ancestor term ID, keyed by term
|
||||
* ID.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface[][]
|
||||
*/
|
||||
protected $ancestors;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
@@ -80,9 +67,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
*/
|
||||
public function resetCache(array $ids = NULL) {
|
||||
drupal_static_reset('taxonomy_term_count_nodes');
|
||||
$this->parents = [];
|
||||
$this->parentsAll = [];
|
||||
$this->children = [];
|
||||
$this->ancestors = [];
|
||||
$this->treeChildren = [];
|
||||
$this->treeParents = [];
|
||||
$this->treeTerms = [];
|
||||
@@ -93,100 +78,125 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteTermHierarchy($tids) {
|
||||
$this->database->delete('taxonomy_term_hierarchy')
|
||||
->condition('tid', $tids, 'IN')
|
||||
->execute();
|
||||
}
|
||||
public function deleteTermHierarchy($tids) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateTermHierarchy(EntityInterface $term) {
|
||||
$query = $this->database->insert('taxonomy_term_hierarchy')
|
||||
->fields(['tid', 'parent']);
|
||||
|
||||
foreach ($term->parent as $parent) {
|
||||
$query->values([
|
||||
'tid' => $term->id(),
|
||||
'parent' => (int) $parent->target_id,
|
||||
]);
|
||||
}
|
||||
$query->execute();
|
||||
}
|
||||
public function updateTermHierarchy(EntityInterface $term) {}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadParents($tid) {
|
||||
if (!isset($this->parents[$tid])) {
|
||||
$parents = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
|
||||
$query->addField('t', 'tid');
|
||||
$query->condition('h.tid', $tid);
|
||||
$query->condition('t.default_langcode', 1);
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->orderBy('t.weight');
|
||||
$query->orderBy('t.name');
|
||||
if ($ids = $query->execute()->fetchCol()) {
|
||||
$parents = $this->loadMultiple($ids);
|
||||
$terms = [];
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
if ($tid && $term = $this->load($tid)) {
|
||||
foreach ($this->getParents($term) as $id => $parent) {
|
||||
// This method currently doesn't return the <root> parent.
|
||||
// @see https://www.drupal.org/node/2019905
|
||||
if (!empty($id)) {
|
||||
$terms[$id] = $parent;
|
||||
}
|
||||
}
|
||||
$this->parents[$tid] = $parents;
|
||||
}
|
||||
return $this->parents[$tid];
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of parents of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* The parent taxonomy term entities keyed by term ID. If this term has a
|
||||
* <root> parent, that item is keyed with 0 and will have NULL as value.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
protected function getParents(TermInterface $term) {
|
||||
$parents = $ids = [];
|
||||
// Cannot use $this->get('parent')->referencedEntities() here because that
|
||||
// strips out the '0' reference.
|
||||
foreach ($term->get('parent') as $item) {
|
||||
if ($item->target_id == 0) {
|
||||
// The <root> parent.
|
||||
$parents[0] = NULL;
|
||||
continue;
|
||||
}
|
||||
$ids[] = $item->target_id;
|
||||
}
|
||||
|
||||
// @todo Better way to do this? AND handle the NULL/0 parent?
|
||||
// Querying the terms again so that the same access checks are run when
|
||||
// getParents() is called as in Drupal version prior to 8.3.
|
||||
$loaded_parents = [];
|
||||
|
||||
if ($ids) {
|
||||
$query = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('tid', $ids, 'IN');
|
||||
|
||||
$loaded_parents = static::loadMultiple($query->execute());
|
||||
}
|
||||
|
||||
return $parents + $loaded_parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadAllParents($tid) {
|
||||
if (!isset($this->parentsAll[$tid])) {
|
||||
$parents = [];
|
||||
if ($term = $this->load($tid)) {
|
||||
$parents[$term->id()] = $term;
|
||||
$terms_to_search[] = $term->id();
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return (!empty($tid) && $term = $this->load($tid)) ? $this->getAncestors($term) : [];
|
||||
}
|
||||
|
||||
while ($tid = array_shift($terms_to_search)) {
|
||||
if ($new_parents = $this->loadParents($tid)) {
|
||||
foreach ($new_parents as $new_parent) {
|
||||
if (!isset($parents[$new_parent->id()])) {
|
||||
$parents[$new_parent->id()] = $new_parent;
|
||||
$terms_to_search[] = $new_parent->id();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns all ancestors of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* A list of ancestor taxonomy term entities keyed by term ID.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
protected function getAncestors(TermInterface $term) {
|
||||
if (!isset($this->ancestors[$term->id()])) {
|
||||
$this->ancestors[$term->id()] = [$term->id() => $term];
|
||||
$search[] = $term->id();
|
||||
|
||||
while ($tid = array_shift($search)) {
|
||||
foreach ($this->getParents(static::load($tid)) as $id => $parent) {
|
||||
if ($parent && !isset($this->ancestors[$term->id()][$id])) {
|
||||
$this->ancestors[$term->id()][$id] = $parent;
|
||||
$search[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->parentsAll[$tid] = $parents;
|
||||
}
|
||||
return $this->parentsAll[$tid];
|
||||
return $this->ancestors[$term->id()];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadChildren($tid, $vid = NULL) {
|
||||
if (!isset($this->children[$tid])) {
|
||||
$children = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
|
||||
$query->addField('t', 'tid');
|
||||
$query->condition('h.parent', $tid);
|
||||
if ($vid) {
|
||||
$query->condition('t.vid', $vid);
|
||||
}
|
||||
$query->condition('t.default_langcode', 1);
|
||||
$query->addTag('taxonomy_term_access');
|
||||
$query->orderBy('t.weight');
|
||||
$query->orderBy('t.name');
|
||||
if ($ids = $query->execute()->fetchCol()) {
|
||||
$children = $this->loadMultiple($ids);
|
||||
}
|
||||
$this->children[$tid] = $children;
|
||||
}
|
||||
return $this->children[$tid];
|
||||
/** @var \Drupal\taxonomy\TermInterface $term */
|
||||
return (!empty($tid) && $term = $this->load($tid)) ? $this->getChildren($term) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all children terms of this term.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* A list of children taxonomy term entities keyed by term ID.
|
||||
*
|
||||
* @internal
|
||||
* @todo Refactor away when TreeInterface is introduced.
|
||||
*/
|
||||
public function getChildren(TermInterface $term) {
|
||||
$query = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('parent', $term->id());
|
||||
return static::loadMultiple($query->execute());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,12 +211,12 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
$this->treeChildren[$vid] = [];
|
||||
$this->treeParents[$vid] = [];
|
||||
$this->treeTerms[$vid] = [];
|
||||
$query = $this->database->select('taxonomy_term_field_data', 't');
|
||||
$query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
|
||||
$query = $this->database->select($this->getDataTable(), 't');
|
||||
$query->join('taxonomy_term__parent', 'p', 't.tid = p.entity_id');
|
||||
$query->addExpression('parent_target_id', 'parent');
|
||||
$result = $query
|
||||
->addTag('taxonomy_term_access')
|
||||
->fields('t')
|
||||
->fields('h', ['parent'])
|
||||
->condition('t.vid', $vid)
|
||||
->condition('t.default_langcode', 1)
|
||||
->orderBy('t.weight')
|
||||
@@ -254,7 +264,9 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
$term = clone $term;
|
||||
}
|
||||
$term->depth = $depth;
|
||||
unset($term->parent);
|
||||
if (!$load_entities) {
|
||||
unset($term->parent);
|
||||
}
|
||||
$tid = $load_entities ? $term->id() : $term->tid;
|
||||
$term->parents = $this->treeParents[$vid][$tid];
|
||||
$tree[] = $term;
|
||||
@@ -293,7 +305,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
public function nodeCount($vid) {
|
||||
$query = $this->database->select('taxonomy_index', 'ti');
|
||||
$query->addExpression('COUNT(DISTINCT ti.nid)');
|
||||
$query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
|
||||
$query->leftJoin($this->getBaseTable(), 'td', 'ti.tid = td.tid');
|
||||
$query->condition('td.vid', $vid);
|
||||
$query->addTag('vocabulary_node_count');
|
||||
return $query->execute()->fetchField();
|
||||
@@ -303,7 +315,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetWeights($vid) {
|
||||
$this->database->update('taxonomy_term_field_data')
|
||||
$this->database->update($this->getDataTable())
|
||||
->fields(['weight' => 0])
|
||||
->condition('vid', $vid)
|
||||
->execute();
|
||||
@@ -313,7 +325,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL) {
|
||||
$query = db_select('taxonomy_term_field_data', 'td');
|
||||
$query = db_select($this->getDataTable(), 'td');
|
||||
$query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
|
||||
$query->fields('td', ['tid']);
|
||||
$query->addField('tn', 'nid', 'node_nid');
|
||||
@@ -351,7 +363,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
public function __sleep() {
|
||||
$vars = parent::__sleep();
|
||||
// Do not serialize static cache.
|
||||
unset($vars['parents'], $vars['parentsAll'], $vars['children'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
|
||||
unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
|
||||
return $vars;
|
||||
}
|
||||
|
||||
@@ -361,9 +373,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
|
||||
public function __wakeup() {
|
||||
parent::__wakeup();
|
||||
// Initialize static caches.
|
||||
$this->parents = [];
|
||||
$this->parentsAll = [];
|
||||
$this->children = [];
|
||||
$this->ancestors = [];
|
||||
$this->treeChildren = [];
|
||||
$this->treeParents = [];
|
||||
$this->treeTerms = [];
|
||||
|
||||
@@ -15,6 +15,10 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
||||
*
|
||||
* @param array $tids
|
||||
* Array of terms that need to be removed from hierarchy.
|
||||
*
|
||||
* @todo Remove this method in Drupal 9.0.x. Now the parent references are
|
||||
* automatically cleared when deleting a taxonomy term.
|
||||
* https://www.drupal.org/node/2785693
|
||||
*/
|
||||
public function deleteTermHierarchy($tids);
|
||||
|
||||
@@ -23,6 +27,10 @@ interface TermStorageInterface extends ContentEntityStorageInterface {
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $term
|
||||
* Term entity that needs to be added to term hierarchy information.
|
||||
*
|
||||
* @todo remove this method Drupal 9.0.x. Now the parent references are
|
||||
* automatically updates when when a taxonomy term is added/updated.
|
||||
* https://www.drupal.org/node/2785693
|
||||
*/
|
||||
public function updateTermHierarchy(EntityInterface $term);
|
||||
|
||||
|
||||
@@ -17,40 +17,12 @@ class TermStorageSchema extends SqlContentEntityStorageSchema {
|
||||
protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
|
||||
$schema = parent::getEntitySchema($entity_type, $reset = FALSE);
|
||||
|
||||
$schema['taxonomy_term_field_data']['indexes'] += [
|
||||
'taxonomy_term__tree' => ['vid', 'weight', 'name'],
|
||||
'taxonomy_term__vid_name' => ['vid', 'name'],
|
||||
];
|
||||
|
||||
$schema['taxonomy_term_hierarchy'] = [
|
||||
'description' => 'Stores the hierarchical relationship between terms.',
|
||||
'fields' => [
|
||||
'tid' => [
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Primary Key: The {taxonomy_term_data}.tid of the term.',
|
||||
],
|
||||
'parent' => [
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => "Primary Key: The {taxonomy_term_data}.tid of the term's parent. 0 indicates no parent.",
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
'parent' => ['parent'],
|
||||
],
|
||||
'foreign keys' => [
|
||||
'taxonomy_term_data' => [
|
||||
'table' => 'taxonomy_term_data',
|
||||
'columns' => ['tid' => 'tid'],
|
||||
],
|
||||
],
|
||||
'primary key' => ['tid', 'parent'],
|
||||
];
|
||||
if ($data_table = $this->storage->getDataTable()) {
|
||||
$schema[$data_table]['indexes'] += [
|
||||
'taxonomy_term__tree' => ['vid', 'weight', 'name'],
|
||||
'taxonomy_term__vid_name' => ['vid', 'name'],
|
||||
];
|
||||
}
|
||||
|
||||
$schema['taxonomy_index'] = [
|
||||
'description' => 'Maintains denormalized information about node/term relationships.',
|
||||
|
||||
@@ -36,7 +36,7 @@ class TermViewsData extends EntityViewsData {
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['id'] = 'taxonomy_index_tid';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['title'] = $this->t('Term');
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['help'] = $this->t('Taxonomy term chosen from autocomplete or select widget.');
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['hierarchy table'] = 'taxonomy_term_hierarchy';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['hierarchy table'] = 'taxonomy_term__parent';
|
||||
$data['taxonomy_term_field_data']['tid']['filter']['numeric'] = TRUE;
|
||||
|
||||
$data['taxonomy_term_field_data']['tid_raw'] = [
|
||||
@@ -61,12 +61,12 @@ class TermViewsData extends EntityViewsData {
|
||||
'argument field' => 'tid',
|
||||
'base' => 'node_field_data',
|
||||
'field' => 'nid',
|
||||
'relationship' => 'node_field_data:term_node_tid'
|
||||
'relationship' => 'node_field_data:term_node_tid',
|
||||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_term_field_data']['vid']['help'] = $this->t('Filter the results of "Taxonomy: Term" to a particular vocabulary.');
|
||||
unset($data['taxonomy_term_field_data']['vid']['field']);
|
||||
$data['taxonomy_term_field_data']['vid']['field']['help'] = t('The vocabulary name.');
|
||||
$data['taxonomy_term_field_data']['vid']['argument']['id'] = 'vocabulary_vid';
|
||||
unset($data['taxonomy_term_field_data']['vid']['sort']);
|
||||
|
||||
@@ -133,7 +133,7 @@ class TermViewsData extends EntityViewsData {
|
||||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_index']['table']['group'] = $this->t('Taxonomy term');
|
||||
$data['taxonomy_index']['table']['group'] = $this->t('Taxonomy term');
|
||||
|
||||
$data['taxonomy_index']['table']['join'] = [
|
||||
'taxonomy_term_field_data' => [
|
||||
@@ -146,8 +146,8 @@ class TermViewsData extends EntityViewsData {
|
||||
'left_field' => 'nid',
|
||||
'field' => 'nid',
|
||||
],
|
||||
'taxonomy_term_hierarchy' => [
|
||||
'left_field' => 'tid',
|
||||
'taxonomy_term__parent' => [
|
||||
'left_field' => 'entity_id',
|
||||
'field' => 'tid',
|
||||
],
|
||||
];
|
||||
@@ -181,7 +181,7 @@ class TermViewsData extends EntityViewsData {
|
||||
'filter' => [
|
||||
'title' => $this->t('Has taxonomy term'),
|
||||
'id' => 'taxonomy_index_tid',
|
||||
'hierarchy table' => 'taxonomy_term_hierarchy',
|
||||
'hierarchy table' => 'taxonomy_term__parent',
|
||||
'numeric' => TRUE,
|
||||
'skip base' => 'taxonomy_term_field_data',
|
||||
'allow empty' => TRUE,
|
||||
@@ -216,47 +216,22 @@ class TermViewsData extends EntityViewsData {
|
||||
'title' => $this->t('Post date'),
|
||||
'help' => $this->t('The date the content related to a term was posted.'),
|
||||
'sort' => [
|
||||
'id' => 'date'
|
||||
'id' => 'date',
|
||||
],
|
||||
'filter' => [
|
||||
'id' => 'date',
|
||||
],
|
||||
];
|
||||
|
||||
$data['taxonomy_term_hierarchy']['table']['group'] = $this->t('Taxonomy term');
|
||||
$data['taxonomy_term_hierarchy']['table']['provider'] = 'taxonomy';
|
||||
|
||||
$data['taxonomy_term_hierarchy']['table']['join'] = [
|
||||
'taxonomy_term_hierarchy' => [
|
||||
// Link to self through left.parent = right.tid (going down in depth).
|
||||
'left_field' => 'tid',
|
||||
'field' => 'parent',
|
||||
],
|
||||
'taxonomy_term_field_data' => [
|
||||
// Link directly to taxonomy_term_field_data via tid.
|
||||
'left_field' => 'tid',
|
||||
'field' => 'tid',
|
||||
],
|
||||
// Link to self through left.parent = right.tid (going down in depth).
|
||||
$data['taxonomy_term__parent']['table']['join']['taxonomy_term__parent'] = [
|
||||
'left_field' => 'entity_id',
|
||||
'field' => 'parent_target_id',
|
||||
];
|
||||
|
||||
$data['taxonomy_term_hierarchy']['parent'] = [
|
||||
'title' => $this->t('Parent term'),
|
||||
'help' => $this->t('The parent term of the term. This can produce duplicate entries if you are using a vocabulary that allows multiple parents.'),
|
||||
'relationship' => [
|
||||
'base' => 'taxonomy_term_field_data',
|
||||
'field' => 'parent',
|
||||
'label' => $this->t('Parent'),
|
||||
'id' => 'standard',
|
||||
],
|
||||
'filter' => [
|
||||
'help' => $this->t('Filter the results of "Taxonomy: Term" by the parent pid.'),
|
||||
'id' => 'numeric',
|
||||
],
|
||||
'argument' => [
|
||||
'help' => $this->t('The parent term of the term.'),
|
||||
'id' => 'taxonomy',
|
||||
],
|
||||
];
|
||||
$data['taxonomy_term__parent']['parent_target_id']['help'] = $this->t('The parent term of the term. This can produce duplicate entries if you are using a vocabulary that allows multiple parents.');
|
||||
$data['taxonomy_term__parent']['parent_target_id']['relationship']['label'] = $this->t('Parent');
|
||||
$data['taxonomy_term__parent']['parent_target_id']['argument']['id'] = 'taxonomy';
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ class RssTest extends TaxonomyTestBase {
|
||||
$this->drupalGet('taxonomy/term/all/feed');
|
||||
$this->assertRaw($raw_xml, "Raw text '$raw_xml' is found.");
|
||||
// Unpublish the article and check that it is not shown in the feed.
|
||||
$node->setPublished(FALSE)->save();
|
||||
$node->setUnpublished()->save();
|
||||
$this->drupalGet('taxonomy/term/all/feed');
|
||||
$this->assertNoRaw($raw_xml);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace Drupal\taxonomy\Tests;
|
||||
|
||||
@trigger_error(__NAMESPACE__ . '\TaxonomyTestTrait is deprecated in Drupal 8.4.0 and will be removed before Drupal 9.0.0. Instead, use \Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait', E_USER_DEPRECATED);
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
@@ -25,7 +24,7 @@ trait TaxonomyTestTrait {
|
||||
$vocabulary = Vocabulary::create([
|
||||
'name' => $this->randomMachineName(),
|
||||
'description' => $this->randomMachineName(),
|
||||
'vid' => Unicode::strtolower($this->randomMachineName()),
|
||||
'vid' => mb_strtolower($this->randomMachineName()),
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
'weight' => mt_rand(0, 10),
|
||||
]);
|
||||
|
||||
@@ -22,7 +22,7 @@ trait TaxonomyTranslationTestTrait {
|
||||
/**
|
||||
* The vocabulary.
|
||||
*
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary;
|
||||
* @var \Drupal\taxonomy\Entity\Vocabulary
|
||||
*/
|
||||
protected $vocabulary;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
||||
use Drupal\Core\Entity\Entity\EntityViewDisplay;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
@@ -86,7 +85,7 @@ class TermAutocompleteTest extends TaxonomyTestBase {
|
||||
|
||||
// Create a taxonomy_term_reference field on the article Content Type that
|
||||
// uses a taxonomy_autocomplete widget.
|
||||
$this->fieldName = Unicode::strtolower($this->randomMachineName());
|
||||
$this->fieldName = mb_strtolower($this->randomMachineName());
|
||||
FieldStorageConfig::create([
|
||||
'field_name' => $this->fieldName,
|
||||
'entity_type' => 'node',
|
||||
@@ -189,7 +188,7 @@ class TermAutocompleteTest extends TaxonomyTestBase {
|
||||
foreach ($expectedResults as $termName) {
|
||||
$expected[] = [
|
||||
'value' => $termName . ' (' . $this->termIds[$termName] . ')',
|
||||
'label' => $termName
|
||||
'label' => $termName,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace Drupal\taxonomy\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Tags;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\field\Entity\FieldConfig;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
@@ -73,6 +72,15 @@ class TermTest extends TaxonomyTestBase {
|
||||
->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* The "parent" field must restrict references to the same vocabulary.
|
||||
*/
|
||||
public function testParentHandlerSettings() {
|
||||
$vocabulary_fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('taxonomy_term', $this->vocabulary->id());
|
||||
$parent_target_bundles = $vocabulary_fields['parent']->getSetting('handler_settings')['target_bundles'];
|
||||
$this->assertIdentical([$this->vocabulary->id() => $this->vocabulary->id()], $parent_target_bundles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test terms in a single and multiple hierarchy.
|
||||
*/
|
||||
@@ -490,7 +498,7 @@ class TermTest extends TaxonomyTestBase {
|
||||
$this->assertFalse($terms, 'No term loaded with an invalid name.');
|
||||
|
||||
// Try to load the term using a substring of the name.
|
||||
$terms = taxonomy_term_load_multiple_by_name(Unicode::substr($term->getName(), 2), 'No term loaded with a substring of the name.');
|
||||
$terms = taxonomy_term_load_multiple_by_name(mb_substr($term->getName(), 2), 'No term loaded with a substring of the name.');
|
||||
$this->assertFalse($terms);
|
||||
|
||||
// Create a new term in a different vocabulary with the same name.
|
||||
|
||||
@@ -19,7 +19,7 @@ class VocabularyForm extends BundleEntityFormBase {
|
||||
/**
|
||||
* The vocabulary storage.
|
||||
*
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface.
|
||||
* @var \Drupal\taxonomy\VocabularyStorageInterface
|
||||
*/
|
||||
protected $vocabularyStorage;
|
||||
|
||||
@@ -89,7 +89,7 @@ class VocabularyForm extends BundleEntityFormBase {
|
||||
if ($this->moduleHandler->moduleExists('language')) {
|
||||
$form['default_terms_language'] = [
|
||||
'#type' => 'details',
|
||||
'#title' => $this->t('Terms language'),
|
||||
'#title' => $this->t('Term language'),
|
||||
'#open' => TRUE,
|
||||
];
|
||||
$form['default_terms_language']['default_language'] = [
|
||||
@@ -125,13 +125,13 @@ class VocabularyForm extends BundleEntityFormBase {
|
||||
$edit_link = $this->entity->link($this->t('Edit'));
|
||||
switch ($status) {
|
||||
case SAVED_NEW:
|
||||
drupal_set_message($this->t('Created new vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->messenger()->addStatus($this->t('Created new vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->logger('taxonomy')->notice('Created new vocabulary %name.', ['%name' => $vocabulary->label(), 'link' => $edit_link]);
|
||||
$form_state->setRedirectUrl($vocabulary->urlInfo('overview-form'));
|
||||
break;
|
||||
|
||||
case SAVED_UPDATED:
|
||||
drupal_set_message($this->t('Updated vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->messenger()->addStatus($this->t('Updated vocabulary %name.', ['%name' => $vocabulary->label()]));
|
||||
$this->logger('taxonomy')->notice('Updated vocabulary %name.', ['%name' => $vocabulary->label(), 'link' => $edit_link]);
|
||||
$form_state->setRedirectUrl($vocabulary->urlInfo('collection'));
|
||||
break;
|
||||
|
||||
@@ -7,6 +7,7 @@ use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Messenger\MessengerInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Url;
|
||||
@@ -45,6 +46,13 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
*/
|
||||
protected $renderer;
|
||||
|
||||
/**
|
||||
* The messenger.
|
||||
*
|
||||
* @var \Drupal\Core\Messenger\MessengerInterface
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* Constructs a new VocabularyListBuilder object.
|
||||
*
|
||||
@@ -56,13 +64,20 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\Render\RendererInterface $renderer
|
||||
* The renderer service.
|
||||
* @param \Drupal\Core\Messenger\MessengerInterface $messenger
|
||||
* The messenger.
|
||||
*/
|
||||
public function __construct(EntityTypeInterface $entity_type, AccountInterface $current_user, EntityTypeManagerInterface $entity_type_manager, RendererInterface $renderer = NULL) {
|
||||
public function __construct(EntityTypeInterface $entity_type,
|
||||
AccountInterface $current_user,
|
||||
EntityTypeManagerInterface $entity_type_manager,
|
||||
RendererInterface $renderer = NULL,
|
||||
MessengerInterface $messenger) {
|
||||
parent::__construct($entity_type, $entity_type_manager->getStorage($entity_type->id()));
|
||||
|
||||
$this->currentUser = $current_user;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->renderer = $renderer;
|
||||
$this->messenger = $messenger;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +88,8 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
$entity_type,
|
||||
$container->get('current_user'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('renderer')
|
||||
$container->get('renderer'),
|
||||
$container->get('messenger')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,7 +139,7 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
$header['label'] = t('Vocabulary name');
|
||||
$header['description'] = t('Description');
|
||||
|
||||
if ($this->currentUser->hasPermission('administer vocabularies')) {
|
||||
if ($this->currentUser->hasPermission('administer vocabularies') && !empty($this->weightKey)) {
|
||||
$header['weight'] = t('Weight');
|
||||
}
|
||||
|
||||
@@ -161,7 +177,7 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
$this->renderer->addCacheableDependency($build['table'], $create_access);
|
||||
if ($create_access->isAllowed()) {
|
||||
$build['table']['#empty'] = t('No vocabularies available. <a href=":link">Add vocabulary</a>.', [
|
||||
':link' => Url::fromRoute('entity.taxonomy_vocabulary.add_form')->toString()
|
||||
':link' => Url::fromRoute('entity.taxonomy_vocabulary.add_form')->toString(),
|
||||
]);
|
||||
}
|
||||
else {
|
||||
@@ -189,7 +205,7 @@ class VocabularyListBuilder extends DraggableListBuilder {
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
parent::submitForm($form, $form_state);
|
||||
|
||||
drupal_set_message(t('The configuration options have been saved.'));
|
||||
$this->messenger->addStatus($this->t('The configuration options have been saved.'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,12 @@ class VocabularyStorage extends ConfigEntityStorage implements VocabularyStorage
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getToplevelTids($vids) {
|
||||
return db_query('SELECT t.tid FROM {taxonomy_term_data} t INNER JOIN {taxonomy_term_hierarchy} th ON th.tid = t.tid WHERE t.vid IN ( :vids[] ) AND th.parent = 0', [':vids[]' => $vids])->fetchCol();
|
||||
$tids = \Drupal::entityQuery('taxonomy_term')
|
||||
->condition('vid', $vids, 'IN')
|
||||
->condition('parent.target_id', 0)
|
||||
->execute();
|
||||
|
||||
return array_values($tids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user