updated core to 8.6.1 via composer

This commit is contained in:
2018-09-12 13:58:26 +02:00
parent a9a219f2ed
commit ea56b9fba3
4443 changed files with 112098 additions and 40708 deletions
@@ -1,28 +0,0 @@
id: d6_taxonomy_vocabulary_translation
label: Taxonomy vocabularies
migration_tags:
- Drupal 6
- Configuration
source:
plugin: d6_taxonomy_vocabulary_translation
process:
vid:
-
plugin: machine_name
source: name
-
plugin: substr
length: 32
langcode: language
property:
plugin: static_map
source: property
map:
name: name
description: description
translation: translation
destination:
plugin: entity:taxonomy_vocabulary
migration_dependencies:
required:
- d6_taxonomy_vocabulary
@@ -11,7 +11,7 @@ process:
vid:
-
plugin: migration_lookup
migration: d6_node
migration: d6_node_revision
source: vid
-
plugin: skip_on_empty
+48 -32
View File
@@ -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();
}
}
+2 -2
View File
@@ -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;
}
+3 -2
View File
@@ -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
+112 -102
View File
@@ -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.',
+15 -40
View File
@@ -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;
}
+1 -1
View File
@@ -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,
];
}
+10 -2
View File
@@ -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.
+4 -4
View File
@@ -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);
}
}
+18 -8
View File
@@ -3,7 +3,7 @@
* Taxonomy behaviors.
*/
(function ($, Drupal) {
(function($, Drupal) {
/**
* Move a block in the blocks table from one region to another.
*
@@ -25,10 +25,16 @@
const rows = $table.find('tr').length;
// When a row is swapped, keep previous and next page classes set.
tableDrag.row.prototype.onSwap = function (swappedRow) {
$table.find('tr.taxonomy-term-preview').removeClass('taxonomy-term-preview');
$table.find('tr.taxonomy-term-divider-top').removeClass('taxonomy-term-divider-top');
$table.find('tr.taxonomy-term-divider-bottom').removeClass('taxonomy-term-divider-bottom');
tableDrag.row.prototype.onSwap = function(swappedRow) {
$table
.find('tr.taxonomy-term-preview')
.removeClass('taxonomy-term-preview');
$table
.find('tr.taxonomy-term-divider-top')
.removeClass('taxonomy-term-divider-top');
$table
.find('tr.taxonomy-term-divider-bottom')
.removeClass('taxonomy-term-divider-bottom');
const tableBody = $table[0].tBodies[0];
if (backStep) {
@@ -43,10 +49,14 @@
for (let k = rows - forwardStep - 1; k < rows - 1; k++) {
$(tableBody.rows[k]).addClass('taxonomy-term-preview');
}
$(tableBody.rows[rows - forwardStep - 2]).addClass('taxonomy-term-divider-top');
$(tableBody.rows[rows - forwardStep - 1]).addClass('taxonomy-term-divider-bottom');
$(tableBody.rows[rows - forwardStep - 2]).addClass(
'taxonomy-term-divider-top',
);
$(tableBody.rows[rows - forwardStep - 1]).addClass(
'taxonomy-term-divider-bottom',
);
}
};
},
};
}(jQuery, Drupal));
})(jQuery, Drupal);
+2 -2
View File
@@ -5,6 +5,6 @@ package: Core
version: VERSION
core: 8.x
dependencies:
- node
- text
- drupal:node
- drupal:text
configure: entity.taxonomy_vocabulary.collection
+183
View File
@@ -0,0 +1,183 @@
<?php
/**
* @file
* Install, update and uninstall functions for the taxonomy module.
*/
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Site\Settings;
/**
* Convert the custom taxonomy term hierarchy storage to a default storage.
*/
function taxonomy_update_8501() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
/** @var \Drupal\Core\Field\BaseFieldDefinition $field_storage_definition */
$field_storage_definition = $definition_update_manager->getFieldStorageDefinition('parent', 'taxonomy_term');
$field_storage_definition->setCustomStorage(FALSE);
$definition_update_manager->updateFieldStorageDefinition($field_storage_definition);
}
/**
* Copy hierarchy from {taxonomy_term_hierarchy} to {taxonomy_term__parent}.
*/
function taxonomy_update_8502(&$sandbox) {
$database = \Drupal::database();
if (!isset($sandbox['current'])) {
// Set batch ops sandbox.
$sandbox['current'] = 0;
$sandbox['tid'] = -1;
$sandbox['delta'] = 0;
$sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
$sandbox['max'] = $database->select('taxonomy_term_hierarchy')
->countQuery()
->execute()
->fetchField();
}
// Save the hierarchy.
$select = $database->select('taxonomy_term_hierarchy', 'h');
$select->join('taxonomy_term_data', 'd', 'h.tid = d.tid');
$hierarchy = $select
->fields('h', ['tid', 'parent'])
->fields('d', ['vid', 'langcode'])
->range($sandbox['current'], $sandbox['limit'])
->orderBy('tid', 'ASC')
->orderBy('parent', 'ASC')
->execute()
->fetchAll();
// Restore data.
$insert = $database->insert('taxonomy_term__parent')
->fields(['bundle', 'entity_id', 'revision_id', 'langcode', 'delta', 'parent_target_id']);
foreach ($hierarchy as $row) {
if ($row->tid !== $sandbox['tid']) {
$sandbox['delta'] = 0;
$sandbox['tid'] = $row->tid;
}
$insert->values([
'bundle' => $row->vid,
'entity_id' => $row->tid,
'revision_id' => $row->tid,
'langcode' => $row->langcode,
'delta' => $sandbox['delta'],
'parent_target_id' => $row->parent,
]);
$sandbox['delta']++;
$sandbox['current']++;
}
$insert->execute();
$sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['current'] / $sandbox['max']);
if ($sandbox['#finished'] >= 1) {
// Update the entity type because the 'taxonomy_term_hierarchy' table is no
// longer part of its shared tables schema.
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$definition_update_manager->updateEntityType($definition_update_manager->getEntityType('taxonomy_term'));
// \Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::onEntityTypeUpdate()
// only deletes *known* entity tables (i.e. the base, data and revision
// tables), so we have to drop it manually.
$database->schema()->dropTable('taxonomy_term_hierarchy');
return t('Taxonomy term hierarchy has been converted to default entity reference storage.');
}
}
/**
* Update views to use {taxonomy_term__parent} in relationships.
*/
function taxonomy_update_8503() {
$config_factory = \Drupal::configFactory();
foreach ($config_factory->listAll('views.view.') as $id) {
$view = $config_factory->getEditable($id);
foreach (array_keys($view->get('display')) as $display_id) {
$changed = FALSE;
foreach (['relationships', 'filters', 'arguments'] as $handler_type) {
$base_path = "display.$display_id.display_options.$handler_type";
$handlers = $view->get($base_path);
if (!$handlers) {
continue;
}
foreach ($handlers as $handler_key => $handler_config) {
$table_path = "$base_path.$handler_key.table";
$field_path = "$base_path.$handler_key.field";
$table = $view->get($table_path);
$field = $view->get($field_path);
if (($table && ($table === 'taxonomy_term_hierarchy')) && ($field && ($field === 'parent'))) {
$view->set($table_path, 'taxonomy_term__parent');
$view->set($field_path, 'parent_target_id');
$changed = TRUE;
}
}
}
if ($changed) {
$view->save(TRUE);
}
}
}
}
/**
* Add the publishing status fields to taxonomy terms.
*/
function taxonomy_update_8601() {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $definition_update_manager->getEntityType('taxonomy_term');
// Bail out early if a field named 'status' is already installed.
if ($definition_update_manager->getFieldStorageDefinition('status', 'taxonomy_term')) {
$message = \Drupal::state()->get('taxonomy_update_8601_skip_message', t('The publishing status field has <strong>not</strong> been added to taxonomy terms. See <a href=":link">this page</a> for more information on how to install it.', [
':link' => 'https://www.drupal.org/node/2985366',
]));
return $message;
}
// Add the 'published' entity key to the taxonomy_term entity type.
$entity_keys = $entity_type->getKeys();
$entity_keys['published'] = 'status';
$entity_type->set('entity_keys', $entity_keys);
$definition_update_manager->updateEntityType($entity_type);
// Add the status field.
$status = BaseFieldDefinition::create('boolean')
->setLabel(t('Publishing status'))
->setDescription(t('A boolean indicating the published state.'))
->setRevisionable(TRUE)
->setTranslatable(TRUE)
->setDefaultValue(TRUE);
$has_content_translation_status_field = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
if ($has_content_translation_status_field) {
$status->setInitialValueFromField('content_translation_status', TRUE);
}
else {
$status->setInitialValue(TRUE);
}
$definition_update_manager->installFieldStorageDefinition('status', 'taxonomy_term', 'taxonomy_term', $status);
// Uninstall the 'content_translation_status' field if needed.
if ($has_content_translation_status_field) {
$content_translation_status = $definition_update_manager->getFieldStorageDefinition('content_translation_status', 'taxonomy_term');
$definition_update_manager->uninstallFieldStorageDefinition($content_translation_status);
}
return t('The publishing status field has been added to taxonomy terms.');
}
+4 -2
View File
@@ -213,7 +213,8 @@ function taxonomy_check_vocabulary_hierarchy(VocabularyInterface $vocabulary, $c
* content language of the current request.
*
* @return array
* A $page element suitable for use by drupal_render().
* A $page element suitable for use by
* \Drupal\Core\Render\RendererInterface::render().
*/
function taxonomy_term_view(Term $term, $view_mode = 'full', $langcode = NULL) {
return entity_view($term, $view_mode, $langcode);
@@ -231,7 +232,8 @@ function taxonomy_term_view(Term $term, $view_mode = 'full', $langcode = NULL) {
* content language of the current request.
*
* @return array
* An array in the format expected by drupal_render().
* An array in the format expected by
* \Drupal\Core\Render\RendererInterface::render().
*/
function taxonomy_term_view_multiple(array $terms, $view_mode = 'full', $langcode = NULL) {
return entity_view_multiple($terms, $view_mode, $langcode);
@@ -0,0 +1,127 @@
<?php
/**
* @file
* Post update functions for Taxonomy.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\views\ViewExecutable;
/**
* Clear caches due to updated taxonomy entity views data.
*/
function taxonomy_post_update_clear_views_data_cache() {
// An empty update will flush caches.
}
/**
* Clear entity_bundle_field_definitions cache for new parent field settings.
*/
function taxonomy_post_update_clear_entity_bundle_field_definitions_cache() {
// An empty update will flush caches.
}
/**
* Add a 'published' = TRUE filter for all Taxonomy term views and converts
* existing ones that were using the 'content_translation_status' field.
*/
function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandbox = NULL) {
$definition_update_manager = \Drupal::entityDefinitionUpdateManager();
$entity_type = $definition_update_manager->getEntityType('taxonomy_term');
$published_key = $entity_type->getKey('published');
$status_filter = [
'id' => 'status',
'table' => 'taxonomy_term_field_data',
'field' => $published_key,
'relationship' => 'none',
'group_type' => 'group',
'admin_label' => '',
'operator' => '=',
'value' => '1',
'group' => 1,
'exposed' => FALSE,
'expose' => [
'operator_id' => '',
'label' => '',
'description' => '',
'use_operator' => FALSE,
'operator' => '',
'identifier' => '',
'required' => FALSE,
'remember' => FALSE,
'multiple' => FALSE,
'remember_roles' => [
'authenticated' => 'authenticated',
'anonymous' => '0',
'administrator' => '0',
],
],
'is_grouped' => FALSE,
'group_info' => [
'label' => '',
'description' => '',
'identifier' => '',
'optional' => TRUE,
'widget' => 'select',
'multiple' => FALSE,
'remember' => FALSE,
'default_group' => 'All',
'default_group_multiple' => [],
'group_items' => [],
],
'entity_type' => 'taxonomy_term',
'entity_field' => $published_key,
'plugin_id' => 'boolean',
];
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($published_key, $status_filter) {
/** @var \Drupal\views\ViewEntityInterface $view */
// Only alter taxonomy term views.
if ($view->get('base_table') !== 'taxonomy_term_field_data') {
return FALSE;
}
$displays = $view->get('display');
foreach ($displays as $display_name => &$display) {
// Update any existing 'content_translation_status fields.
$fields = isset($display['display_options']['fields']) ? $display['display_options']['fields'] : [];
foreach ($fields as $id => $field) {
if (isset($field['field']) && $field['field'] == 'content_translation_status') {
$fields[$id]['field'] = $published_key;
}
}
$display['display_options']['fields'] = $fields;
// Update any existing 'content_translation_status sorts.
$sorts = isset($display['display_options']['sorts']) ? $display['display_options']['sorts'] : [];
foreach ($sorts as $id => $sort) {
if (isset($sort['field']) && $sort['field'] == 'content_translation_status') {
$sorts[$id]['field'] = $published_key;
}
}
$display['display_options']['sorts'] = $sorts;
// Update any existing 'content_translation_status' filters or add a new
// one if necessary.
$filters = isset($display['display_options']['filters']) ? $display['display_options']['filters'] : [];
$has_status_filter = FALSE;
foreach ($filters as $id => $filter) {
if (isset($filter['field']) && $filter['field'] == 'content_translation_status') {
$filters[$id]['field'] = $published_key;
$has_status_filter = TRUE;
}
}
if (!$has_status_filter) {
$status_filter['id'] = ViewExecutable::generateHandlerId($published_key, $filters);
$filters[$status_filter['id']] = $status_filter;
}
$display['display_options']['filters'] = $filters;
}
$view->set('display', $displays);
return TRUE;
});
}
@@ -0,0 +1,32 @@
<?php
/**
* @file
* Contains database additions to drupal-8.filled.standard.php.gz for testing
* the upgrade path of https://www.drupal.org/project/drupal/issues/2981887.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_with_content_translation_status.yml';
$view_with_cts_config = Yaml::decode(file_get_contents($view_file));
$view_file = __DIR__ . '/views.view.test_taxonomy_term_view_without_content_translation_status.yml';
$view_without_cts_config = Yaml::decode(file_get_contents($view_file));
$connection->insert('config')
->fields(['collection', 'name', 'data'])
->values([
'collection' => '',
'name' => 'views.view.test_taxonomy_term_view_with_content_translation_status',
'data' => serialize($view_with_cts_config),
])
->values([
'collection' => '',
'name' => 'views.view.test_taxonomy_term_view_without_content_translation_status',
'data' => serialize($view_without_cts_config),
])
->execute();
@@ -0,0 +1,250 @@
langcode: en
status: true
dependencies:
module:
- taxonomy
- user
id: test_taxonomy_term_view_with_content_translation_status
label: 'Test taxonomy term view with content translation status'
module: views
description: ''
tag: ''
base_table: taxonomy_term_field_data
base_field: tid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: none
options:
offset: 0
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
name:
id: name
table: taxonomy_term_field_data
field: name
entity_type: taxonomy_term
entity_field: name
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
type: string
settings:
link_to_entity: true
plugin_id: term_name
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
convert_spaces: false
content_translation_status:
id: content_translation_status
table: taxonomy_term_field_data
field: content_translation_status
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: value
type: boolean
settings:
format: true-false
format_custom_true: ''
format_custom_false: ''
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: taxonomy_term
entity_field: content_translation_status
plugin_id: field
filters:
content_translation_status:
id: content_translation_status
table: taxonomy_term_field_data
field: content_translation_status
relationship: none
group_type: group
admin_label: ''
operator: '='
value: All
group: 1
exposed: true
expose:
operator_id: ''
label: 'Translation status'
description: ''
use_operator: false
operator: content_translation_status_op
identifier: content_translation_status
required: false
remember: false
multiple: false
remember_roles:
authenticated: authenticated
anonymous: '0'
administrator: '0'
is_grouped: false
group_info:
label: ''
description: ''
identifier: ''
optional: true
widget: select
multiple: false
remember: false
default_group: All
default_group_multiple: { }
group_items: { }
entity_type: taxonomy_term
entity_field: content_translation_status
plugin_id: boolean
sorts:
content_translation_status:
id: content_translation_status
table: taxonomy_term_field_data
field: content_translation_status
relationship: none
group_type: group
admin_label: ''
order: ASC
exposed: false
expose:
label: ''
entity_type: taxonomy_term
entity_field: content_translation_status
plugin_id: standard
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url
- user.permissions
tags: { }
@@ -0,0 +1,128 @@
langcode: en
status: true
dependencies:
module:
- taxonomy
- user
id: test_taxonomy_term_view_without_content_translation_status
label: 'Test taxonomy term view without content translation status'
module: views
description: ''
tag: ''
base_table: taxonomy_term_field_data
base_field: tid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: none
options:
offset: 0
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
name:
id: name
table: taxonomy_term_field_data
field: name
entity_type: taxonomy_term
entity_field: name
label: ''
alter:
alter_text: false
make_link: false
absolute: false
trim: false
word_boundary: false
ellipsis: false
strip_tags: false
html: false
hide_empty: false
empty_zero: false
type: string
settings:
link_to_entity: true
plugin_id: term_name
relationship: none
group_type: group
admin_label: ''
exclude: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: true
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_alter_empty: true
click_sort_column: value
group_column: value
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
convert_spaces: false
filters: { }
sorts: { }
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- user.permissions
tags: { }
@@ -5,4 +5,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- taxonomy
- drupal:taxonomy
@@ -5,5 +5,5 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- taxonomy
- migrate
- drupal:taxonomy
- drupal:migrate
@@ -5,4 +5,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- taxonomy
- drupal:taxonomy
@@ -5,5 +5,5 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- taxonomy
- views
- drupal:taxonomy
- drupal:views
@@ -171,4 +171,3 @@ display:
- url
- user.permissions
tags: { }
@@ -124,8 +124,8 @@ display:
relationships:
parent:
id: parent
table: taxonomy_term_hierarchy
field: parent
table: taxonomy_term__parent
field: parent_target_id
relationship: none
group_type: group
admin_label: Parent
@@ -186,8 +186,8 @@ display:
plugin_id: standard
parent:
id: parent
table: taxonomy_term_hierarchy
field: parent
table: taxonomy_term__parent
field: parent_target_id
relationship: none
group_type: group
admin_label: Parent
@@ -0,0 +1,163 @@
langcode: en
status: true
dependencies:
module:
- taxonomy
- user
id: test_taxonomy_vid_field
label: test_taxonomy_vid_field
module: views
description: ''
tag: ''
base_table: taxonomy_term_field_data
base_field: tid
core: 8.x
display:
default:
display_plugin: default
id: default
display_title: Master
position: 0
display_options:
access:
type: perm
options:
perm: 'access content'
cache:
type: tag
options: { }
query:
type: views_query
options:
disable_sql_rewrite: false
distinct: false
replica: false
query_comment: ''
query_tags: { }
exposed_form:
type: basic
options:
submit_button: Apply
reset_button: false
reset_button_label: Reset
exposed_sorts_label: 'Sort by'
expose_sort_order: true
sort_asc_label: Asc
sort_desc_label: Desc
pager:
type: full
options:
items_per_page: 10
offset: 0
id: 0
total_pages: null
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
tags:
previous: ' Previous'
next: 'Next '
first: '« First'
last: 'Last »'
quantity: 9
style:
type: default
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
row:
type: fields
options:
inline: { }
separator: ''
hide_empty: false
default_field_elements: true
fields:
vid:
id: vid
table: taxonomy_term_field_data
field: vid
relationship: none
group_type: group
admin_label: ''
label: ''
exclude: false
alter:
alter_text: false
text: ''
make_link: false
path: ''
absolute: false
external: false
replace_spaces: false
path_case: none
trim_whitespace: false
alt: ''
rel: ''
link_class: ''
prefix: ''
suffix: ''
target: ''
nl2br: false
max_length: 0
word_boundary: true
ellipsis: true
more_link: false
more_link_text: ''
more_link_path: ''
strip_tags: false
trim: false
preserve_tags: ''
html: false
element_type: ''
element_class: ''
element_label_type: ''
element_label_class: ''
element_label_colon: false
element_wrapper_type: ''
element_wrapper_class: ''
element_default_classes: true
empty: ''
hide_empty: false
empty_zero: false
hide_alter_empty: true
click_sort_column: target_id
type: entity_reference_label
settings:
link: false
group_column: target_id
group_columns: { }
group_rows: true
delta_limit: 0
delta_offset: 0
delta_reversed: false
delta_first_last: false
multi_type: separator
separator: ', '
field_api_classes: false
entity_type: taxonomy_term
entity_field: vid
plugin_id: field
filters: { }
sorts: { }
header: { }
footer: { }
empty: { }
relationships: { }
arguments: { }
display_extenders: { }
cache_metadata:
max-age: -1
contexts:
- 'languages:language_content'
- 'languages:language_interface'
- url.query_args
- user.permissions
tags: { }
@@ -4,4 +4,4 @@ package: Testing
version: VERSION
core: 8.x
dependencies:
- taxonomy
- drupal:taxonomy
@@ -0,0 +1,178 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\taxonomy\Functional\Rest\TermResourceTestBase;
/**
* @group hal
*/
class TermHalJsonAnonTest extends TermResourceTestBase {
use HalEntityNormalizationTrait;
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
// We test with multiple parent terms, and combinations thereof.
// @see ::createEntity()
// @see ::testGet()
// @see ::testGetTermWithParent()
// @see ::providerTestGetTermWithParent()
// @see ::testGetTermWithParent()
$parent_term_ids = [];
for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
$parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
}
$expected_parent_normalization_links = FALSE;
$expected_parent_normalization_embedded = FALSE;
switch ($parent_term_ids) {
case [0]:
$expected_parent_normalization_links = [
NULL,
];
$expected_parent_normalization_embedded = [
NULL,
];
break;
case [2]:
$expected_parent_normalization_links = [
[
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
];
$expected_parent_normalization_embedded = [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
],
'uuid' => [
['value' => Term::load(2)->uuid()],
],
],
];
break;
case [0, 2]:
$expected_parent_normalization_links = [
NULL,
[
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
];
$expected_parent_normalization_embedded = [
NULL,
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
],
'uuid' => [
['value' => Term::load(2)->uuid()],
],
],
];
break;
case [3, 2]:
$expected_parent_normalization_links = [
[
'href' => $this->baseUrl . '/taxonomy/term/3?_format=hal_json',
],
[
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
];
$expected_parent_normalization_embedded = [
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/taxonomy/term/3?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
],
'uuid' => [
['value' => Term::load(3)->uuid()],
],
],
[
'_links' => [
'self' => [
'href' => $this->baseUrl . '/taxonomy/term/2?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
],
'uuid' => [
['value' => Term::load(2)->uuid()],
],
],
];
break;
}
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/llama?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
$this->baseUrl . '/rest/relation/taxonomy_term/camelids/parent' => $expected_parent_normalization_links,
],
'_embedded' => [
$this->baseUrl . '/rest/relation/taxonomy_term/camelids/parent' => $expected_parent_normalization_embedded,
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/taxonomy_term/camelids',
],
],
];
}
}
@@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
*/
class TermHalJsonBasicAuthTest extends TermHalJsonAnonTest {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,18 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
*/
class TermHalJsonCookieTest extends TermHalJsonAnonTest {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -0,0 +1,37 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
/**
* @group hal
*/
class VocabularyHalJsonAnonTest extends VocabularyResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* @todo Remove this override in https://www.drupal.org/node/2805281.
*/
public function testGet() {
$this->markTestSkipped();
}
}
@@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
/**
* @group hal
*/
class VocabularyHalJsonBasicAuthTest extends VocabularyResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\taxonomy\Functional\Rest\VocabularyResourceTestBase;
/**
* @group hal
*/
class VocabularyHalJsonCookieTest extends VocabularyResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class TermJsonAnonTest extends TermResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
}
@@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class TermJsonBasicAuthTest extends TermResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class TermJsonCookieTest extends TermResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -0,0 +1,365 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Core\Cache\Cache;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
use GuzzleHttp\RequestOptions;
abstract class TermResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['taxonomy', 'path'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'taxonomy_term';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [
'changed' => NULL,
];
/**
* @var \Drupal\taxonomy\TermInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
switch ($method) {
case 'GET':
$this->grantPermissionsToTestedRole(['access content']);
break;
case 'POST':
$this->grantPermissionsToTestedRole(['create terms in camelids']);
break;
case 'PATCH':
// Grant the 'create url aliases' permission to test the case when
// the path field is accessible, see
// \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase
// for a negative test.
$this->grantPermissionsToTestedRole(['edit terms in camelids', 'create url aliases']);
break;
case 'DELETE':
$this->grantPermissionsToTestedRole(['delete terms in camelids']);
break;
}
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$vocabulary = Vocabulary::load('camelids');
if (!$vocabulary) {
// Create a "Camelids" vocabulary.
$vocabulary = Vocabulary::create([
'name' => 'Camelids',
'vid' => 'camelids',
]);
$vocabulary->save();
}
// Create a "Llama" taxonomy term.
$term = Term::create(['vid' => $vocabulary->id()])
->setName('Llama')
->setDescription("It is a little known fact that llamas cannot count higher than seven.")
->setChangedTime(123456789)
->set('path', '/llama');
$term->save();
return $term;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
// We test with multiple parent terms, and combinations thereof.
// @see ::createEntity()
// @see ::testGet()
// @see ::testGetTermWithParent()
// @see ::providerTestGetTermWithParent()
$parent_term_ids = [];
for ($i = 0; $i < $this->entity->get('parent')->count(); $i++) {
$parent_term_ids[$i] = (int) $this->entity->get('parent')[$i]->target_id;
}
$expected_parent_normalization = FALSE;
switch ($parent_term_ids) {
case [0]:
$expected_parent_normalization = [
[
'target_id' => NULL,
],
];
break;
case [2]:
$expected_parent_normalization = [
[
'target_id' => 2,
'target_type' => 'taxonomy_term',
'target_uuid' => Term::load(2)->uuid(),
'url' => base_path() . 'taxonomy/term/2',
],
];
break;
case [0, 2]:
$expected_parent_normalization = [
[
'target_id' => NULL,
],
[
'target_id' => 2,
'target_type' => 'taxonomy_term',
'target_uuid' => Term::load(2)->uuid(),
'url' => base_path() . 'taxonomy/term/2',
],
];
break;
case [3, 2]:
$expected_parent_normalization = [
[
'target_id' => 3,
'target_type' => 'taxonomy_term',
'target_uuid' => Term::load(3)->uuid(),
'url' => base_path() . 'taxonomy/term/3',
],
[
'target_id' => 2,
'target_type' => 'taxonomy_term',
'target_uuid' => Term::load(2)->uuid(),
'url' => base_path() . 'taxonomy/term/2',
],
];
break;
}
return [
'tid' => [
['value' => 1],
],
'uuid' => [
['value' => $this->entity->uuid()],
],
'vid' => [
[
'target_id' => 'camelids',
'target_type' => 'taxonomy_vocabulary',
'target_uuid' => Vocabulary::load('camelids')->uuid(),
],
],
'name' => [
['value' => 'Llama'],
],
'description' => [
[
'value' => 'It is a little known fact that llamas cannot count higher than seven.',
'format' => NULL,
'processed' => "<p>It is a little known fact that llamas cannot count higher than seven.</p>\n",
],
],
'parent' => $expected_parent_normalization,
'weight' => [
['value' => 0],
],
'langcode' => [
[
'value' => 'en',
],
],
'changed' => [
$this->formatExpectedTimestampItemValues($this->entity->getChangedTime()),
],
'default_langcode' => [
[
'value' => TRUE,
],
],
'path' => [
[
'alias' => '/llama',
'pid' => 1,
'langcode' => 'en',
],
],
'status' => [
[
'value' => TRUE,
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'vid' => [
[
'target_id' => 'camelids',
],
],
'name' => [
[
'value' => 'Dramallama',
],
],
'description' => [
[
'value' => 'Dramallamas are the coolest camelids.',
'format' => NULL,
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
switch ($method) {
case 'GET':
return "The 'access content' permission is required and the taxonomy term must be published.";
case 'POST':
return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
case 'PATCH':
return "The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.";
case 'DELETE':
return "The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.";
default:
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
/**
* Tests PATCHing a term's path.
*
* For a negative test, see the similar test coverage for Node.
*
* @see \Drupal\Tests\rest\Functional\EntityResource\Node\NodeResourceTestBase::testPatchPath()
*/
public function testPatchPath() {
$this->initAuthentication();
$this->provisionEntityResource();
$this->setUpAuthorization('GET');
$this->setUpAuthorization('PATCH');
$url = $this->getEntityResourceUrl()->setOption('query', ['_format' => static::$format]);
// GET term's current normalization.
$response = $this->request('GET', $url, $this->getAuthenticationRequestOptions('GET'));
$normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
// Change term's path alias.
$normalization['path'][0]['alias'] .= 's-rule-the-world';
// Create term PATCH request.
$request_options = [];
$request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
$request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('PATCH'));
$request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format);
// PATCH request: 200.
$response = $this->request('PATCH', $url, $request_options);
$this->assertResourceResponse(200, FALSE, $response);
$updated_normalization = $this->serializer->decode((string) $response->getBody(), static::$format);
$this->assertSame($normalization['path'], $updated_normalization['path']);
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheTags() {
return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
}
/**
* Tests GETting a term with a parent term other than the default <root> (0).
*
* @see ::getExpectedNormalizedEntity()
*
* @dataProvider providerTestGetTermWithParent
*/
public function testGetTermWithParent(array $parent_term_ids) {
// Create all possible parent terms.
Term::create(['vid' => Vocabulary::load('camelids')->id()])
->setName('Lamoids')
->save();
Term::create(['vid' => Vocabulary::load('camelids')->id()])
->setName('Wimoids')
->save();
// Modify the entity under test to use the provided parent terms.
$this->entity->set('parent', $parent_term_ids)->save();
$this->initAuthentication();
$url = $this->getEntityResourceUrl();
$url->setOption('query', ['_format' => static::$format]);
$request_options = $this->getAuthenticationRequestOptions('GET');
$this->provisionEntityResource();
$this->setUpAuthorization('GET');
$response = $this->request('GET', $url, $request_options);
$expected = $this->getExpectedNormalizedEntity();
static::recursiveKSort($expected);
$actual = $this->serializer->decode((string) $response->getBody(), static::$format);
static::recursiveKSort($actual);
$this->assertSame($expected, $actual);
}
public function providerTestGetTermWithParent() {
return [
'root parent: [0] (= no parent)' => [
[0],
],
'non-root parent: [2]' => [
[2],
],
'multiple parents: [0,2] (root + non-root parent)' => [
[0, 2],
],
'multiple parents: [3,2] (both non-root parents)' => [
[3, 2],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessCacheability() {
// @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
return parent::getExpectedUnauthorizedAccessCacheability()
->addCacheTags(['taxonomy_term:1']);
}
}
@@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class TermXmlAnonTest extends TermResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}
@@ -0,0 +1,44 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class TermXmlBasicAuthTest extends TermResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}
@@ -0,0 +1,39 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class TermXmlCookieTest extends TermResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
/**
* {@inheritdoc}
*/
public function testPatchPath() {
// Deserialization of the XML format is not supported.
$this->markTestSkipped();
}
}
@@ -0,0 +1,32 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group rest
*/
class VocabularyJsonAnonTest extends VocabularyResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* Disable the GET test coverage due to bug in taxonomy module.
* @todo Fix in https://www.drupal.org/node/2805281: remove this override.
*/
public function testGet() {
$this->markTestSkipped();
}
}
@@ -0,0 +1,34 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group rest
*/
class VocabularyJsonBasicAuthTest extends VocabularyResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,29 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group rest
*/
class VocabularyJsonCookieTest extends VocabularyResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -0,0 +1,83 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
abstract class VocabularyResourceTestBase extends EntityResourceTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['taxonomy'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'taxonomy_vocabulary';
/**
* @var \Drupal\taxonomy\VocabularyInterface
*/
protected $entity;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
$this->grantPermissionsToTestedRole(['administer taxonomy']);
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$vocabulary = Vocabulary::create([
'name' => 'Llama',
'vid' => 'llama',
]);
$vocabulary->save();
return $vocabulary;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'uuid' => $this->entity->uuid(),
'vid' => 'llama',
'langcode' => 'en',
'status' => TRUE,
'dependencies' => [],
'name' => 'Llama',
'description' => NULL,
'hierarchy' => 0,
'weight' => 0,
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
// @todo Update in https://www.drupal.org/node/2300677.
}
/**
* {@inheritdoc}
*/
protected function getExpectedUnauthorizedAccessMessage($method) {
if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
return parent::getExpectedUnauthorizedAccessMessage($method);
}
if ($method === 'GET') {
return "The following permissions are required: 'access taxonomy overview' OR 'administer taxonomy'.";
}
return parent::getExpectedUnauthorizedAccessMessage($method);
}
}
@@ -0,0 +1,26 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class VocabularyXmlAnonTest extends VocabularyResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
}
@@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class VocabularyXmlBasicAuthTest extends VocabularyResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* @group rest
*/
class VocabularyXmlCookieTest extends VocabularyResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -50,12 +50,12 @@ class TaxonomyQueryAlterTest extends BrowserTestBase {
$this->setupQueryTagTestHooks();
$loaded_terms = $term_storage->loadParents($terms[2]->id());
$this->assertEqual(count($loaded_terms), 1, 'All parent terms were loaded');
$this->assertQueryTagTestResult(2, 1, 'TermStorage::loadParents()');
$this->assertQueryTagTestResult(3, 1, 'TermStorage::loadParents()');
$this->setupQueryTagTestHooks();
$loaded_terms = $term_storage->loadChildren($terms[1]->id());
$this->assertEqual(count($loaded_terms), 1, 'All child terms were loaded');
$this->assertQueryTagTestResult(2, 1, 'TermStorage::loadChildren()');
$this->assertQueryTagTestResult(3, 1, 'TermStorage::loadChildren()');
$this->setupQueryTagTestHooks();
$query = db_select('taxonomy_term_data', 't');
@@ -2,7 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Language\LanguageInterface;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\Entity\Term;
@@ -20,7 +19,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),
]);
@@ -17,7 +17,7 @@ trait TaxonomyTranslationTestTrait {
/**
* The vocabulary.
*
* @var \Drupal\taxonomy\Entity\Vocabulary;
* @var \Drupal\taxonomy\Entity\Vocabulary
*/
protected $vocabulary;
@@ -0,0 +1,124 @@
<?php
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\TermInterface;
use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
/**
* Tests the taxonomy term access permissions.
*
* @group taxonomy
*/
class TermAccessTest extends TaxonomyTestBase {
use AssertPageCacheContextsAndTagsTrait;
/**
* Test access control functionality for taxonomy terms.
*/
public function testTermAccess() {
$assert_session = $this->assertSession();
$vocabulary = $this->createVocabulary();
// Create two terms.
$published_term = Term::create([
'vid' => $vocabulary->id(),
'name' => 'Published term',
'status' => 1,
]);
$published_term->save();
$unpublished_term = Term::create([
'vid' => $vocabulary->id(),
'name' => 'Unpublished term',
'status' => 0,
]);
$unpublished_term->save();
// Start off logged in as admin.
$this->drupalLogin($this->drupalCreateUser(['administer taxonomy']));
// Test the 'administer taxonomy' permission.
$this->drupalGet('taxonomy/term/' . $published_term->id());
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($published_term, 'view', TRUE);
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($unpublished_term, 'view', TRUE);
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($published_term, 'update', TRUE);
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($unpublished_term, 'update', TRUE);
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($published_term, 'delete', TRUE);
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($unpublished_term, 'delete', TRUE);
// Test the 'access content' permission.
$this->drupalLogin($this->drupalCreateUser(['access content']));
$this->drupalGet('taxonomy/term/' . $published_term->id());
$assert_session->statusCodeEquals(200);
$this->assertTermAccess($published_term, 'view', TRUE);
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
$assert_session->statusCodeEquals(403);
$this->assertTermAccess($unpublished_term, 'view', FALSE, "The 'access content' permission is required and the taxonomy term must be published.");
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/edit');
$assert_session->statusCodeEquals(403);
$this->assertTermAccess($published_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/edit');
$assert_session->statusCodeEquals(403);
$this->assertTermAccess($unpublished_term, 'update', FALSE, "The following permissions are required: 'edit terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
$this->drupalGet('taxonomy/term/' . $published_term->id() . '/delete');
$assert_session->statusCodeEquals(403);
$this->assertTermAccess($published_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
$this->drupalGet('taxonomy/term/' . $unpublished_term->id() . '/delete');
$assert_session->statusCodeEquals(403);
$this->assertTermAccess($unpublished_term, 'delete', FALSE, "The following permissions are required: 'delete terms in {$vocabulary->id()}' OR 'administer taxonomy'.");
// Install the Views module and repeat the checks for the 'view' permission.
\Drupal::service('module_installer')->install(['views'], TRUE);
$this->rebuildContainer();
$this->drupalGet('taxonomy/term/' . $published_term->id());
$assert_session->statusCodeEquals(200);
// @todo Change this assertion to expect a 403 status code when
// https://www.drupal.org/project/drupal/issues/2983070 is fixed.
$this->drupalGet('taxonomy/term/' . $unpublished_term->id());
$assert_session->statusCodeEquals(404);
}
/**
* Checks access on taxonomy term.
*
* @param \Drupal\taxonomy\TermInterface $term
* A taxonomy term entity.
* @param $access_operation
* The entity operation, e.g. 'view', 'edit', 'delete', etc.
* @param bool $access_allowed
* Whether the current use has access to the given operation or not.
* @param string $access_reason
* (optional) The reason of the access result.
*/
protected function assertTermAccess(TermInterface $term, $access_operation, $access_allowed, $access_reason = '') {
$access_result = $term->access($access_operation, NULL, TRUE);
$this->assertSame($access_allowed, $access_result->isAllowed());
if ($access_reason) {
$this->assertSame($access_reason, $access_result->getReason());
}
}
}
@@ -2,9 +2,9 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\system\Tests\Entity\EntityWithUriCacheTagsTestBase;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\system\Functional\Entity\EntityWithUriCacheTagsTestBase;
/**
* Tests the Taxonomy term entity's cache tags.
@@ -2,7 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
/**
@@ -49,7 +48,7 @@ class TermIndexTest extends TaxonomyTestBase {
// Create a vocabulary and add two term reference fields to article nodes.
$this->vocabulary = $this->createVocabulary();
$this->fieldName1 = Unicode::strtolower($this->randomMachineName());
$this->fieldName1 = mb_strtolower($this->randomMachineName());
$handler_settings = [
'target_bundles' => [
$this->vocabulary->id() => $this->vocabulary->id(),
@@ -69,7 +68,7 @@ class TermIndexTest extends TaxonomyTestBase {
])
->save();
$this->fieldName2 = Unicode::strtolower($this->randomMachineName());
$this->fieldName2 = mb_strtolower($this->randomMachineName());
$this->createEntityReferenceField('node', 'article', $this->fieldName2, NULL, 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
entity_get_form_display('node', 'article', 'default')
@@ -0,0 +1,101 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\taxonomy\Entity\Term;
/**
* Ensure that the taxonomy updates are running as expected.
*
* @group taxonomy
* @group Update
* @group legacy
*/
class TaxonomyParentUpdateTest extends UpdatePathTestBase {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $db;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->db = $this->container->get('database');
}
/**
* {@inheritdoc}
*/
public function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz',
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.php',
];
}
/**
* Tests taxonomy term parents update.
*
* @see taxonomy_update_8501()
* @see taxonomy_update_8502()
* @see taxonomy_update_8503()
*/
public function testTaxonomyUpdateParents() {
// Force the update hook to only run one term per batch.
drupal_rewrite_settings([
'settings' => [
'entity_update_batch_size' => (object) [
'value' => 1,
'required' => TRUE,
],
],
]);
// Run updates.
$this->runUpdates();
/** @var \Drupal\taxonomy\TermInterface $term */
$term = Term::load(1);
$parents = [2, 3];
$this->assertCount(2, $term->parent);
$this->assertTrue(in_array($term->parent[0]->entity->id(), $parents));
$this->assertTrue(in_array($term->parent[1]->entity->id(), $parents));
$term = Term::load(2);
$parents = [0, 3];
$this->assertCount(2, $term->parent);
$this->assertTrue(in_array($term->parent[0]->target_id, $parents));
$this->assertTrue(in_array($term->parent[1]->target_id, $parents));
$term = Term::load(3);
$this->assertCount(1, $term->parent);
// Target ID is returned as string.
$this->assertSame(0, (int) $term->get('parent')[0]->target_id);
// Test if the view has been converted to use the {taxonomy_term__parent}
// table instead of the {taxonomy_term_hierarchy} table.
$view = $this->config("views.view.test_taxonomy_parent");
$relationship_base_path = 'display.default.display_options.relationships.parent';
$this->assertSame('taxonomy_term__parent', $view->get("$relationship_base_path.table"));
$this->assertSame('parent_target_id', $view->get("$relationship_base_path.field"));
$filters_base_path_1 = 'display.default.display_options.filters.parent';
$this->assertSame('taxonomy_term__parent', $view->get("$filters_base_path_1.table"));
$this->assertSame('parent_target_id', $view->get("$filters_base_path_1.field"));
$filters_base_path_2 = 'display.default.display_options.filters.parent';
$this->assertSame('taxonomy_term__parent', $view->get("$filters_base_path_2.table"));
$this->assertSame('parent_target_id', $view->get("$filters_base_path_2.field"));
// The {taxonomy_term_hierarchy} table has been removed.
$this->assertFalse($this->db->schema()->tableExists('taxonomy_term_hierarchy'));
}
}
@@ -0,0 +1,139 @@
<?php
namespace Drupal\Tests\taxonomy\Functional\Update;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\user\Entity\User;
use Drupal\views\Entity\View;
/**
* Tests the upgrade path for taxonomy terms.
*
* @group taxonomy
* @group Update
* @group legacy
*/
class TaxonomyTermUpdatePathTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz',
__DIR__ . '/../../../fixtures/update/drupal-8.views-taxonomy-term-publishing-status-2981887.php',
];
}
/**
* Tests the conversion of taxonomy terms to be publishable.
*
* @see taxonomy_update_8601()
*/
public function testPublishable() {
$this->runUpdates();
// Log in as user 1.
$account = User::load(1);
$account->passRaw = 'drupal';
$this->drupalLogin($account);
// Make sure our vocabulary exists.
$this->drupalGet('admin/structure/taxonomy/manage/test_vocabulary/overview');
// Make sure our terms exist.
$assert_session = $this->assertSession();
$assert_session->pageTextContains('Test root term');
$assert_session->pageTextContains('Test child term');
$this->drupalGet('taxonomy/term/3');
$assert_session->statusCodeEquals('200');
// Make sure the terms are still translated.
$this->drupalGet('taxonomy/term/2/translations');
$assert_session->linkExists('Test root term - Spanish');
$storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
// Check that the 'content_translation_status' field has been updated
// correctly.
/** @var \Drupal\taxonomy\TermInterface $term */
$term = $storage->load(2);
$translation = $term->getTranslation('es');
$this->assertTrue($translation->isPublished());
// Check that taxonomy terms can be created, saved and then loaded.
$term = $storage->create([
'name' => 'Test term',
'vid' => 'tags',
]);
$term->save();
$term = $storage->loadUnchanged($term->id());
$this->assertEquals('Test term', $term->label());
$this->assertEquals('tags', $term->bundle());
$this->assertTrue($term->isPublished());
// Check that the term can be unpublished.
$term->setUnpublished();
$term->save();
$term = $storage->loadUnchanged($term->id());
$this->assertFalse($term->isPublished());
// Test the update does not run when a status field already exists.
module_load_install('taxonomy');
$this->assertEquals('The publishing status field has <strong>not</strong> been added to taxonomy terms. See <a href="https://www.drupal.org/node/2985366">this page</a> for more information on how to install it.', (string) taxonomy_update_8601());
// Test the message can be overridden.
\Drupal::state()->set('taxonomy_update_8601_skip_message', 'Another message');
$this->assertEquals('Another message', (string) taxonomy_update_8601());
}
/**
* Tests handling of the publishing status in taxonomy term views updates.
*
* @see taxonomy_post_update_handle_publishing_status_addition_in_views()
*/
public function testPublishingStatusUpdateForTaxonomyTermViews() {
// Check that the test view was previously using the
// 'content_translation_status' field.
$config = \Drupal::config('views.view.test_taxonomy_term_view_with_content_translation_status');
$display_options = $config->get('display.default.display_options');
$this->assertEquals('content_translation_status', $display_options['fields']['content_translation_status']['field']);
$this->assertEquals('content_translation_status', $display_options['filters']['content_translation_status']['field']);
$this->assertEquals('content_translation_status', $display_options['sorts']['content_translation_status']['field']);
// Check a test view without any filter.
$config = \Drupal::config('views.view.test_taxonomy_term_view_without_content_translation_status');
$display_options = $config->get('display.default.display_options');
$this->assertEmpty($display_options['filters']);
$this->runUpdates();
// Check that a view which had a field, filter and a sort on the
// 'content_translation_status' field has been updated to use the new
// 'status' field.
$view = View::load('test_taxonomy_term_view_with_content_translation_status');
foreach ($view->get('display') as $display) {
$this->assertEquals('status', $display['display_options']['fields']['content_translation_status']['field']);
$this->assertEquals('status', $display['display_options']['sorts']['content_translation_status']['field']);
$this->assertEquals('status', $display['display_options']['filters']['content_translation_status']['field']);
}
// Check that a view without any filters has been updated to include a
// filter for the 'status' field.
$view = View::load('test_taxonomy_term_view_without_content_translation_status');
foreach ($view->get('display') as $display) {
$this->assertNotEmpty($display['display_options']['filters']);
$this->assertEquals('status', $display['display_options']['filters']['status']['field']);
}
}
/**
* {@inheritdoc}
*/
protected function replaceUser1() {
// Do not replace the user from our dump.
}
}
@@ -2,11 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional\Views;
use Drupal\field\Entity\FieldConfig;
use Drupal\views\Views;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Tests the representative node relationship for terms.
*
@@ -21,73 +16,6 @@ class TaxonomyDefaultArgumentTest extends TaxonomyTestBase {
*/
public static $testViews = ['taxonomy_default_argument_test'];
/**
* Tests the relationship.
*/
public function testNodePath() {
$view = Views::getView('taxonomy_default_argument_test');
$request = Request::create($this->nodes[0]->url());
$request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
$request->server->set('SCRIPT_FILENAME', 'index.php');
$response = $this->container->get('http_kernel')
->handle($request, HttpKernelInterface::SUB_REQUEST);
$view->setRequest($request);
$view->setResponse($response);
$view->initHandlers();
$expected = implode(',', [$this->term1->id(), $this->term2->id()]);
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
$view->destroy();
}
public function testNodePathWithViewSelection() {
// Change the term entity reference field to use a view as selection plugin.
\Drupal::service('module_installer')->install(['entity_reference_test']);
$field_name = 'field_' . $this->vocabulary->id();
$field = FieldConfig::loadByName('node', 'article', $field_name);
$field->setSetting('handler', 'views');
$field->setSetting('handler_settings', [
'view' => [
'view_name' => 'test_entity_reference',
'display_name' => 'entity_reference_1',
],
]);
$field->save();
$view = Views::getView('taxonomy_default_argument_test');
$request = Request::create($this->nodes[0]->url());
$request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
$request->server->set('SCRIPT_FILENAME', 'index.php');
$response = $this->container->get('http_kernel')->handle($request, HttpKernelInterface::SUB_REQUEST);
$view->setRequest($request);
$view->setResponse($response);
$view->initHandlers();
$expected = implode(',', [$this->term1->id(), $this->term2->id()]);
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
}
public function testTermPath() {
$view = Views::getView('taxonomy_default_argument_test');
$request = Request::create($this->term1->url());
$request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
$request->server->set('SCRIPT_FILENAME', 'index.php');
$response = $this->container->get('http_kernel')->handle($request, HttpKernelInterface::SUB_REQUEST);
$view->setRequest($request);
$view->setResponse($response);
$view->initHandlers();
$expected = $this->term1->id();
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
}
/**
* Tests escaping of page title when the taxonomy plugin provides it.
*/
@@ -199,7 +199,7 @@ class TaxonomyIndexTidUiTest extends UITestBase {
// Select 'Term' and 'Vocabulary' as filters.
$edit = [
'name[taxonomy_term_field_data.tid]' => TRUE,
'name[taxonomy_term_field_data.vid]' => TRUE
'name[taxonomy_term_field_data.vid]' => TRUE,
];
$this->drupalPostForm('admin/structure/views/nojs/add-handler/test_taxonomy_term_name/default/filter', $edit, 'Add and configure filter criteria');
// Select 'Empty Vocabulary' and 'Autocomplete' from the list of options.
@@ -61,24 +61,24 @@ class TaxonomyRelationshipTest extends TaxonomyTestBase {
$this->assertEqual($views_data['table']['join']['taxonomy_term_field_data']['field'], 'tid');
$this->assertEqual($views_data['table']['join']['node_field_data']['left_field'], 'nid');
$this->assertEqual($views_data['table']['join']['node_field_data']['field'], 'nid');
$this->assertEqual($views_data['table']['join']['taxonomy_term_hierarchy']['left_field'], 'tid');
$this->assertEqual($views_data['table']['join']['taxonomy_term_hierarchy']['field'], 'tid');
$this->assertEqual($views_data['table']['join']['taxonomy_term__parent']['left_field'], 'entity_id');
$this->assertEqual($views_data['table']['join']['taxonomy_term__parent']['field'], 'tid');
// Check the generated views data of taxonomy_term_hierarchy.
$views_data = Views::viewsData()->get('taxonomy_term_hierarchy');
// Check the generated views data of taxonomy_term__parent.
$views_data = Views::viewsData()->get('taxonomy_term__parent');
// Check the table join data.
$this->assertEqual($views_data['table']['join']['taxonomy_term_hierarchy']['left_field'], 'tid');
$this->assertEqual($views_data['table']['join']['taxonomy_term_hierarchy']['field'], 'parent');
$this->assertEqual($views_data['table']['join']['taxonomy_term__parent']['left_field'], 'entity_id');
$this->assertEqual($views_data['table']['join']['taxonomy_term__parent']['field'], 'parent_target_id');
$this->assertEqual($views_data['table']['join']['taxonomy_term_field_data']['left_field'], 'tid');
$this->assertEqual($views_data['table']['join']['taxonomy_term_field_data']['field'], 'tid');
$this->assertEqual($views_data['table']['join']['taxonomy_term_field_data']['field'], 'entity_id');
// Check the parent relationship data.
$this->assertEqual($views_data['parent']['relationship']['base'], 'taxonomy_term_field_data');
$this->assertEqual($views_data['parent']['relationship']['field'], 'parent');
$this->assertEqual($views_data['parent']['relationship']['label'], t('Parent'));
$this->assertEqual($views_data['parent']['relationship']['id'], 'standard');
$this->assertEqual($views_data['parent_target_id']['relationship']['base'], 'taxonomy_term_field_data');
$this->assertEqual($views_data['parent_target_id']['relationship']['base field'], 'tid');
$this->assertEqual($views_data['parent_target_id']['relationship']['label'], t('Parent'));
$this->assertEqual($views_data['parent_target_id']['relationship']['id'], 'standard');
// Check the parent filter and argument data.
$this->assertEqual($views_data['parent']['filter']['id'], 'numeric');
$this->assertEqual($views_data['parent']['argument']['id'], 'taxonomy');
$this->assertEqual($views_data['parent_target_id']['filter']['id'], 'numeric');
$this->assertEqual($views_data['parent_target_id']['argument']['id'], 'taxonomy');
// Check an actual test view.
$view = Views::getView('test_taxonomy_term_relationship');
@@ -95,7 +95,7 @@ class TaxonomyRelationshipTest extends TaxonomyTestBase {
if (!$index) {
$this->assertTrue($row->_relationship_entities['parent'] instanceof TermInterface);
$this->assertEqual($row->_relationship_entities['parent']->id(), $this->term2->id());
$this->assertEqual($row->taxonomy_term_field_data_taxonomy_term_hierarchy_tid, $this->term2->id());
$this->assertEqual($row->taxonomy_term_field_data_taxonomy_term__parent_tid, $this->term2->id());
}
$this->assertTrue($row->_relationship_entities['nid'] instanceof NodeInterface);
$this->assertEqual($row->_relationship_entities['nid']->id(), $this->nodes[$index]->id());
@@ -2,7 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional\Views;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\node\Entity\Node;
@@ -50,7 +49,7 @@ class TaxonomyTermViewTest extends TaxonomyTestBase {
// Create a vocabulary and add two term reference fields to article nodes.
$this->fieldName1 = Unicode::strtolower($this->randomMachineName());
$this->fieldName1 = mb_strtolower($this->randomMachineName());
$handler_settings = [
'target_bundles' => [
@@ -2,7 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\field\Entity\FieldConfig;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\field\Entity\FieldStorageConfig;
@@ -144,12 +143,12 @@ class VocabularyCrudTest extends TaxonomyTestBase {
public function testUninstallReinstall() {
// Field storages and fields attached to taxonomy term bundles should be
// removed when the module is uninstalled.
$field_name = Unicode::strtolower($this->randomMachineName() . '_field_name');
$field_name = mb_strtolower($this->randomMachineName() . '_field_name');
$storage_definition = [
'field_name' => $field_name,
'entity_type' => 'taxonomy_term',
'type' => 'text',
'cardinality' => 4
'cardinality' => 4,
];
FieldStorageConfig::create($storage_definition)->save();
$field_definition = [
@@ -165,7 +164,7 @@ class VocabularyCrudTest extends TaxonomyTestBase {
// installed for testing below.
$this->vocabulary->unsetThirdPartySetting('taxonomy_crud', 'foo');
require_once \Drupal::root() . '/core/includes/install.inc';
require_once $this->root . '/core/includes/install.inc';
$this->container->get('module_installer')->uninstall(['taxonomy']);
$this->container->get('module_installer')->install(['taxonomy']);
@@ -2,7 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\language\Entity\ContentLanguageSettings;
@@ -43,7 +42,7 @@ class VocabularyLanguageTest extends TaxonomyTestBase {
$this->assertField('edit-langcode', 'The language selector field was found on the page.');
// Create the vocabulary.
$vid = Unicode::strtolower($this->randomMachineName());
$vid = mb_strtolower($this->randomMachineName());
$edit['name'] = $this->randomMachineName();
$edit['description'] = $this->randomMachineName();
$edit['langcode'] = 'aa';
@@ -72,7 +71,7 @@ class VocabularyLanguageTest extends TaxonomyTestBase {
// the terms are saved.
$edit = [
'name' => $this->randomMachineName(),
'vid' => Unicode::strtolower($this->randomMachineName()),
'vid' => mb_strtolower($this->randomMachineName()),
'default_language[langcode]' => 'bb',
'default_language[language_alterable]' => TRUE,
];
@@ -83,6 +83,7 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkExists('Add term');
$assert_session->buttonExists('Save');
$assert_session->pageTextContains('Weight');
$assert_session->fieldExists('Weight');
$assert_session->pageTextContains($edit_help_text);
// Visit vocabulary overview without terms. 'Add term' should be shown.
@@ -108,7 +109,8 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkNotExists('Edit');
$assert_session->linkNotExists('Delete');
$assert_session->buttonNotExists('Save');
$assert_session->pageTextNotContains('Weight');
$assert_session->pageTextContains('Weight');
$assert_session->fieldNotExists('Weight');
$assert_session->linkNotExists('Add term');
$assert_session->pageTextContains($no_edit_help_text);
@@ -132,6 +134,7 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkNotExists('Delete');
$assert_session->buttonExists('Save');
$assert_session->pageTextContains('Weight');
$assert_session->fieldExists('Weight');
$assert_session->linkNotExists('Add term');
$assert_session->pageTextContains($edit_help_text);
@@ -154,7 +157,8 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkExists('Delete');
$assert_session->linkNotExists('Add term');
$assert_session->buttonNotExists('Save');
$assert_session->pageTextNotContains('Weight');
$assert_session->pageTextContains('Weight');
$assert_session->fieldNotExists('Weight');
$assert_session->pageTextContains($no_edit_help_text);
// Visit vocabulary overview without terms. 'Add term' should not be shown.
@@ -179,6 +183,7 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkNotExists('Add term');
$assert_session->buttonExists('Save');
$assert_session->pageTextContains('Weight');
$assert_session->fieldExists('Weight');
$assert_session->pageTextContains($edit_help_text);
// Visit vocabulary overview without terms. 'Add term' should not be shown.
@@ -201,7 +206,8 @@ class VocabularyPermissionsTest extends TaxonomyTestBase {
$assert_session->linkNotExists('Delete');
$assert_session->linkExists('Add term');
$assert_session->buttonNotExists('Save');
$assert_session->pageTextNotContains('Weight');
$assert_session->pageTextContains('Weight');
$assert_session->fieldNotExists('Weight');
$assert_session->pageTextContains($no_edit_help_text);
// Visit vocabulary overview without terms. 'Add term' should not be shown.
@@ -2,8 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
/**
* Tests content translation for vocabularies.
*
@@ -39,7 +37,7 @@ class VocabularyTranslationTest extends TaxonomyTestBase {
$this->assertField('edit-default-language-content-translation', 'The content translation checkbox is present on the page.');
// Create the vocabulary.
$vid = Unicode::strtolower($this->randomMachineName());
$vid = mb_strtolower($this->randomMachineName());
$edit['name'] = $this->randomMachineName();
$edit['description'] = $this->randomMachineName();
$edit['langcode'] = 'en';
@@ -2,8 +2,6 @@
namespace Drupal\Tests\taxonomy\Functional;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Url;
use Drupal\taxonomy\Entity\Vocabulary;
@@ -39,7 +37,7 @@ class VocabularyUiTest extends TaxonomyTestBase {
// Create a new vocabulary.
$this->clickLink(t('Add vocabulary'));
$edit = [];
$vid = Unicode::strtolower($this->randomMachineName());
$vid = mb_strtolower($this->randomMachineName());
$edit['name'] = $this->randomMachineName();
$edit['description'] = $this->randomMachineName();
$edit['vid'] = $vid;
@@ -131,7 +129,7 @@ class VocabularyUiTest extends TaxonomyTestBase {
*/
public function testTaxonomyAdminDeletingVocabulary() {
// Create a vocabulary.
$vid = Unicode::strtolower($this->randomMachineName());
$vid = mb_strtolower($this->randomMachineName());
$edit = [
'name' => $this->randomMachineName(),
'vid' => $vid,
@@ -92,7 +92,7 @@ class MigrateTaxonomyTermTest extends MigrateDrupal6TestBase {
$this->assertSame($values['vid'], $term->vid->target_id);
$this->assertSame((string) $values['weight'], $term->weight->value);
if ($values['parent'] === [0]) {
$this->assertNull($term->parent->target_id);
$this->assertSame(0, (int) $term->parent->target_id);
}
else {
$parents = [];
@@ -32,7 +32,7 @@ class MigrateTaxonomyVocabularyTest extends MigrateDrupal6TestBase {
for ($i = 0; $i < 3; $i++) {
$j = $i + 1;
$vocabulary = Vocabulary::load("vocabulary_{$j}_i_{$i}_");
$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("description of vocabulary $j (i=$i)", $vocabulary->getDescription());
$this->assertSame($i, $vocabulary->getHierarchy());
@@ -14,7 +14,13 @@ class MigrateTaxonomyVocabularyTranslationTest extends MigrateDrupal6TestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['language', 'taxonomy'];
public static $modules = [
'config_translation',
'language',
'taxonomy',
// Required for translation migrations.
'migrate_drupal_multilingual',
];
/**
* {@inheritdoc}
@@ -31,7 +31,7 @@ class MigrateTermNodeRevisionTest extends MigrateDrupal6TestBase {
* Tests the Drupal 6 term-node revision association to Drupal 8 migration.
*/
public function testTermRevisionNode() {
$node = \Drupal::entityManager()->getStorage('node')->loadRevision(2);
$node = \Drupal::entityManager()->getStorage('node')->loadRevision(2001);
$this->assertSame(2, count($node->field_vocabulary_3_i_2_));
$this->assertSame('4', $node->field_vocabulary_3_i_2_[0]->target_id);
$this->assertSame('5', $node->field_vocabulary_3_i_2_[1]->target_id);
@@ -45,7 +45,7 @@ class MigrateVocabularyEntityDisplayTest extends MigrateDrupal6TestBase {
$this->assertSame('entity_reference_label', $component['type']);
$this->assertSame(20, $component['weight']);
// Test the Id map.
$this->assertSame(['node', 'article', 'default', 'field_tags'], $this->getMigration('d6_vocabulary_entity_display')->getIdMap()->lookupDestinationID([4, 'article']));
$this->assertSame(['node', 'article', 'default', 'field_tags'], $this->getMigration('d6_vocabulary_entity_display')->getIdMap()->lookupDestinationId([4, 'article']));
// Tests that a vocabulary named like a D8 base field will be migrated and
// prefixed with 'field_' to avoid conflicts.
@@ -45,7 +45,7 @@ class MigrateVocabularyEntityFormDisplayTest extends MigrateDrupal6TestBase {
$this->assertSame('options_select', $component['type']);
$this->assertSame(20, $component['weight']);
// Test the Id map.
$this->assertSame(['node', 'article', 'default', 'field_tags'], $this->getMigration('d6_vocabulary_entity_form_display')->getIdMap()->lookupDestinationID([4, 'article']));
$this->assertSame(['node', 'article', 'default', 'field_tags'], $this->getMigration('d6_vocabulary_entity_form_display')->getIdMap()->lookupDestinationId([4, 'article']));
// Test the term widget tags setting.
$entity_form_display = EntityFormDisplay::load('node.story.default');
@@ -58,7 +58,7 @@ class MigrateVocabularyFieldInstanceTest extends MigrateDrupal6TestBase {
$this->assertSame(['field_tags'], $settings['handler_settings']['target_bundles'], 'The target_bundles handler setting is correct.');
$this->assertSame(TRUE, $settings['handler_settings']['auto_create'], 'The "auto_create" setting is correct.');
$this->assertSame(['node', 'article', 'field_tags'], $this->getMigration('d6_vocabulary_field_instance')->getIdMap()->lookupDestinationID([4, 'article']));
$this->assertSame(['node', 'article', 'field_tags'], $this->getMigration('d6_vocabulary_field_instance')->getIdMap()->lookupDestinationId([4, 'article']));
// Test the the field vocabulary_1_i_0_.
$field_id = 'node.story.field_vocabulary_1_i_0_';
@@ -39,7 +39,7 @@ class MigrateVocabularyFieldTest extends MigrateDrupal6TestBase {
$this->assertSame('taxonomy_term', $settings['target_type'], "Target type is correct.");
$this->assertSame(1, $field_storage->getCardinality(), "Field cardinality in 1.");
$this->assertSame(['node', 'field_tags'], $this->getMigration('d6_vocabulary_field')->getIdMap()->lookupDestinationID([4]), "Test IdMap");
$this->assertSame(['node', 'field_tags'], $this->getMigration('d6_vocabulary_field')->getIdMap()->lookupDestinationId([4]), "Test IdMap");
// Tests that a vocabulary named like a D8 base field will be migrated and
// prefixed with 'field_' to avoid conflicts.
@@ -47,7 +47,7 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
'd7_field',
'd7_taxonomy_vocabulary',
'd7_field_instance',
'd7_taxonomy_term'
'd7_taxonomy_term',
]);
}
@@ -104,7 +104,11 @@ class MigrateTaxonomyTermTest extends MigrateDrupal7TestBase {
*/
public function testTaxonomyTerms() {
$this->assertEntity(1, 'General discussion', 'forums', '', NULL, 2);
$this->assertEntity(2, 'Term1', 'test_vocabulary', 'The first term.', 'filtered_html', 0, [], NULL, 3);
// Tests that terms that used the Drupal 7 Title module and that have their
// name and description replaced by real fields are correctly migrated.
$this->assertEntity(2, 'Term1 (This is a real field!)', 'test_vocabulary', 'The first term. (This is a real field!)', 'filtered_html', 0, [], NULL, 3);
$this->assertEntity(3, 'Term2', 'test_vocabulary', 'The second term.', 'filtered_html');
$this->assertEntity(4, 'Term3', 'test_vocabulary', 'The third term.', 'full_html', 0, [3], 6);
$this->assertEntity(5, 'Custom Forum', 'forums', 'Where the cool kids are.', NULL, 3);
@@ -27,16 +27,16 @@ class TermSourceWithVocabularyFilterTest extends TermTest {
[
'tid' => 1,
'vid' => 5,
'name' => 'name value 1',
'description' => 'description value 1',
'name' => 'name value 1 (name_field)',
'description' => 'description value 1 (description_field)',
'weight' => 0,
'parent' => [0],
],
[
'tid' => 4,
'vid' => 5,
'name' => 'name value 4',
'description' => 'description value 4',
'name' => 'name value 4 (name_field)',
'description' => 'description value 4 (description_field)',
'weight' => 1,
'parent' => [1],
],
@@ -126,19 +126,57 @@ class TermTest extends MigrateSqlSourceTestBase {
'machine_name' => 'categories',
],
];
$tests[0]['source_data']['field_config'] = [
[
'id' => '3',
'translatable' => '0',
],
[
'id' => '4',
'translatable' => '1',
],
[
'id' => '5',
'translatable' => '1',
],
];
$tests[0]['source_data']['field_config_instance'] = [
[
'id' => '2',
'field_id' => 3,
'field_name' => 'field_term_field',
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'data' => 'a:0:{}',
'deleted' => 0,
],
[
'id' => '3',
'field_id' => 3,
'field_name' => 'field_term_field',
'entity_type' => 'taxonomy_term',
'bundle' => 'categories',
'data' => 'a:0:{}',
'deleted' => 0,
],
[
'id' => '4',
'field_id' => '4',
'field_name' => 'name_field',
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'data' => 'a:0:{}',
'deleted' => '0',
],
[
'id' => '5',
'field_id' => '5',
'field_name' => 'description_field',
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'data' => 'a:0:{}',
'deleted' => '0',
],
];
$tests[0]['source_data']['field_data_field_term_field'] = [
[
@@ -156,6 +194,61 @@ class TermTest extends MigrateSqlSourceTestBase {
'delta' => 0,
],
];
$tests[0]['source_data']['field_data_name_field'] = [
[
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'deleted' => '0',
'entity_id' => '1',
'revision_id' => '1',
'language' => 'und',
'delta' => '0',
'name_field_value' => 'name value 1 (name_field)',
'name_field_format' => NULL,
],
[
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'deleted' => '0',
'entity_id' => '4',
'revision_id' => '4',
'language' => 'und',
'delta' => '0',
'name_field_value' => 'name value 4 (name_field)',
'name_field_format' => NULL,
],
];
$tests[0]['source_data']['field_data_description_field'] = [
[
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'deleted' => '0',
'entity_id' => '1',
'revision_id' => '1',
'language' => 'und',
'delta' => '0',
'description_field_value' => 'description value 1 (description_field)',
'description_field_format' => NULL,
],
[
'entity_type' => 'taxonomy_term',
'bundle' => 'tags',
'deleted' => '0',
'entity_id' => '4',
'revision_id' => '4',
'language' => 'und',
'delta' => '0',
'description_field_value' => 'description value 4 (description_field)',
'description_field_format' => NULL,
],
];
$tests[0]['source_data']['system'] = [
[
'name' => 'title',
'type' => 'module',
'status' => 1,
],
];
$tests[0]['source_data']['variable'] = [
[
'name' => 'forum_containers',
@@ -168,8 +261,8 @@ class TermTest extends MigrateSqlSourceTestBase {
[
'tid' => 1,
'vid' => 5,
'name' => 'name value 1',
'description' => 'description value 1',
'name' => 'name value 1 (name_field)',
'description' => 'description value 1 (description_field)',
'weight' => 0,
'parent' => [0],
],
@@ -192,8 +285,8 @@ class TermTest extends MigrateSqlSourceTestBase {
[
'tid' => 4,
'vid' => 5,
'name' => 'name value 4',
'description' => 'description value 4',
'name' => 'name value 4 (name_field)',
'description' => 'description value 4 (description_field)',
'weight' => 1,
'parent' => [1],
],
@@ -233,16 +326,16 @@ class TermTest extends MigrateSqlSourceTestBase {
[
'tid' => 1,
'vid' => 5,
'name' => 'name value 1',
'description' => 'description value 1',
'name' => 'name value 1 (name_field)',
'description' => 'description value 1 (description_field)',
'weight' => 0,
'parent' => [0],
],
[
'tid' => 4,
'vid' => 5,
'name' => 'name value 4',
'description' => 'description value 4',
'name' => 'name value 4 (name_field)',
'description' => 'description value 4 (description_field)',
'weight' => 1,
'parent' => [1],
],
@@ -0,0 +1,93 @@
<?php
namespace Drupal\Tests\taxonomy\Kernel\Views;
use Drupal\field\Entity\FieldConfig;
use Drupal\views\Views;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* Tests the representative node relationship for terms.
*
* @group taxonomy
*/
class TaxonomyDefaultArgumentTest extends TaxonomyTestBase {
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['taxonomy_default_argument_test'];
/**
* Init view with a request by provided url.
*
* @param string $request_url
* The requested url.
* @param string $view_name
* The name of the view.
*
* @return \Drupal\views\ViewExecutable
* The initiated view.
*
* @throws \Exception
*/
protected function initViewWithRequest($request_url, $view_name = 'taxonomy_default_argument_test') {
$view = Views::getView($view_name);
$request = Request::create($request_url);
$request->server->set('SCRIPT_NAME', $GLOBALS['base_path'] . 'index.php');
$request->server->set('SCRIPT_FILENAME', 'index.php');
$response = $this->container->get('http_kernel')
->handle($request, HttpKernelInterface::SUB_REQUEST);
$view->setRequest($request);
$view->setResponse($response);
$view->initHandlers();
return $view;
}
/**
* Tests the relationship.
*/
public function testNodePath() {
$view = $this->initViewWithRequest($this->nodes[0]->url());
$expected = implode(',', [$this->term1->id(), $this->term2->id()]);
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
$view->destroy();
}
public function testNodePathWithViewSelection() {
// Change the term entity reference field to use a view as selection plugin.
\Drupal::service('module_installer')->install(['entity_reference_test']);
$field_name = 'field_' . $this->vocabulary->id();
$field = FieldConfig::loadByName('node', 'article', $field_name);
$field->setSetting('handler', 'views');
$field->setSetting('handler_settings', [
'view' => [
'view_name' => 'test_entity_reference',
'display_name' => 'entity_reference_1',
],
]);
$field->save();
$view = $this->initViewWithRequest($this->nodes[0]->url());
$expected = implode(',', [$this->term1->id(), $this->term2->id()]);
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
}
public function testTermPath() {
$view = $this->initViewWithRequest($this->term1->url());
$expected = $this->term1->id();
$this->assertEqual($expected, $view->argument['tid']->getDefaultArgument());
}
}
@@ -0,0 +1,92 @@
<?php
namespace Drupal\Tests\taxonomy\Kernel\Views;
use Drupal\Core\Render\RenderContext;
use Drupal\Tests\taxonomy\Functional\TaxonomyTestTrait;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\user\Entity\User;
use Drupal\views\Tests\ViewTestData;
use Drupal\views\Views;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests the taxonomy term VID field handler.
*
* @group taxonomy
*/
class TaxonomyFieldVidTest extends ViewsKernelTestBase {
use TaxonomyTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['taxonomy', 'taxonomy_test_views', 'text', 'filter'];
/**
* Views used by this test.
*
* @var array
*/
public static $testViews = ['test_taxonomy_vid_field'];
/**
* A taxonomy term to use in this test.
*
* @var \Drupal\taxonomy\Entity\Term
*/
protected $term1;
/**
* An admin user.
*
* @var \Drupal\user\Entity\User;
*/
protected $adminUser;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
$this->installEntitySchema('taxonomy_term');
$this->installEntitySchema('user');
$this->installConfig(['filter']);
/** @var \Drupal\taxonomy\Entity\Vocabulary $vocabulary */
$vocabulary = $this->createVocabulary();
$this->term1 = $this->createTerm($vocabulary);
// Create user 1 and set is as the logged in user, so that the logged in
// user has the correct permissions to view the vocabulary name.
$this->adminUser = User::create(['name' => $this->randomString()]);
$this->adminUser->save();
$this->container->get('current_user')->setAccount($this->adminUser);
ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']);
}
/**
* Tests the field handling for the Vocabulary ID.
*/
public function testViewsHandlerVidField() {
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$view = Views::getView('test_taxonomy_vid_field');
$this->executeView($view);
$actual = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['vid']->advancedRender($view->result[0]);
});
$vocabulary = Vocabulary::load($this->term1->bundle());
$expected = $vocabulary->get('name');
$this->assertEquals($expected, $actual);
}
}
@@ -0,0 +1,184 @@
<?php
namespace Drupal\Tests\taxonomy\Kernel\Views;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
use Drupal\Tests\node\Traits\NodeCreationTrait;
use Drupal\Tests\views\Kernel\ViewsKernelTestBase;
use Drupal\views\Tests\ViewTestData;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\Entity\Term;
/**
* Base class for views kernel taxonomy tests.
*/
abstract class TaxonomyTestBase extends ViewsKernelTestBase {
use EntityReferenceTestTrait;
use NodeCreationTrait {
createNode as drupalCreateNode;
}
use ContentTypeCreationTrait {
createContentType as drupalCreateContentType;
}
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'taxonomy',
'taxonomy_test_views',
'text',
'node',
'field',
'filter',
];
/**
* Stores the nodes used for the different tests.
*
* @var \Drupal\node\NodeInterface[]
*/
protected $nodes = [];
/**
* The vocabulary used for creating terms.
*
* @var \Drupal\taxonomy\VocabularyInterface
*/
protected $vocabulary;
/**
* Stores the first term used in the different tests.
*
* @var \Drupal\taxonomy\TermInterface
*/
protected $term1;
/**
* Stores the second term used in the different tests.
*
* @var \Drupal\taxonomy\TermInterface
*/
protected $term2;
/**
* {@inheritdoc}
*/
protected function setUp($import_test_views = TRUE) {
parent::setUp($import_test_views);
// Install node config to create body field.
$this->installConfig(['node', 'filter']);
$this->installEntitySchema('user');
$this->installEntitySchema('taxonomy_term');
$this->mockStandardInstall();
if ($import_test_views) {
ViewTestData::createTestViews(get_class($this), ['taxonomy_test_views']);
}
$this->term1 = $this->createTerm();
$this->term2 = $this->createTerm();
$node = [];
$node['type'] = 'article';
$node['field_views_testing_tags'][]['target_id'] = $this->term1->id();
$node['field_views_testing_tags'][]['target_id'] = $this->term2->id();
$this->nodes[] = $this->drupalCreateNode($node);
$this->nodes[] = $this->drupalCreateNode($node);
}
/**
* Provides a workaround for the inability to use the standard profile.
*
* @see https://www.drupal.org/node/1708692
*/
protected function mockStandardInstall() {
$this->drupalCreateContentType([
'type' => 'article',
]);
// Create the vocabulary for the tag field.
$this->vocabulary = Vocabulary::create([
'name' => 'Views testing tags',
'vid' => 'views_testing_tags',
]);
$this->vocabulary->save();
$field_name = 'field_' . $this->vocabulary->id();
$handler_settings = [
'target_bundles' => [
$this->vocabulary->id() => $this->vocabulary->id(),
],
'auto_create' => TRUE,
];
$this->installEntitySchema('node');
$this->createEntityReferenceField('node', 'article', $field_name, 'Tags', 'taxonomy_term', 'default', $handler_settings, FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
$entity_type_manager = $this->container->get('entity_type.manager');
$entity_type_manager
->getStorage('entity_form_display')
->load('node.article.default')
->setComponent($field_name, [
'type' => 'entity_reference_autocomplete_tags',
'weight' => -4,
])
->save();
$view_modes = [
'default',
'teaser',
];
foreach ($view_modes as $view_mode) {
$entity_type_manager
->getStorage('entity_view_display')
->load("node.article.{$view_mode}")
->setComponent($field_name, [
'type' => 'entity_reference_label',
'weight' => 10,
])
->save();
}
}
/**
* Creates and returns a taxonomy term.
*
* @param array $settings
* (optional) An array of values to override the following default
* properties of the term:
* - name: A random string.
* - description: A random string.
* - format: First available text format.
* - vid: Vocabulary ID of self::$vocabulary object.
* - langcode: LANGCODE_NOT_SPECIFIED.
* Defaults to an empty array.
*
* @return \Drupal\taxonomy\Entity\Term
* The created taxonomy term.
*/
protected function createTerm(array $settings = []) {
$filter_formats = filter_formats();
$format = array_pop($filter_formats);
$settings += [
'name' => $this->randomMachineName(),
'description' => $this->randomMachineName(),
// Use the first available text format.
'format' => $format->id(),
'vid' => $this->vocabulary->id(),
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$term = Term::create($settings);
$term->save();
return $term;
}
}
@@ -0,0 +1,18 @@
<?php
namespace Drupal\Tests\taxonomy\Unit\Plugin\migrate\cckfield;
/**
* @group taxonomy
* @group legacy
*/
class TaxonomyTermReferenceCckLegacyTest extends TaxonomyTermReferenceCckTest {
/**
* @expectedDeprecation Deprecated in Drupal 8.6.0, to be removed before Drupal 9.0.0. Use defineValueProcessPipeline() instead. See https://www.drupal.org/node/2944598.
*/
public function testDefineValueProcessPipeline($method = 'processFieldValues') {
parent::testDefineValueProcessPipeline($method);
}
}
@@ -44,11 +44,15 @@ class TaxonomyTermReferenceCckTest extends UnitTestCase {
$this->migration = $migration->reveal();
}
/**
* @covers ::processCckFieldValues
*/
public function testProcessCckFieldValues() {
$this->plugin->processFieldValues($this->migration, 'somefieldname', []);
$this->testDefineValueProcessPipeline('processCckFieldValues');
}
/**
* @covers ::defineValueProcessPipeline
*/
public function testDefineValueProcessPipeline($method = 'defineValueProcessPipeline') {
$this->plugin->$method($this->migration, 'somefieldname', []);
$expected = [
'plugin' => 'sub_process',

Some files were not shown because too many files have changed in this diff Show More