Problem

When multiple profiles per user are allowed, and the profile form is displayed on the user account form, the first profile is displayed multiple times and any changes made overwrite the data from the first profile, causing a loss of stored data.

Steps to reproduce

- Define a Profile Type (let's call it "Pet") with text field "Name"
- Select the option to "Allow multiple profiles per user"
- Under Configuration / People / Account Settings / Manage form display, enable the display of "Pet Profiles" and set the widget to "Profile Form".
- Add two Pet profiles to a particular user, say "Rover" and "Killer".
- Edit that user. Notice that 3 profile forms are displayed, all with "Rover". Change the third one to "Frank".
- Observe that Rover is now Frank and Killer is unchanged.

Proposed resolution

I believe the root of this problem is that the form state contains an array of profiles, indexed by profile type. Thus only the data from one profile of a given type is stored.

Remaining tasks

Fix the bug.

User interface changes

None

API changes

Unknown. The internal structure of the profiles in the form state may need to change.

Data model changes

None.

I reluctantly assigned the Priority of Critical because this bug causes a loss of stored data when the form is submitted. It can be reasonably argued that the circumstances that are needed to exhibit the bug are sufficiently uncommon that a lower priority such as major is appropriate.

Issue fork profile-3315270

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

DanChadwick created an issue. See original summary.

DanChadwick’s picture

Status: Active » Needs review
Issue tags: +API change, +Needs change record
FileSize
3.46 KB

This patch changes the storage of the profiles in the form state from an array of profiles indexed by profile type to an associative array (indexed by profile type) of arrays (indexed by delta) of profiles. This would be a backward-breaking change if any custom module relies on the storage of the profiles in the form state.

tBKoT’s picture

The patch from #2 is almost working for me. The issue I'm facing after applying it is that whenever we edit user info and save changes a new empty profile is created. So I added a condition to remove empty profiles from the form state, it works only for new items.

DanChadwick’s picture

Neither #2 nor #3 apply to 1.8. In reviewing #3, I feel this is a distinct issue -- should new empty profiles be saved? This applies both to single and multiple profile entity references. I suggest @tBKoT create a new issue. First question is do you simply not save new empty profiles, or do you delete existing profiles which became empty. I would advocate the latter, but this is a change in behavior. This could be accomplished with something like:

      $empty_profile = $this->entityTypeManager->getStorage('profile')->create(['type' => $profile_type]);
      $profiles = array_filter($profiles, fn (ProfileInterface $profile) => $profile->equalToProfile($empty_profile));
<code>
This could be placed in <code>extractFormValues

, but might be better in saveProfiles.

Since patch-based testing is being discontinued, I will open an issue fork for a re-roll of #2.

DanChadwick’s picture

Status: Needs review » Needs work
DanChadwick’s picture

Status: Needs work » Needs review
FileSize
3.48 KB

Reroll of #2, leaving the empty profile changes of #3 to a to-be-created separate issue. Patch for convenience of composer workflow.

DanChadwick’s picture

Catch 22. Drupal 9 support ended November 1st. The latest version of Drupal 9 required PHP 7.4, which includes support for arrow functions, which I used in this patch. But I cannot start a test with PHP 7.4 without using Drupal 10, which requires a composer.json file. So either I need to remove the arrow function just to make the linting pass, or we need to make profile be Drupal 10 testing compatible.

  • jsacksick committed 8cb44eb1 on 8.x-1.x
    Issue #3315270 by DanChadwick, tBKoT: Loss of stored data when multiple...
jsacksick’s picture

Status: Needs review » Fixed

I committed your patch. If you're in the mood for writing a change record, that'd be great... Added the following note to the release notes for now:

As part of #3315270, the storage of the profiles in the form state changed from an array of profiles indexed by profile type to an associative array (indexed by profile type) of arrays (indexed by delta) of profiles.

DanChadwick’s picture

Issue tags: -Needs change record

Draft change record created.

drupalfan2’s picture

After upgrading from profile 1.8 to 1.9 I get this error message:

Error: Class "Drupal\profile\ProfileType" not found in Drupal\profile\ProfileListBuilder->getDefaultOperations() (line 120 of modules/contrib/profile/src/ProfileListBuilder.php).
Drupal\Core\Entity\EntityListBuilder->getOperations() (Line: 212)
Drupal\Core\Entity\EntityListBuilder->buildOperations() (Line: 194)
Drupal\Core\Entity\EntityListBuilder->buildRow() (Line: 112)
Drupal\profile\ProfileListBuilder->buildRow() (Line: 242)
Drupal\Core\Entity\EntityListBuilder->render() (Line: 23)
Drupal\Core\Entity\Controller\EntityListController->listing()
call_user_func_array() (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 627)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 58)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 704)
Drupal\Core\DrupalKernel->handle() (Line: 19)

Same problem with profile 1.10.

I do not allow multiple profiles per user, "Allow multiple profiles per user" is off.

And patch #16 of https://www.drupal.org/project/profile/issues/2599014 does not apply anymore.

I need a solution to get profile 1.9 and 1.10 running.

drupalfan2’s picture

jsacksick’s picture

@DanChadwick: Where is the change record?

DanChadwick’s picture

@jsacksick: Scroll up. It should be in the right sidebar at the bottom. Unless only I see it? I think a maintainer has to publish it, maybe?
https://www.drupal.org/node/3432547

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.