Problem/Motivation

Currently, stubs are blindly created for any referenced entity ID on the source site, even if that is a non-existing entity reference ID!

If you're also validating all your migrated entities (like you should be), which is possible since #2745797: Add option to content entity destinations for validation (see https://www.drupal.org/node/3073707 for the CR), then all of those rows will also not trigger validation errors, when in reality they should.

This means you end up getting a false sense of security: your entities are migrated and pass validation.

Proposed resolution

Only create stubs if the source plugin finds a row for the given source ID values.

Remaining tasks

Test coverage.

User interface changes

None.

API changes

TBD

Data model changes

TBD

Release notes snippet

TBD

CommentFileSizeAuthor
#57 core-create_stub_only_when_matching_source_row_exists-3156730-57--10.2.x.patch21.01 KBwim leers
#53 3156730-53.patch20.95 KBfloydm
#53 interdiff.3156730-49-53.txt816 bytesfloydm
#49 interdiff-3156730-47_49.txt927 byteskimberleycgm
#49 3156730-49.patch20.93 KBkimberleycgm
#47 interdiff-3156730-44_47.txt500 bytesgauravvvv
#47 3156730-47.patch20.93 KBgauravvvv
#44 interdiff-3156730-43-44.patch6.38 KBkimberleycgm
#44 core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730-44.patch20.91 KBkimberleycgm
#43 interdiff-3156730-41-43.patch3.34 KBkimberleycgm
#43 core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730-43.patch18.21 KBkimberleycgm
#41 core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730-41.patch16.79 KBwim leers
#2 3156730-2.patch1005 byteswim leers
#4 interdiff.txt1.49 KBwim leers
#4 3156730-4.patch1.08 KBwim leers
#8 core-create_stub_only_when_matching_source_row_exists-3156730-8.patch14.99 KBhuzooka
#8 interdiff-3156730-4-8.txt12.78 KBhuzooka
#11 core-create_stub_only_when_matching_source_row_exists-3156730-8.patch14.99 KBhuzooka
#11 interdiff-3156730-4-8.txt12.78 KBhuzooka
#12 core-create_stub_only_when_matching_source_row_exists-3156730-12.patch19.93 KBhuzooka
#12 interdiff-3156730-8-12.txt9.36 KBhuzooka
#14 core-create_stub_only_when_matching_source_row_exists-3156730-14.patch23.75 KBhuzooka
#14 interdiff-3156730-12-14.txt4.94 KBhuzooka
#16 core-create_stub_only_when_matching_source_row_exists-3156730-16--9.1.x.patch23.75 KBhuzooka
#18 core-create_stub_only_when_matching_source_row_exists--3156730-18--9.1.x.patch23.75 KBhuzooka
#18 core-create_stub_only_when_matching_source_row_exists--3156730-18--9.0.x.patch23.75 KBhuzooka
#18 interdiff-3156730-16-18.txt858 byteshuzooka
#24 core-create_stub_only_when_matching_source_row_exists--3156730-24--9.2.x.patch25.07 KBhuzooka
#24 core-create_stub_only_when_matching_source_row_exists--3156730-24--9.0.x.patch25.07 KBhuzooka
#24 interdiff-3156730-18-24.txt5.95 KBhuzooka
#29 core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730--29.patch21.91 KBhuzooka
#29 core-create_stub_only_when_matching_source_row_exists--9.0.x--3156730--29.patch21.91 KBhuzooka
#29 interdiff-3156730-24-29.txt6.75 KBhuzooka
#31 core-create_stub_only_when_matching_source_row_exists--9.2.x--3156730-31.patch17.33 KBhuzooka
#31 core-create_stub_only_when_matching_source_row_exists--9.0.x--3156730-31.patch17.33 KBhuzooka
#31 interdiff-3156730-29-31.txt11.51 KBhuzooka

Issue fork drupal-3156730

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

Wim Leers created an issue. See original summary.

wim leers’s picture

Status: Active » Needs review
StatusFileSize
new1005 bytes

Status: Needs review » Needs work

The last submitted patch, 2: 3156730-2.patch, failed testing. View results

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new1.49 KB
new1.08 KB

Status: Needs review » Needs work

The last submitted patch, 4: 3156730-4.patch, failed testing. View results

wim leers’s picture

