Problem/Motivation

New contact methods are often saved before the parent contact exists, with crm_contact left empty. The contact is then expected to fill that parent reference in Contact::postSave().

That hook only walks the three default fields:

emails, telephones, addresses

Inline REST writes, by contrast, honor every contact-method reference field listed in crm.serialization.settings (ContactRestWriteService::processInlineContactMethods() via ContactSerializationService::getEnabledContactMethodFields()). Creating or updating those extra fields (REST POST/PATCH, or the contact form / IEF) can leave methods referenced on the contact but still parentless.

Effects of an unparented method:

  • Queries, Views, search, and access that key off crm_contact miss the method.
  • REST PATCH removal skips it: shouldSkipRemoval() treats a method as not owned when crm_contact does not match the contact, so omitted items are not deleted.

The default emails, telephones, and addresses fields are not affected.

Steps to reproduce

  1. Add a contact-method entity-reference field on a contact bundle (for example a second email-style field) and include it in Contact method fields at /admin/config/crm/serialization.
  2. POST or PATCH a contact with an inline nested entity on that field (no crm_contact in the nested payload; the write path strips it).
  3. Load the new contact method. crm_contact is empty even though the contact references it.
  4. (Optional) PATCH the same field without that method. The method entity remains because removal only deletes methods whose crm_contact matches the contact.

Proposed resolution

In Contact::postSave(), parent any referenced crm_contact_method whose crm_contact is empty. Do not hard-code field names. Walk every eligible contact-method reference field on the saved contact (same idea as ContactSerializationService::isEligibleField(): entity reference / primary entity reference / entity reference revisions targeting crm_contact_method).

That covers REST, IEF, and programmatic saves. PATCH deletion of extra fields should then work because those methods will have a parent.

Remaining tasks

  • Replace the hardcoded field list in Contact::postSave().
  • Kernel coverage: create a contact with a non-default contact-method reference field and assert the method’s crm_contact is set.
  • Kernel coverage: PATCH-omit that method after it is parented and assert it is deleted.

User interface changes

None.

API changes

None. Behavior for the three default fields stays the same. Extra contact-method reference fields start getting a parent, which is the intended contract.

Data model changes

None. Existing orphan methods are not repaired by this change unless the parent contact is saved again.

Issue fork crm-3622723

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

bluegeek9 created an issue. See original summary.

bluegeek9’s picture

Status: Active » Fixed
//www.flaticon.com/free-icons/thank-you Thank you for your contribution! Your continued support makes this project sustainable.
There are multiple ways to show appreciation for the work contributed to this project including:
  • Triage issues and adding more context to existing issues.
  • Flagging CRM as a favorite on the project page to help others discover it and show your support.
  • Review the Developer Docs for accuracy and clarity.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • bluegeek9 committed 7ba255d6 on 1.0.x
    task: #3622723 Custom contact-method fields leave newly created methods...