Project

General

Profile

Actions

Bug #106565

closed

Constructor Promotion Not Supported in Extbase Domain Models

Added by Lina Wolf 15 days ago. Updated 9 days ago.

Status:
Resolved
Priority:
Should have
Assignee:
-
Category:
Extbase
Target version:
-
Start date:
2025-04-13
Due date:
% Done:

100%

Estimated time:
TYPO3 Version:
14
PHP Version:
Tags:
Complexity:
Is Regression:
Sprint Focus:

Description

When using PHP 8+ constructor property promotion in Extbase domain models (classes extending \TYPO3\CMS\Extbase\DomainObject\AbstractEntity), the promoted properties are not persisted, hydrated, or validated as expected.

Although promoted properties are real class properties (per PHP), Extbase does not treat them equivalently to explicitly declared properties. This leads to unexpected behavior when persisting or retrieving entities from the database.

When using:

class Blog extends AbstractEntity
{
    public function __construct(
        #[Lazy]
        #[Cascade(['value' => 'remove'])]
        public ObjectStorage $posts = new ObjectStorage()
    ) {}
}

The behaviour is not the same like for


class Blog extends AbstractEntity
{
    #[Lazy]
    #[Cascade(['value' => 'remove'])]
    protected ObjectStorage $posts;

    public function __construct()
    {
        $this->posts = new ObjectStorage();
    }

    public function getPosts(): ObjectStorage
    {
        return $this->posts;
    }
}


When I write a test in which I change typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/Blog.php
To constructor promotion there are currently 12 errors and 1 failute in the functional extbase tests.

Actions #1

Updated by Gerrit Code Review 15 days ago

  • Status changed from New to Under Review

Patch set 1 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/89095

Actions #2

Updated by Lina Wolf 15 days ago

  • Description updated (diff)
Actions #3

Updated by Gerrit Code Review 9 days ago

Patch set 2 for branch main of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/89095

Actions #4

Updated by Stefan Bürk 9 days ago

To make it short: This is not a bug and Extbase is not broken here.

For extbase models following things are a long standing known fact,
which is also documented:

  • Extbase instantiates models without calling the constructor when hydrating. (documented)
  • Extbase calls initializeObject() when hydrating to allow setting properties to default values. (documented)
  • Extbase tries to hydrate all properties given in the data array, not touching or setting other properties (except some system ones).
  • Implementor/Developer creating the extbase model is in charge to ensure to have either correctly initialized properites for direct creation or hydrating by extbase, or handle it correctly in getter methods.

PHP capabilities and language changed over the time Exbase is beeing around, which does not
change the concet how extbase works in any regard. It's still the responsibility of the person
implementing the model to ensure correct initialized properties.

The "bug" here is a missunderstanding on how PHP works, special for the constructor parameter promotion.

Simple said:

public function __construct(protected ?string $nullableStringProperty = null) {}

is not a 1:1 replacement for the class property:

class someClass {
  protected ?string $nullableStringProperty = null;

  public function __construct() {}
}

The point is, that PHP declares the property WITHOUT the default value assignment,
if the constructore method is called but executed the default value assignment only
when the constructor is called, which would be basically following code:

class someClass {
  protected ?string $nullableStringProperty;

  public function __construct(
    ?string $nullableStringProperty = null
  ) {
    $this->nullableStringProperty = $nullableStringProperty;
  }
}

The latter example holds a uninitialized property when the constructor is not called,
and requires to do the "default" value assignment using `initializeObject()` to have
it initialized when Extbase ORM hydrates the model. Following that, the same counts
when using CPP.

Note, that this is true since PHP 7.4 when typed class properties got to play role,
and required to have either the default value assigned in the property definition
or set within the constructor (when the constructor is called).

The above explanation shows that this is not a bug, and more a thing for the documentation
around extbase and extbase models to make not so experienced PHP developers (has nothing to
do with TYPO3 or extbase) aware how to correctly deal with that.

I took the oppurtunity and transformed your "POC showing broking extbase" gerrit change into
a "Demonstrate how it is done correctly" as a task along with tests, thus not closing this
issue here now.

As you are part of the documentation team, can you coordinate the modification and enhancement
of the documentation for this ? Let me know if more insight in PHP is required here, when shareing
the technical background is required or if I should do a short huddle/screenshare to make that a
quick demosntartion over the versions and behaviour (completly with plain PHP without TYPO3 or extbase).

Actions #5

Updated by Gerrit Code Review 9 days ago

Patch set 1 for branch 13.4 of project Packages/TYPO3.CMS has been pushed to the review server.
It is available at https://review.typo3.org/c/Packages/TYPO3.CMS/+/89174

Actions #6

Updated by Lina Wolf 9 days ago

  • Status changed from Under Review to Resolved
  • % Done changed from 0 to 100
Actions

Also available in: Atom PDF