Problem/Motivation
Content entities don't require having bundle support. For example – User entity doesn't have it out of the box. This means, this entity type doesn't have value for bundle entity key. In that cases, entities by itself fallback to entity type id for bundle name. For User, it will be user bundle.
\Drupal\Core\Entity\ContentEntityBase::__construct — $this->entityKeys['bundle'] = $bundle ? $bundle : $this->entityTypeId;
For the main migration, it solved by providing configuration default_bundle (\Drupal\migrate\Plugin\migrate\destination\Entity::getBundle).
But for stub entity migrations, this situation doesn't handled at all and this escalates very quickly.
When creating stub for entity without bundle, this method fails to provide proper handling of this situation: \Drupal\migrate\Plugin\migrate\destination\EntityContentBase::processStubRow. It tries to get bundle from entity key $bundle_key = $this->getKey('bundle');, but it doesn't exist for such entities, and then it collected fields for this entity + bundle combination:
$fields = $this->entityFieldManager
->getFieldDefinitions($this->storage->getEntityTypeId(), $row->getDestinationProperty($bundle_key));. The problem here is $row->getDestinationProperty($bundle_key) returns NULL and passes it as a $bundle value for \Drupal\Core\Entity\EntityFieldManager::getFieldDefinitions which doesn allows that:
\Drupal\Core\Entity\EntityFieldManagerInterface::getFieldDefinitions:
/**
* Gets the field definitions for a specific bundle.
*
* @param string $entity_type_id
* The entity type ID. Only entity types that implement
* \Drupal\Core\Entity\FieldableEntityInterface are supported.
* @param string $bundle
* The bundle.
*
* @return \Drupal\Core\Field\FieldDefinitionInterface[]
* The array of field definitions for the bundle, keyed by field name.
*/
public function getFieldDefinitions($entity_type_id, $bundle);
Then it calls hooks like hook_entity_bundle_field_info() and other code that also expects that $bundle is exists. So the code that relies on bundle value during stub migration will fail, which will lead to broken migration.
Steps to reproduce
Run migration with migration_lookup that creates stubs for entities without bundle like User and provide hook_entity_bundle_field_info() with types string $bundle and declare(strict_types=1);.
Proposed resolution
Use same logic used by content entities itself – provide fallback bundle ID equals entity type ID $bundle_key = $this->getKey('bundle') ?: $this->storage->getEntityTypeId();
Remaining tasks
- Check tests
- Fix it
| Comment | File | Size | Author |
|---|---|---|---|
| #28 | core-3335269-9.5.x-28.patch | 4.66 KB | niklan |
| #20 | interdiff_19-20.txt | 1.05 KB | niklan |
| #20 | interdiff_13-20.txt | 2.39 KB | niklan |
| #20 | core-3335269-20-test-only.patch | 3.28 KB | niklan |
| #20 | core-3335269-20.patch | 4.6 KB | niklan |
Comments
Comment #2
niklanI didn't come up with any better idea than just decorate
entity_field.managerand throw exception if$bundleisNULL.Comment #3
niklanThis patch with a fix.
Comment #4
niklanComment #5
niklanComment #7
niklanSettings needs review, because I don't think the fail
in both patches related to them in any way.
Comment #8
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Thank you for a super clear issue summary.
The proposed solution lines up with the patch.
#2 shows the issue
Triggering for 10.1
Comment #9
smustgrave commentedNo failures.
Comment #11
niklanTests passes again, the error was not related to this issue.
Comment #12
larowlancould we simplify this if the anonymous class extended from the existing entity field manager?
Comment #13
niklanUpdated patch according to suggestion from #12.
Comment #15
andypostThank you, looks ready again
Comment #16
niklanBtw, should such tests be marked somehow? Because when an interface will start using typehints this test becomes pointless, it will be covered by PHP directly.
Comment #17
larowlanI don't think this is the correct fix, a 'bundle key' is the name of the row property that contains the bundle field.
I think instead we should change this line
which is a few rows lower.
I think it should be
Sorry for not picking that up in my earlier review.
Fine to self RTBC after making that change.
I was tempted to just make that change on commit but felt it was best to go through the peer review process.
Once again, sorry for not picking that up the first time.
Ordinarily we'd add a followup for that, i.e a new issue 'remove test x once [something] is complete' and put an
// @todo remove this class in [url to followup]that way when someone resolves the issue they can search by URL for todos.I'd support doing that here if you're rerolling for the above, as I agree, a proper type hint would have prevented this.
Comment #18
larowlanComment #19
niklanUpdated patch to reflect requested changes in #17. Also, please check my language for @todo. I've also added void return typhing for test method. While I'm searching for #3050720: [Meta] Implement strict typing in existing code I've also found that all new code should use type-hints. Since this is a test method, it shouldn't affect any project.
Comment #20
niklanI made a mistake, just straightforward passes entity type ID as a bundle. Fixed in this patch. Ignore #19. For easier code understanding, I've introduced a new $bundle variable with the logic for bundle, instead of doing this as an argument in a method call.
P.s. also found a typo in @todo. But won't update it for now to avoid a lot of notifications. I want to hear how to better write it anyway, then I update it properly with a typo fix.
Comment #23
andypostRetested and #17 addressed
Comment #26
larowlanPushed to 10.1.x and 10.0.x
Queued a 9.5.x test and will backport there too if it passes
Comment #27
larowlanThe patch doesn't apply to 9.5.x, so changing to patch (to be ported)
Comment #28
niklanComment #29
catchCommitted/pushed to 9.5.x, thanks!