Problem/Motivation

Running operations as the anonymous user e.g. via Drush or cron, can result in problems with access to entities being imported. Support switching to another user in a pre-initiate event.

Steps to reproduce

Proposed resolution

Remaining tasks

- Make the account switching subscriber to always be the first.
- Implement switching back to the original accout in the last post-terminate event subscriber.

User interface changes

API changes

Data model changes

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

krystalcode created an issue. See original summary.

krystalcode’s picture

Issue summary: View changes

krystalcode’s picture

Issue summary: View changes
krystalcode’s picture

The current implementation on the MRs does the account switching in an event subscriber. This, however, causes a problem in that
switching back will not happen if there's an error in the following cases:

- If an operation is cancelled by a pre-initiate subscriber.
- If there's a fatal error in another pre-initiate subscriber.
- If there's a fatal error in another post-terminate subscriber.

Here's example code.

$cancel = $this->preInitiate(
  Events::REMOTE_LIST_PRE_INITIATE,
  'import_list',
  $context,
  $sync
);
if ($cancel) {
  return;
}

try {
  $this->doImportRemoteList($sync, $filters, $options, $context);
}
finally {
  $this->postTerminate(
    Events::REMOTE_LIST_POST_TERMINATE,
    'import_list',
    $context,
    $sync
  );
}

We therefore need to move account switching from an event subscriber to a service that is used by the import/export manager.

- Move the logic to a service called AccountSwitcher
- In all relevant places in both the import and the export manager, switch accounts before pre-iniate events.
- Wrap pre-initiate events in try/catch, switch back accounts, re-throw the error.
- Switch back accounts if the operation is cancelled.
- Wrap post-terminate events in try/catch, switch back accounts, re-throw the error.

Now, here's the other complexity. An operation can have dependent operations i.e. it can call or be called within the exeuction of another operation. That's actually a pretty common use case.

Imagine the following:

- Operation A switches from user 0 to user 1.
- Operation A runs.
- Before terminating, operation A triggers the execution of operation B.
- Operation B switches from user 1 to user 12.
- Operation B runs.
- Operation B terminates, at which point needs to switch back from user 12 to user 1.
- Operation A terminates, at which point needs to switch back from user 1 to user 0.

We therefore need to track in a variable whether the account switched and then use that result to switch back. We might need to refactor the code a bit so that we both avoid code repetition, maybe abstracting some code and moving it to the base manager class.

shabana.navas’s picture

Re-rolled for fixing deprecation notices for PHP 8.2+.