Skip to content

IBX-11179: Resolve PHP 8.4 lazy proxy incompatibility#707

Open
wiewiurdp wants to merge 7 commits into4.6from
IBX-11179-PHP-8.4-certification-entity-manager-not-lazy
Open

IBX-11179: Resolve PHP 8.4 lazy proxy incompatibility#707
wiewiurdp wants to merge 7 commits into4.6from
IBX-11179-PHP-8.4-certification-entity-manager-not-lazy

Conversation

@wiewiurdp
Copy link
Contributor

@wiewiurdp wiewiurdp commented Jan 26, 2026

🎫 Issue IBX-11179

Description:

This pull request removes the lazy loading mechanism from Doctrine EntityManager to ensure full PHP 8.4 compatibility. The issue arises from Symfony's lazy proxy factory limitation when handling nested lazy services, which is incompatible with PHP 8.4's strict lazy proxy requirements.

PHP 8.4 introduces stricter rules for lazy proxy handling. Symfony's lazy proxy factory cannot handle nested lazy services, resulting in the error: "Lazy proxy factory must return a non-lazy object". The current implementation of EntityManager relied on lazy loading, which violates this constraint.

The fix implements SiteAccessAwareEntityManager, a non-lazy decorator that wraps EntityManager and implements explicit lazy resolution via EntityManagerFactory.

(almost) green regressions : ibexa/commerce#1668
Results discussed with QA and these fails are known.

For QA:

Please do sanities with multirepository setup

Documentation:

@wiewiurdp wiewiurdp changed the title Remove lazy loading for Doctrine EntityManager IBX-11179: Remove lazy loading for Doctrine EntityManager Jan 27, 2026
@wiewiurdp wiewiurdp marked this pull request as ready for review January 27, 2026 08:51
@wiewiurdp wiewiurdp requested a review from a team January 27, 2026 08:51
@ibexa-workflow-automation-1 ibexa-workflow-automation-1 bot requested review from Steveb-p, ViniTou, alongosz, barw4, ciastektk, konradoboza, mikadamczyk and tbialcz and removed request for a team January 27, 2026 08:51
@wiewiurdp wiewiurdp marked this pull request as draft January 28, 2026 07:47
@wiewiurdp wiewiurdp force-pushed the IBX-11179-PHP-8.4-certification-entity-manager-not-lazy branch from 279fbba to 856bb49 Compare January 29, 2026 08:04
@wiewiurdp wiewiurdp changed the title IBX-11179: Remove lazy loading for Doctrine EntityManager IBX-11179: Resolve PHP 8.4 lazy proxy incompatibility Jan 29, 2026
@wiewiurdp wiewiurdp marked this pull request as ready for review January 29, 2026 14:34
@wiewiurdp wiewiurdp requested a review from a team January 29, 2026 14:35
@ibexa-workflow-automation-1 ibexa-workflow-automation-1 bot requested review from Steveb-p, ViniTou, alongosz, barw4, ciastektk, konradoboza, mikadamczyk and tbialcz and removed request for a team January 29, 2026 14:35
@wiewiurdp wiewiurdp force-pushed the IBX-11179-PHP-8.4-certification-entity-manager-not-lazy branch from 2e7d02f to ba89981 Compare January 29, 2026 15:08
@wiewiurdp wiewiurdp requested a review from konradoboza January 29, 2026 15:24
path: src/lib/Persistence/Cache/UserPreferenceHandler.php

-
message: '#^Return type \(Doctrine\\ORM\\Mapping\\ClassMetadataFactory\) of method Ibexa\\Core\\Persistence\\Doctrine\\SiteAccessAwareEntityManager\:\:getMetadataFactory\(\) should be compatible with return type \(Doctrine\\Persistence\\Mapping\\ClassMetadataFactory\<Doctrine\\Persistence\\Mapping\\ClassMetadata\<object\>\>\) of method Doctrine\\Persistence\\ObjectManager\:\:getMetadataFactory\(\)$#'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't add new entries to PHPStan baseline in the new code, please resolve this one as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@konradoboza
The problem is that :

\Doctrine\ORM\EntityManagerInterface has:

/**
 * EntityManager interface
 *
 * @method Mapping\ClassMetadataFactory getMetadataFactory()
 * @method mixed wrapInTransaction(callable $func)
 * @method void refresh(object $object, ?int $lockMode = null)
 */
interface EntityManagerInterface extends ObjectManager

and in: \Doctrine\Persistence\ObjectManager

there is :

 /**
     * Gets the metadata factory used to gather the metadata of classes.
     *
     * @phpstan-return ClassMetadataFactory<ClassMetadata<object>>
     */
    public function getMetadataFactory();

Should I add phpstan line ignore to SiteAccessAwareEntityManager instead of adding it to phpstan-baseline ?

class: Doctrine\ORM\EntityManager
lazy: true
factory: ['@ibexa.doctrine.orm.entity_manager_factory', 'getEntityManager']
class: Ibexa\Core\Persistence\Doctrine\SiteAccessAwareEntityManager
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also have decorates: here?
Regardless: doesn't that approach leave us with some technical debt we need to reassess later while upgrading dependencies late? I wonder how Doctrine themselves have dealt with providing support for PHP8.4. Have you checked that? First idea is the one we initially have - bumping the dependency version. However, maybe there is a specific PHP8.4-compatibility-related part we might be able to utilize for the time being.

POV ping @alongosz @Steveb-p.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should NOT decorate the primary Doctrine Entity Manager.

We only expect it to "overwrite" the default behavior specifically when we ask for ibexa.doctrine.orm.entity_manager service.

@wiewiurdp wiewiurdp changed the base branch from main to 4.6 February 4, 2026 10:29
@wiewiurdp wiewiurdp force-pushed the IBX-11179-PHP-8.4-certification-entity-manager-not-lazy branch from ba89981 to d6345e6 Compare February 4, 2026 10:30
Comment on lines +41 to +57
private function getWrapped(): EntityManagerInterface
{
return $this->resolvedEntityManager ??= $this->entityManagerFactory->getEntityManager();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed on daily meetup, I expect this $this->resolvedEntityManager to be reset when SiteAccess changes (Ibexa\Core\MVC\Symfony\MVCEvents::CONFIG_SCOPE_CHANGE or Ibexa\Core\MVC\Symfony\MVCEvents::CONFIG_SCOPE_RESTORE).

Additionally, up for debate within team, is whether we should use kernel.reset, since we have effectively a stateful service.

@wiewiurdp wiewiurdp force-pushed the IBX-11179-PHP-8.4-certification-entity-manager-not-lazy branch from 9b243f1 to 3b865c7 Compare February 4, 2026 14:34
@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 4, 2026

@wiewiurdp wiewiurdp requested a review from Steveb-p February 4, 2026 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants