Problem/Motivation

This is a follow-up to #3488115, which added commerce_update_8204() to replace serialized Drupal\commerce\BundleFieldDefinition field storage definitions with Drupal\entity\BundleFieldDefinition.

That update fixes the stale serialized class reference, but on some update paths it can run too late.

When updating a site from Commerce 2.x to Commerce 3.3.x, Commerce submodule updates such as commerce_payment_update_10301() can run before commerce_update_8204(). Those updates rebuild entity schemas and unserialize installed field storage definitions from the key_value table.

If commerce_update_8204() has not run yet, stale Drupal\commerce\BundleFieldDefinition objects unserialize as __PHP_Incomplete_Class, causing failures like:

TypeError: Drupal\Core\Entity\Sql\DefaultTableMapping::Drupal\Core\Entity\Sql\{closure}(): Argument #1 ($definition) must be of type Drupal\Core\Field\FieldStorageDefinitionInterface, __PHP_Incomplete_Class given

In our case this first manifested while using a custom SEPA payment method type and custom payment gateway. The SEPA payment method type defines an additional payment method field using BundleFieldDefinition::create(), which meant the stale serialized class reference was present for its account_number field.

However, this is not specific to the custom gateway/plugin. Commerce core payment method types also define bundle fields using BundleFieldDefinition::create(), for example:

  • credit_card: card_type, card_number, card_exp_month, card_exp_year
  • paypal: paypal_mail

Therefore the same failure can occur on sites using only Commerce core payment method plugins, if their installed field storage definitions still contain serialized Drupal\commerce\BundleFieldDefinition objects from older Commerce versions.

Steps to reproduce

  1. Start with a site that was originally installed with an older Commerce 2.x version, before Commerce bundle field definitions were moved from Drupal\commerce\BundleFieldDefinition to Drupal\entity\BundleFieldDefinition.
  2. Ensure the database still contains installed field storage definitions serialized with the old class name. For example, check:
    SELECT name
    FROM key_value
    WHERE collection = 'entity.definitions.installed'
      AND name LIKE '%.field_storage_definitions'
      AND value LIKE '%Drupal\\\\commerce\\\\BundleFieldDefinition%';
  3. Update the codebase to Commerce 3.3.x.
  4. Run database updates, for example:
    drush updatedb

    or:

    drush deploy
  5. Observe that Commerce submodule updates can run before commerce_update_8204().
  6. If an earlier Commerce submodule update rebuilds entity schemas or loads installed field storage definitions, the stale serialized class is unserialized as __PHP_Incomplete_Class.

In our case, the update run failed first at:

commerce_payment_update_10301

with:

TypeError: Drupal\Core\Entity\Sql\DefaultTableMapping::Drupal\Core\Entity\Sql\{closure}(): Argument #1 ($definition) must be of type Drupal\Core\Field\FieldStorageDefinitionInterface, __PHP_Incomplete_Class given

After that, unrelated updates also failed with the same error because the installed entity definitions were still poisoned:

webform_update_8648
admin_toolbar_search_update_8002

Proposed resolution

Add hook_update_dependencies() so Commerce submodule updates that may trigger schema/entity definition rebuilds depend on commerce_update_8204().

This ensures the existing fix from #3488115 runs before later Commerce submodule updates need to unserialize installed field storage definitions.

This does not replace the fix from #3488115. It only ensures that fix runs early enough in the update order.

Remaining tasks

  • Review whether the dependency list should cover all Commerce submodule updates after the relevant Commerce 2.x update range, or only specific Commerce 3.x schema-related updates.
  • Confirm the patch against an upgrade path from Commerce 2.x to Commerce 3.3.x with stale serialized Drupal\commerce\BundleFieldDefinition entries.
  • Add or adjust test coverage if there is an existing update-path test pattern suitable for this.

User interface changes

None.

API changes

None.

Data model changes

None. The existing data repair is still performed by commerce_update_8204(). This issue only changes update ordering so that repair happens before Commerce submodule schema updates need to unserialize installed field storage definitions.

Comments

berliner created an issue.

berliner’s picture

I didn't create a MR yet, but want to wait for feedback first, to see if this is the right way forward to address this issue.