Issue tags: +Needs tests
1) Drupal\Tests\migrate_drupal_ui\Functional\d7\Upgrade7Test::testMigrateUpgradeExecute
Found 16 menu_link_content entities, expected 12.

This means there's probably 4 entities pointing to non-existing menu links

All other failures are only occurring for Drupal 6 migrations; apparently there's something different about how Drupal 6 migration plugins/definitions are processed.

huzooka’s picture

Assigned: Unassigned » huzooka

Re #4:
I don't see how we can assume that the column name (what you use in the condition) is in the plugin's configuration (with key source). That's a wrong assumption. With this patch, you will get these kind of errors if you migrate users with pictures before the file migration was executed:

SQL error:

SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '= '1443')) "subquery"' at line 6: SELECT COUNT(*) AS "expression" FROM (SELECT 1 AS "expression" FROM {file_managed} "f" WHERE ("uri" NOT LIKE :db_condition_placeholder_0 ESCAPE '\\') AND ("uri" LIKE :db_condition_placeholder_1 ESCAPE '\\') AND (= :db_condition_placeholder_2)) "subquery"; Array ( [:db_condition_placeholder_0] => temporary://% [:db_condition_placeholder_1] => public://% [:db_condition_placeholder_2] => 1443 )

Lets pick the very last condition: (= :db_condition_placeholder_2). Yes, the column name is missing :).

Why?

Let's see how the user migration looks:

id: d7_user
label: User accounts
audit: true
[...]
process:
  uid: uid
  name: name
  pass: pass
  [...]
  user_picture:
    -
      plugin: default_value
      source: picture
      default_value: null
    -
      plugin: migration_lookup
      migration: d7_file
destination:
  plugin: entity:user
[...]

First of all, the migration_lookup plugin's configuration does not have a source key. But if it would be the the first process plugin in the user_picture's process pipeline, that would be defined as

user_picture:
  plugin: migration_lookup
  source: picture
  migration: d7_file

This still leads to the SQL error cited above.

Whenever this process plugin isn't the first process plugin, you won't have that key set at all. What you need there is the ID(s) of the source: $source_plugin->getIds(). Ideally, you need as many incoming value in $value as many source ID the stub_migration's source plugin defines (or just hope that there will be only one result).

huzooka’s picture

Moved the "fixed" main logic into \Drupal\migrate\MigrateStub, and since with that change it is actually feasible to create a valid stub in the right migration, I removed the "only one stubbing migration" restriction from \Drupal\migrate\Plugin\migrate\process\MigrationLookup.

huzooka’s picture

Assigned: huzooka » Unassigned
huzooka’s picture

Assigned: Unassigned » huzooka
huzooka’s picture

Assigned: huzooka » Unassigned
StatusFileSize
new14.99 KB
new12.78 KB
huzooka’s picture

#11 contains the same patch as #8.

huzooka’s picture

Assigned: Unassigned » huzooka
huzooka’s picture

Assigned: huzooka » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new23.75 KB
new4.94 KB

\Drupal\migrate\MigrateStub also got additional test coverage in MigrateStubTest::testCreateStub.

huzooka’s picture

Assigned: Unassigned » huzooka
Status: Needs review » Needs work
huzooka’s picture

Assigned: huzooka » Unassigned
Status: Needs work » Needs review
StatusFileSize
new23.75 KB

This is the right patch for 9.1.x.

huzooka’s picture

Assigned: Unassigned » huzooka
Status: Needs review » Needs work

I will fix the coding standard violations

huzooka’s picture

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

wim leers’s picture

Status: Needs review » Needs work

#7: superb comment! Crystal clear. I obviously made grossly simplistic assumptions. Thanks for describing in detail why I was wrong, it makes it very easy to see that your proposed patch is the appropriate solution!

  1. 🥳🥳🥳 Tested in detail, works great!
  2. +++ b/core/modules/migrate/src/MigrateStub.php
    @@ -70,13 +76,59 @@ public function createStub($migration_id, array $source_ids, array $default_valu
    +        $sql_succeed = TRUE;
    

    🤓 Nit: I'd have preferred to start with $sql_succeed = TRUE and then set it to FALSE if an exception is caught.

    I think that'd be easier to understand.

    Right now on the first reading it would seem that if the SQL query doesn't find the requested source row, that then we fall back to the slower behavior anyway! That's not the case, but restructuring the logic that slight way would make it more obvious I think 😊

  3. +++ b/core/modules/migrate/src/MigrateStub.php
    @@ -70,13 +76,59 @@ public function createStub($migration_id, array $source_ids, array $default_valu
    +    // Cannot use the source plugin's query and condition, let's do the slower
    +    // discovery.
    +    if (!$exists_in_source && !$sql_succeed) {
    +      try {
    +        foreach ($source_plugin as $row) {
    +          assert($row instanceof Row);
    +          $id_values = [];
    +          foreach (array_keys($source_ids) as $source_id_key) {
    +            $id_values[$source_id_key] = $row->getSourceProperty($source_id_key);
    +          }
    +          $id_values = array_filter($id_values);
    +          if ($exists_in_source = $id_values === $source_ids) {
    +            break 1;
    +          }
    +        }
    +      }
    +      catch (\Exception $e) {
    +      }
    +    }
    +
    

    👍 This will be slow but there's nothing we can do about it…

  4. +++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
    @@ -289,4 +271,85 @@ protected function isValid($value) {
    +        catch (PluginNotFoundException $e) {
    

    🤓 Shouldn't this be $exception instead of $e? Otherwise it will not be rethrown…

  5. +++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
    @@ -289,4 +271,85 @@ protected function isValid($value) {
    +        catch (MigrateException $exception) {
    +        }
    +        catch (MigrateSkipRowException $exception) {
    +        }
    +        catch (\Exception $exception) {
    +        }
    

    🙏 Let's not lose the helpful comments that used to be there before this refactor?

  6. +++ b/core/modules/migrate/tests/src/Unit/MigrateStubTest.php
    @@ -43,27 +44,54 @@ protected function setUp(): void {
    +    $source_plugin = new EmbeddedDataSource([
    +      'data_rows' => [
    +        $row_source_2->getSource(),
    +      ],
    +      'ids' => $ids,
    +    ], 'embedded_data', [], $migration->reveal());
    

    Clever 😃

  7. +++ b/core/modules/migrate/tests/src/Unit/MigrateStubTest.php
    @@ -43,27 +44,54 @@ protected function setUp(): void {
    +    // If MigrateStub is asked to create only valid stubs, then with the
    +    // incoming "['id' => 1]" source IDs array shouldn't create a stub.
    +    $this->assertSame(FALSE, $stub->createStub('test_migration', $row_source_1_missing->getSource(), [], NULL, TRUE));
    +    $this->assertSame($destination_2, $stub->createStub('test_migration', $row_source_2->getSource(), [], NULL, TRUE));
    

    🥳

  8. +++ b/core/modules/taxonomy/tests/modules/taxonomy_term_stub_test/migrations/taxonomy_term_stub_test_valid.yml
    @@ -0,0 +1,31 @@
    +label: Taxonomy term migration which stubs a valid source id
    

    🤔 What makes this have a valid source ID and taxomy_term_stub_test not? See next point.

  9. +++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    @@ -67,20 +68,24 @@ public function testStubWithWeightMapping() {
    -    // We have a term referencing an unmigrated parent, forcing a stub to be
    -    // created.
    -    $migration = $this->getMigration('taxonomy_term_stub_test');
    -    $term_executable = new MigrateExecutable($migration, $this);
    +    // We have a term referencing a not migrated parent. Check whether a valid
    +    // stub is created.
    +    $migration_valid = $this->getMigration('taxonomy_term_stub_test_valid');
    +    $migration_missing_stub = $this->getMigration('taxonomy_term_stub_test');
    +    $term_executable = new MigrateExecutable($migration_valid, $this);
         $term_executable->import();
    -    $this->assertNotEmpty($migration->getIdMap()->getRowBySource(['2']), 'Stub row exists in the ID map table');
    +    $this->assertNotEmpty($migration_missing_stub->getIdMap()->getRowBySource(['3']), 'Stub row exists in the ID map table');
     
         // Load the referenced term, which should exist as a stub.
    -    /** @var \Drupal\Core\Entity\ContentEntityBase $stub_entity */
    -    $stub_entity = Term::load(2);
    -    $this->assertNotEmpty($stub_entity, 'Stub successfully created');
    -    if ($stub_entity) {
    -      $this->assertCount(0, $stub_entity->validate(), 'Stub is a valid entity');
    -    }
    +    $stub_entity = Term::load(3);
    +    $this->assertTrue($stub_entity instanceof TermInterface, 'Stub successfully created');
    +    $this->assertCount(0, $stub_entity->validate(), 'Stub is a valid entity');
    +
    +    // We have a term referencing a missing parent: check whether no stub is
    +    // created.
    +    $term_executable = new MigrateExecutable($migration_missing_stub, $this);
    +    $term_executable->import();
    

    🤔🙏 It took me a while to understand that the new taxonomy_term_stub_test_valid is to be used in tandem with taxonomy_term_stub_test, specifically for this test. I think this would've clarified it a lot:

     .../taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php   | 2 ++
     1 file changed, 2 insertions(+)
    
    diff --git a/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php b/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    index c007426796..cc3c286f76 100644
    --- a/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    +++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    @@ -80,11 +80,13 @@ public function testStubWithParentStub() {
         $stub_entity = Term::load(3);
         $this->assertTrue($stub_entity instanceof TermInterface, 'Stub successfully created');
         $this->assertCount(0, $stub_entity->validate(), 'Stub is a valid entity');
    +    $this->assertNotSame('cat', $stub_entity->label());
     
         // We have a term referencing a missing parent: check whether no stub is
         // created.
         $term_executable = new MigrateExecutable($migration_missing_stub, $this);
         $term_executable->import();
    +    $this->assertSame('cat', Term::load(3)->label());
         $this->assertEmpty($migration_missing_stub->getIdMap()->getRowBySource(['2']), 'Stub row not exists in the ID map table, since "2" is missing from the source rows');
       }
     
    
  10. +++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    @@ -67,20 +68,24 @@ public function testStubWithWeightMapping() {
    +    $this->assertEmpty($migration_missing_stub->getIdMap()->getRowBySource(['2']), 'Stub row not exists in the ID map table, since "2" is missing from the source rows');
    

    🤓 s/not exists/does not exist/

wim leers’s picture

+++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
@@ -289,4 +271,85 @@ protected function isValid($value) {
+      throw new MigrateException(sprintf('A(n) %s was thrown while attempting to stub.', gettype($exception)), $exception->getCode(), $exception);

This is resulting in hard-to-debug messages such as:

A(n) object was thrown while attempting to stub.

It'd be better to include the exception class + message, like so:

throw new MigrateException(sprintf('A(n) %s was thrown while attempting to stub, with the following message: %s.', get_class($exception), $exception->getMessage()), $exception->getCode(), $exception);
huzooka’s picture

Assigned: Unassigned » huzooka

Re #21:

That's a legacy line :)

huzooka’s picture

I just realized that the original comments of the exceptions (that are mentioned in #20.5) are/were misleading, because they also caught the same exceptions thrown in MigrateStub::doCreateStub().

huzooka’s picture

Fixed #21, and also addresses #20:

  1. 😊
  2. Done!
  3. Agree
  4. No, it shouldn't be. I added comments to this and to the missing (and re-added clause as well.
  5. At this three catch clause, there weren't any comments.
  6. 😊
  7. 😊
  8. ...
  9. I don't want to add $this->assertNotSame('cat', $stub_entity->label()); because the stub's label is a random generated string, and nothing guarantees that it won't be 'cat'. I hope that $this->assertEquals(MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $stub_row_3['source_row_status']); also helps.
  10. 🧐 😊 Fixed, thanks!
wim leers’s picture

  1. +++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
    @@ -321,7 +321,17 @@ protected function getDestinationIds(array $source_id_values): ?array {
    +        catch (\LogicException $e) {
    

    Ah yes, InvalidArgumentException extends LogicException and therefore this catch would've prevented the problem we saw in #21. 👍

  2. +++ b/core/modules/taxonomy/tests/src/Kernel/Migrate/MigrateTaxonomyTermStubTest.php
    @@ -68,24 +69,29 @@ public function testStubWithParentStub() {
    +    $this->assertEquals(MigrateIdMapInterface::STATUS_NEEDS_UPDATE, $stub_row_3['source_row_status']);
    ...
    +    // The previously stubbed parent term should be fully migrated.
    +    $this->assertEquals(MigrateIdMapInterface::STATUS_IMPORTED, $migration_missing_stub->getIdMap()->getRowBySource(['3'])['source_row_status']);
    

    WFM! 👍

wim leers’s picture

+++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
@@ -144,13 +153,16 @@ class MigrationLookup extends ProcessPluginBase implements ContainerFactoryPlugi
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrateLookupInterface $migrate_lookup, MigrateStubInterface $migrate_stub) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrateLookupInterface $migrate_lookup, MigrateStubInterface $migrate_stub, MigrationPluginManagerInterface $migration_plugin_manager) {
...
+    $this->migrationPluginManager = $migration_plugin_manager;

@@ -163,7 +175,8 @@ public static function create(ContainerInterface $container, array $configuratio
+      $container->get('migrate.stub'),
+      $container->get('plugin.manager.migration')

This is a BC break.

AFAICT this BC break can easily be avoided? 🤔

#3146646-2: Clean up ParagraphsLookup could've been avoided too then?

huzooka’s picture

Assigned: Unassigned » huzooka
Status: Needs review » Needs work

Hmmmm. Yes, it can be avoided! I've seen several times, how.

huzooka’s picture

I removed the feature that made possible to stub an entity in the right migration derivative (that was the reason of the need for the migration plugin manager injection, and it was an implicit feature addition as well).

So there shouldn't be any BC violations anymore.

huzooka’s picture

Assigned: Unassigned » huzooka
Status: Needs review » Needs work
huzooka’s picture

huzooka’s picture

Issue summary: View changes
wim leers’s picture

Ahhh, that looks much better indeed! And much simpler 💪

mikelutz’s picture

Category: Bug report » Feature request
Priority: Major » Normal
Status: Needs review » Needs work
  1. +++ b/core/modules/migrate/src/MigrateStub.php
    @@ -70,13 +76,59 @@ public function createStub($migration_id, array $source_ids, array $default_valu
    +    if (!$stub_should_be_created && $source_plugin instanceof SqlBase) {
    +      $source_plugin_query = $source_plugin->query();
    +
    +      try {
    +        foreach ($source_ids as $source_id => $source_id_value) {
    +          $source_plugin_query->condition($source_id, $source_id_value);
    +        }
    +        $stub_should_be_created = (bool) $source_plugin_query
    +          ->countQuery()
    +          ->execute()
    +          ->fetchField();
    +      }
    +      catch (DatabaseExceptionWrapper $e) {
    +        $sql_succeed = FALSE;
    +      }
    +    }
    +    // Cannot use the source plugin's query and condition, let's do the slower
    +    // discovery.
    +    if (!$stub_should_be_created && !$sql_succeed) {
    +      try {
    +        foreach ($source_plugin as $row) {
    +          assert($row instanceof Row);
    +          $id_values = [];
    +          foreach (array_keys($source_ids) as $source_id_key) {
    +            $id_values[$source_id_key] = $row->getSourceProperty($source_id_key);
    +          }
    +          $id_values = array_filter($id_values);
    +          if ($stub_should_be_created = $id_values === $source_ids) {
    +            break 1;
    +          }
    +        }
    +      }
    +      catch (\Exception $e) {
    +      }
    +    }
    +
    

    So, I'm not opposed to adding this feature, I think it could help flag migrations issues, but I'm not a huge fan of having all of this souce plugin type dependent code here in the service. Would it be possible to create a new interface for source plugins, `MigrateSourceIdCheckInterface`, with a single method, `hasSourceIds(array $source_ids) : bool` That could let source plugins decide how to handle checking whether source ids exist? `SourcePluginBase` could implement the long one, `SqlBase` could do the query, and other source plugins could implement the check efficiently in a way that makes sense for them.

    This also needs to be configurable, as current expected behavior is to create a stub regardless of whether the referenced migration has a row or not. For something other than a Drupal upgrade, this behavior can be desired. complex workflows with migrations for non upgrade reasons may be expecting this. There may be an expectation that the referenced entity will be added to the referenced source at a later date. Even if that's a rare use case, Migrations to pull data from apis all the time such that trying to cycle through all the source ids for every reference would be a huge performance hit. Custom remote sources may be able to implement a remote query to determine quickly if a source id actually exists though, so I think this really needs to be considered a feature request and handled in a BC way so that the old behavior is preserved by default, and I think the source plugins should have the ability to determine the best way to find out if a given id exists.

  2. +++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
    @@ -228,17 +227,21 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
    -        $destination_ids = $this->migrateStub->createStub($stub_migration, $source_id_values[$stub_migration], [], FALSE);
    +        $destination_ids = $this->migrateStub->createStub($stub_migration, $source_id_values[$stub_migration], [], FALSE, TRUE);
    

    Same as above, you are changing the behavior of this plugin in a non bc way, so it needs to default to the old behavior and have a configuration option to override.

berdir’s picture

Related issue when the reason for an ID to not exist is because it's part of a different migration if you have multiple possible migrations. #2842811: Stubbing goes wrong in processes with several migrations

wim leers’s picture

quietone’s picture

Issue tags: -migrate-d7-d8

This issue is not specific to Drupal 7 sources, removing tag.

thursday_bw’s picture

re: #21

New issue created [https://www.drupal.org/project/drupal/issues/3202665] to deal with that issue specifically. Let's keep issue's to one issue per issue.

thursday_bw’s picture

+++ b/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
@@ -247,7 +250,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
+        throw new MigrateException(sprintf('A(n) %s was thrown while attempting to stub, with the following message: %s.', get_class($e), $e->getMessage()), $e->getCode(), $e);

Deal with this in it's own issue: https://www.drupal.org/project/drupal/issues/3202665

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

wim leers’s picture

#3207968: Replace @codingStandards comments with phpcs: comments broke this between 9.1.7 and 9.2.0-rc1.

This does not address #34 yet, so keeping NW.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

kimberleycgm’s picture

I've implemented the configuration option and defaulted to the previous behaviour. Haven't addressed the first point from #34 yet though.

kimberleycgm’s picture

First pass at creating MigrateSourceIdCheckInterface to pull that logic out of the method. Kept the fallback for plugins that don't implement the interface. Also cleaned up the variables to (I hope!) make it clearer what's happening.

As an example I implemented it for migrate_source_csv's CSV plugin using the following:

/**
 * {@inheritdoc}
 */
public function hasSourceIds(array $source_ids): bool {
  $reader = $this->getReader();
  $header = $reader->getHeader();

  // Need to ensure we cache individually for each CSV.
  $config = $this->getConfiguration();
  $csv_path = $config['path'];
  $hash = hash('sha256', $csv_path);

  $name = __CLASS__ . '_' . __METHOD__ . '_' . $hash;
  $column_data = &drupal_static($name, []);

  $rows = [];
  // Find the index of the columns we need.
  foreach ($source_ids as $column_name => $value) {
    // Get the column data if we don't have it already.
    if (!isset($column_data[$column_name])) {
      $index = array_search($column_name, $header);
      if ($index !== FALSE) {
        $column_data[$column_name] = iterator_to_array($reader->fetchColumn($index));
      }
    }

    if (isset($column_data[$column_name])) {
      $row = array_search($value, $column_data[$column_name]);
      if ($row !== FALSE) {
        $rows[$column_name] = $row;
      }
    }
  }

  // If all from the same row then the source exists.
  $unique = array_unique($rows);
  return count($unique) === 1;
}
kimberleycgm’s picture

Status: Needs work » Needs review

gauravvvv’s picture

StatusFileSize
new20.93 KB
new500 bytes

Re-rolled patch #44, Fixed phpcs issues. Attached interdiff for same.

Status: Needs review » Needs work

The last submitted patch, 47: 3156730-47.patch, failed testing. View results

kimberleycgm’s picture

Status: Needs review » Needs work

The last submitted patch, 49: 3156730-49.patch, failed testing. View results

huzooka’s picture

If any of the followers want to use the feature, you can do so with this process plugin I wrote 16 months ago (and released almost a year ago thanks to Acquia): #3224702: Release the magical migration lookup process plugin, I also add it as a related issue.

MigMagLookup documentation (with a lot of typos as I see).

We have been using it for a while – it made us able to completely drop the currently known follow-up migration concept.

And if it is necessary to stub non-existent entities, then you can specify a stub trap migration for these missing entities (check out the "Use a fallback migration to collect invalid (missing) target ID references" example).

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

floydm’s picture

StatusFileSize
new816 bytes
new20.95 KB

Rerolling patch #49 for D9.4.8.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

wim leers’s picture

Thank you, @floydm! 😊 I'm glad Acquia isn't the only organization using this Migration system improvement! 👍

I will not have capacity to address the maintainer's feedback from #34.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mikelutz’s picture

Status: Needs review » Needs work

Still needs work for #34

trackleft2 made their first commit to this issue’s fork.

trackleft2’s picture

Hiding patch files in favor of a Merge Request.

trackleft2’s picture

trackleft2’s picture

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.