Skip to content

Api4 - Support portable export/import for dynamic foreign keys - #36338

Merged
colemanw merged 1 commit into
civicrm:masterfrom
mattwire:dynamic-fk-export-import
Jul 27, 2026
Merged

Api4 - Support portable export/import for dynamic foreign keys#36338
colemanw merged 1 commit into
civicrm:masterfrom
mattwire:dynamic-fk-export-import

Conversation

@mattwire

@mattwire mattwire commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds support for exporting/importing entities which use dynamic foreign keys such as PriceSetEntity, EntityTag, Note, etc.

Split out from #35329, where portability of PriceSetEntity.entity_id was raised as an open question by @mattwire and @ufundo.

Before

Cannot export/import entities with dynamic foreign key (entity_table/entity_id)

After

Can

Technical Details

  • Dynamic FKs (e.g. an entity_id column paired with an entity_table discriminator, as used by PriceSetEntity, EntityTag, Note, etc.) had no way to export/import portably: ExportAction only checked the static fk_entity field, so such columns always fell back to a raw, non-portable database id, and DAOActionTrait::resolveFKValues() had no way to resolve a .name-suffixed dynamic FK back to an id on write.
  • ExportAction now resolves the target entity for each dynamic FK from the record's own entity_table column value, and uses a field.name lookup instead of the raw id when that target entity has a name field (falling back to the raw id otherwise, unchanged).
  • resolveFKValues() gains the matching write-side resolution, using the sibling discriminator column already present in the record to pick the correct target DAO.
  • This is a generic, entity-agnostic framework change with no behavior change for entities whose dynamic FK target has no name field.

Test plan

  • New tests/phpunit/api/v4/Action/ExportActionTest.php: exports a ContributionPage-linked PriceSetEntity (portable, has name) and an Event-linked one (no name, falls back to raw id as before); also tests the write-side round trip.
  • tests/phpunit/api/v4/Entity/ManagedEntityTest.php, tests/phpunit/CRM/Core/ManagedEntitiesTest.php, and other dynamic-FK-adjacent tests (FkJoinTest, EntityFileTest, TagTest, GetFieldsTest, CoreUtilTest) pass with no regressions.

Comments

Dynamic FKs (e.g. an `entity_id` column paired with an `entity_table`
discriminator, as used by PriceSetEntity, EntityTag, Note, etc.) had no
way to export/import portably: ExportAction only checked the static
`fk_entity` field, so such columns always fell back to a raw,
non-portable database id, and DAOActionTrait::resolveFKValues() had no
way to resolve a `.name`-suffixed dynamic FK back to an id on write.

ExportAction now resolves the concrete target entity for each dynamic
FK from the record's own discriminator column value, and uses a
`field.name` lookup instead of the raw id when that target entity has
a `name` field (falling back to the raw id otherwise, unchanged).
resolveFKValues() gains the matching write-side resolution, using the
sibling discriminator column already present in the record to pick the
correct target DAO.

This is a generic, entity-agnostic framework change with no behavior
change for entities whose dynamic FK target has no `name` field.
@civibot

civibot Bot commented Jul 27, 2026

Copy link
Copy Markdown

🤖 Thank you for contributing to CiviCRM! ❤️ We will need to test and review this PR. 👷

Introduction for new contributors...
  • If this is your first PR, an admin will greenlight automated testing with the command ok to test or add to whitelist.
  • A series of tests will automatically run. You can see the results at the bottom of this page (if there are any problems, it will include a link to see what went wrong).
  • A demo site will be built where anyone can try out a version of CiviCRM that includes your changes.
  • If this process needs to be repeated, an admin will issue the command test this please to rerun tests and build a new demo site.
  • Before this PR can be merged, it needs to be reviewed. Please keep in mind that reviewers are volunteers, and their response time can vary from a few hours to a few weeks depending on their availability and their knowledge of this particular part of CiviCRM.
  • A great way to speed up this process is to "trade reviews" with someone - find an open PR that you feel able to review, and leave a comment like "I'm reviewing this now, could you please review mine?" (include a link to yours). You don't have to wait for a response to get started (and you don't have to stop at one!) the more you review, the faster this process goes for everyone 😄
  • To ensure that you are credited properly in the final release notes, please add yourself to contributor-key.yml
  • For more information about contributing, see CONTRIBUTING.md.
PR commands & links...
  • /rebase <branch-name> will rebase your branch and change the base of the PR.
  • /squash will combine all commits (keeping only the first commit messsage).
  • /port <branch-name> will create a copy of this PR against a different branch.
  • /lintroll will automatically fix linting errors, amending commits as needed.
  • retest this please will rerun the tests and rebuild the demo site.
  • 📖 Review standards
  • 🗒️ Review template (brief or verbose)

➡️ Online demo of this PR 🔗

@civibot civibot Bot added the master label Jul 27, 2026
@mattwire
mattwire marked this pull request as draft July 27, 2026 16:40
@mattwire
mattwire marked this pull request as ready for review July 27, 2026 16:55
@colemanw colemanw added the merge ready PR will be merged after a few days if there are no objections label Jul 27, 2026
@colemanw

Copy link
Copy Markdown
Member

Looks great @mattwire

@colemanw
colemanw merged commit 1fa2c6f into civicrm:master Jul 27, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

master merge ready PR will be merged after a few days if there are no objections

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants