diff --git a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php index ce35238fad..8880652008 100644 --- a/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php +++ b/core/lib/Drupal/Core/Field/EntityReferenceFieldItemList.php @@ -140,22 +140,9 @@ public function defaultValuesFormSubmit(array $element, array &$form, FormStateI * https://www.drupal.org/node/2785673 */ public function removeItemsByTargetId($target_id) { - if (isset($this->list)) { - // Copy list items and re-set the whole list after rather than removing - // one item at a time with removeItem() as that re-keys the list array - // when it is called. This means the wrong items can be removed on - // subsequent iterations. - foreach ($this->list as $delta => $item) { - if ($item->target_id == $target_id) { - unset($this->list[$delta]); - } - } - - // Re-key the items. - $this->rekey(); - } - - return $this; + return $this->filter(function ($item) use ($target_id) { + return $item->target_id != $target_id; + }); } } diff --git a/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.php b/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.php new file mode 100644 index 0000000000..7cf9a0b15e --- /dev/null +++ b/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.php @@ -0,0 +1,62 @@ +insert('config') + ->fields(['collection', 'name', 'data']) + ->values([ + 'collection' => '', + 'name' => "views.view.test_taxonomy_parent", + 'data' => serialize($view_config), + ]) + ->execute(); + +$uuid = \Drupal::service('uuid'); + +// The root tid. +$tids = [0]; + +for ($i = 0; $i < 4; $i++) { + $name = $this->randomString(); + + $tid = $connection->insert('taxonomy_term_data') + ->fields(['vid', 'uuid', 'langcode']) + ->values(['vid' => 'tags', 'uuid' => $uuid->generate(), 'langcode' => 'en']) + ->execute(); + + $connection->insert('taxonomy_term_field_data') + ->fields(['tid', 'vid', 'langcode', 'name', 'weight', 'changed', 'default_langcode']) + ->values(['tid' => $tid, 'vid' => 'tags', 'langcode' => 'en', 'name' => $name, 'weight' => 0, 'changed' => REQUEST_TIME, 'default_langcode' => 1]) + ->execute(); + + $tids[] = $tid; +} + +$hierarchy = [ + // This reads as: tid with index 1 has tids with index 2 and 3 as parents. + 1 => [2, 3], + 2 => [3, 0], + 3 => [0], +]; + +$query = $connection->insert('taxonomy_term_hierarchy')->fields(['tid', 'parent']); + +foreach ($hierarchy as $tid => $parents) { + foreach ($parents as $parent) { + $query->values(['tid' => $tids[$tid], 'parent' => $tids[$parent]]); + } +} + +$query->execute(); diff --git a/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.yml b/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.yml new file mode 100644 index 0000000000..65df6a80e8 --- /dev/null +++ b/core/modules/system/tests/fixtures/update/drupal-8.views-taxonomy-parent-2543726.yml @@ -0,0 +1,134 @@ +langcode: en +status: true +dependencies: + module: + - taxonomy + - user +id: test_taxonomy_parent +label: test_taxonomy_parent +module: views +description: '' +tag: '' +base_table: taxonomy_term_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: + name: + id: name + table: taxonomy_term_data + 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 + 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 + plugin_id: field + type: string + settings: + link_to_entity: true + entity_type: taxonomy_term + entity_field: name + filters: { } + sorts: { } + header: { } + footer: { } + empty: { } + relationships: + parent: + id: parent + table: taxonomy_term__parent + field: parent_target_id + relationship: none + group_type: group + admin_label: Parent + required: true + plugin_id: standard + arguments: { } diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php index 6a11d972e0..e61fa731ab 100644 --- a/core/modules/taxonomy/src/Entity/Vocabulary.php +++ b/core/modules/taxonomy/src/Entity/Vocabulary.php @@ -174,24 +174,4 @@ public static function postDelete(EntityStorageInterface $storage, array $entiti } } - /** - * Gets top-level term IDs of vocabularies. - * - * @param array $vids - * Array of vocabulary IDs. - * - * @return array - * Array of top-level term IDs. - * - * @todo Add this to \Drupal\taxonomy\VocabularyInterface in Drupal 9.0.x. - * https://www.drupal.org/node/2785681 - */ - public static function getTopLevelTids(array $vids) { - $tids = \Drupal::entityQuery('taxonomy_term') - ->condition('vid', $vids, 'IN') - ->condition('parent.target_id', TermInterface::ROOT_ID) - ->execute(); - return array_values($tids); - } - } diff --git a/core/modules/taxonomy/src/VocabularyStorage.php b/core/modules/taxonomy/src/VocabularyStorage.php index fb4efee296..0538e71b49 100644 --- a/core/modules/taxonomy/src/VocabularyStorage.php +++ b/core/modules/taxonomy/src/VocabularyStorage.php @@ -22,7 +22,12 @@ public function resetCache(array $ids = NULL) { * {@inheritdoc} */ public function getToplevelTids($vids) { - return Vocabulary::getTopLevelTids($vids); + $tids = \Drupal::entityQuery('taxonomy_term') + ->condition('vid', $vids, 'IN') + ->condition('parent.target_id', TermInterface::ROOT_ID) + ->execute(); + + return array_values($tids); } } diff --git a/core/modules/taxonomy/src/VocabularyStorageInterface.php b/core/modules/taxonomy/src/VocabularyStorageInterface.php index adb59c721e..1ece404850 100644 --- a/core/modules/taxonomy/src/VocabularyStorageInterface.php +++ b/core/modules/taxonomy/src/VocabularyStorageInterface.php @@ -17,9 +17,6 @@ * * @return array * Array of top-level term IDs. - * - * @deprecated in Drupal 8.3.x, will be removed in Drupal 9.0.x Use - * \Drupal\taxonomy\Entity\Vocabulary::getTopLevelTids($vids) instead. */ public function getToplevelTids($vids); diff --git a/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyParentUpdateTest.php b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyParentUpdateTest.php index 8f88bfd13e..dae3cc2925 100644 --- a/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyParentUpdateTest.php +++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyParentUpdateTest.php @@ -12,7 +12,7 @@ * * @group taxonomy */ -class TaxonomyUpdateTest extends UpdatePathTestBase { +class TaxonomyParentUpdateTest extends UpdatePathTestBase { /** * The database connection. @@ -21,15 +21,6 @@ class TaxonomyUpdateTest extends UpdatePathTestBase { */ protected $db; - /** - * {@inheritdoc} - */ - public function setDatabaseDumpFiles() { - $this->databaseDumpFiles = [ - __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8-rc1.bare.standard.php.gz', - ]; - } - /** * {@inheritdoc} */ @@ -38,6 +29,16 @@ protected function 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. * @@ -47,33 +48,37 @@ protected function setUp() { * @see taxonomy_update_8504() */ public function testTaxonomyUpdateParents() { - $tids = $this->createTerms(); - $vid = $this->createView(); - // Run updates. $this->runUpdates(); + $tids = [ + // This reads as: tid with index 1 has tids with index 2 and 3 as parents. + 1 => [2, 3], + 2 => [3, 0], + 3 => [0], + ]; + /** @var \Drupal\taxonomy\TermInterface $term */ - $term = Term::load($tids[1]); - $parents = [$tids[2], $tids[3]]; + $term = Term::load(1); + $parents = [2, 3]; $this->assertSame(count($term->parent), 2); $this->assertTrue(in_array($term->parent[0]->entity->id(), $parents)); $this->assertTrue(in_array($term->parent[1]->entity->id(), $parents)); - $term = Term::load($tids[2]); - $parents = [0, $tids[3]]; + $term = Term::load(2); + $parents = [0, 3]; $this->assertSame(count($term->parent), 2); $this->assertTrue(in_array($term->parent[0]->target_id, $parents)); $this->assertTrue(in_array($term->parent[1]->target_id, $parents)); - $term = Term::load($tids[3]); + $term = Term::load(3); $this->assertSame(count($term->parent), 1); // Target ID is returned as string. $this->assertSame((int) $term->get('parent')[0]->target_id, 0); // Test if the view has been converted to use {taxonomy_term__parent} table // instead of {taxonomy_term_hierarchy}. - $view = $this->config("views.view.$vid"); + $view = $this->config("views.view.test_taxonomy_parent"); $path = 'display.default.display_options.relationships.parent.table'; $this->assertSame($view->get($path), 'taxonomy_term__parent'); @@ -81,70 +86,4 @@ public function testTaxonomyUpdateParents() { $this->assertFalse($this->db->schema()->tableExists('taxonomy_term_hierarchy')); } - /** - * Creates some terms on a very low level, bypassing the API. - * - * @return array - * A list of created term IDs. - */ - protected function createTerms() { - /** @var \Drupal\Component\Uuid\UuidInterface $uuid */ - $uuid = \Drupal::service('uuid'); - - // The root tid. - $tids = [0]; - for ($i = 0; $i < 4; $i++) { - $name = $this->randomString(); - $tid = $this->db->insert('taxonomy_term_data') - ->fields(['vid', 'uuid', 'langcode']) - ->values(['vid' => 'tags', 'uuid' => $uuid->generate(), 'langcode' => 'en']) - ->execute(); - $this->db->insert('taxonomy_term_field_data') - ->fields(['tid', 'vid', 'langcode', 'name', 'weight', 'changed', 'default_langcode']) - ->values(['tid' => $tid, 'vid' => 'tags', 'langcode' => 'en', 'name' => $name, 'weight' => 0, 'changed' => REQUEST_TIME, 'default_langcode' => 1]) - ->execute(); - $tids[] = $tid; - } - - $hierarchy = [ - // This reads as: tid with index 1 has tids with index 2 and 3 as parents. - 1 => [2, 3], - 2 => [3, 0], - 3 => [0], - ]; - - $query = $this->db->insert('taxonomy_term_hierarchy')->fields(['tid', 'parent']); - foreach ($hierarchy as $tid => $parents) { - foreach ($parents as $parent) { - $query->values(['tid' => $tids[$tid], 'parent' => $tids[$parent]]); - } - } - $query->execute(); - - return $tids; - } - - /** - * Creates a test view using a low level API. - * - * @return string - * The view id. - */ - protected function createView() { - $vid = Unicode::strtolower($this->randomMachineName()); - $file = __DIR__ . '/../../../modules/taxonomy_test_views/test_views/views.view.test_taxonomy_parent.yml'; - $config = Yaml::decode(file_get_contents($file)); - - $this->db->insert('config') - ->fields(['collection', 'name', 'data']) - ->values([ - 'collection' => '', - 'name' => "views.view.$vid", - 'data' => serialize($config), - ]) - ->execute(); - - return $vid; - } - }