Problem/Motivation
Reading the magic $entity->original property is deprecated in drupal:11.2.0 and removed from drupal:12.0.0, replaced by EntityInterface::getOriginal() (change record 3295826). Core renamed its own real property to $originalEntity specifically so it would not clash with the deprecated magic one, so on core 12 the magic getter is gone and the expression evaluates to NULL.
Webform still uses it in five places. The most visible consequence is that saving any Webform config entity fatals on Drupal 12:
Error: Call to a member function getAccessRules() on null at src/WebformEntityStorage.php:101, reached from Webform::save().
That is enough to fail every kernel test that saves a webform, and it happens in setUp() rather than in an assertion, so the tests error rather than fail.
Steps to reproduce
On core 12.0.x-dev, save a Webform config entity, for example in the setUp() of any kernel test that creates one.
Proposed resolution
Use EntityInterface::getOriginal() where it exists, and keep the magic property as the fallback where it does not. getOriginal() was only added in 11.2 while this branch declares ^10.3 || ^11, so calling it unconditionally fatals with "call to undefined method" on 10.3 through 11.1. The MR therefore selects per site with method_exists(): the magic property on 10.3 to 11.1, where it still exists and raises no deprecation; getOriginal() from 11.2 on, where it avoids the deprecation and is the only path left in 12.
Dropping the method_exists() and using getOriginal() outright needs a branch whose floor is 11.2, which is a wider decision than this issue: Drupal 12 will require dropping Drupal 10 anyway, so that may belong to a 6.4 branch.
src/WebformEntityStorage.phpline 101, in doPostSave().src/Entity/WebformSubmission.phplines 878 to 880: an isset() check plus two calls through the property. The resolved original is NULL when there is none, so the isset() becomes a null check.src/Hook/WebformEditorHooks.phpline 44, passing the original into _webform_get_config_entity_file_uuids().
Remaining tasks
Review, and decide whether the same sweep should cover the 6.x branch.
User interface changes
None.
API changes
None.
Found while testing another module against core 12, after #3618362: Align definitions of getSortedDefinitions and getGroupedDefinitions with core and #3618665: webform_submission.exporter injects plugin.manager.archiver, which Drupal 12 removes cleared the earlier failures. It is the third distinct Drupal 12 break in webform and the one that stops the module functioning rather than merely warning.
AI-Generated: Yes (Claude Code was used to help draft this issue summary and the change. I reviewed them. The fatal was observed on a real Drupal 12 pipeline and I grepped the branch for every remaining use of the property.)
Issue fork webform-3618674
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
Comment #3
mably commentedComment #4
mably commentedVerified against Drupal 12, and the Drupal 10 concern raised on #3537314: file_get_content_headers() is deprecated in 11.2.0 is handled here rather than deferred.
I applied this MR's diff to webform 6.3.0 as a Composer patch on the next-major CI lane of the Personal Data Vault module, and ran that module's whole suite against core 12.x-dev (dev-main, b1b76c0). It is green: 436 tests pass, 0 failures, 0 errors.
getOriginal() only exists from Drupal 11.2, while the magic ->original property it replaces is removed in Drupal 12, so a branch supporting ^10.3 || ^11 has to satisfy both. Each of the five call sites therefore goes through method_exists($entity, 'getOriginal'), with a comment on the first one saying why. That keeps 6.3.x working on Drupal 10.3 while making it work on Drupal 12, and every conditional can be deleted in one pass whenever this branch drops Drupal 10.
The diff applies cleanly to released 6.3.0. Evidence: https://git.drupalcode.org/project/pdv/-/jobs/11717269
AI-Generated: Yes (Claude Code was used to help draft this comment and to write the merge request. I reviewed both, and the Drupal 12 test run referenced above is a real CI job whose log is linked.)
Comment #5
liam morlandThis will be done for 6.4.x which will be for Drupal 11 and 12.