DDC-2556: Proxy getId() different code generated when using Trait #3206

Closed
opened 2026-01-22 14:15:25 +01:00 by admin · 12 comments
Owner

Originally created by @doctrinebot on GitHub (Jul 16, 2013).

Originally assigned to: @Ocramius on GitHub.

Jira issue originally created by user entering:

class Timezone {
    /****
     * @var integer
     *
     * @ORM\Column(name="id", type="smallint", nullable=false, options={"unsigned": true})
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /****
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }
}

If I replace that code with a Trait with equal code and use it on the entity the proxy will be generated different.

Without trait:

    /****
     * {@inheritDoc}
     */
    public function getId()
    {
        if ($this->*_isInitialized_* === false) {
            return (int)  parent::getId();
        }


        $this->*_initializer__ && $this->__initializer__->_*invoke($this, 'getId', array());

        return parent::getId();
    }

With trait:

    /****
     * {@inheritDoc}
     */
    public function getId()
    {

        $this->*_initializer__ && $this->__initializer__->_*invoke($this, 'getId', array());

        return parent::getId();
    }

And in this code:

$timezone = $this->timezoneRepository->findReadOnly(
    $campaign->getTimezone()->getId()
);

I get:
Doctrine\ORM\ORMException: The identifier id is missing for a query of EB\Core\KernelBundle\Entity\Common\Timezone

$campaign->getTimezone()->getId()
Is returning null.

About the findReadOnly is just a wrapper that will fetch from cache if not there fetch from DB, anyway if I change it to find() exact same problem

My versions of doctrine:

$ php composer.phar show -i | grep doctrine
doctrine/annotations                   v1.1.2             Docblock Annotations Parser
doctrine/cache                         v1.0               Caching library offering an object-oriented API for many cache backends
doctrine/collections                   v1.1               Collections Abstraction library
doctrine/common                        2.4.0-RC4          Common Library for Doctrine projects
doctrine/data-fixtures                 dev-master 6924952 Data Fixtures for all Doctrine Object Managers
doctrine/dbal                          2.4.0-RC2          Database Abstraction Layer
doctrine/doctrine-bundle               v1.2.0             Symfony DoctrineBundle
doctrine/doctrine-fixtures-bundle      dev-master 512fc0f Symfony DoctrineFixturesBundle
doctrine/doctrine-migrations-bundle    dev-master 5fc1167 Symfony DoctrineMigrationsBundle
doctrine/inflector                     v1.0               Common String Manipulations with regard to casing and singular/plural rules.
doctrine/lexer                         v1.0               Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
doctrine/migrations                    dev-master ced3b41 Database Schema migrations using Doctrine DBAL
doctrine/orm                           2.4.0-RC2          Object-Relational-Mapper for PHP
gedmo/doctrine-extensions              v2.3.6             Doctrine2 behavioral extensions
stof/doctrine-extensions-bundle        dev-master 6577f23 Integration of the gedmo/doctrine-extensions with Symfony2
Originally created by @doctrinebot on GitHub (Jul 16, 2013). Originally assigned to: @Ocramius on GitHub. Jira issue originally created by user entering: ``` class Timezone { /**** * @var integer * * @ORM\Column(name="id", type="smallint", nullable=false, options={"unsigned": true}) * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /**** * Get id * * @return int */ public function getId() { return $this->id; } } ``` If I replace that code with a Trait with equal code and use it on the entity the proxy will be generated different. Without trait: ``` /**** * {@inheritDoc} */ public function getId() { if ($this->*_isInitialized_* === false) { return (int) parent::getId(); } $this->*_initializer__ && $this->__initializer__->_*invoke($this, 'getId', array()); return parent::getId(); } ``` With trait: ``` /**** * {@inheritDoc} */ public function getId() { $this->*_initializer__ && $this->__initializer__->_*invoke($this, 'getId', array()); return parent::getId(); } ``` And in this code: ``` $timezone = $this->timezoneRepository->findReadOnly( $campaign->getTimezone()->getId() ); ``` I get: Doctrine\ORM\ORMException: The identifier id is missing for a query of EB\Core\KernelBundle\Entity\Common\Timezone $campaign->getTimezone()->getId() Is returning null. About the findReadOnly is just a wrapper that will fetch from cache if not there fetch from DB, anyway if I change it to find() exact same problem My versions of doctrine: ``` $ php composer.phar show -i | grep doctrine doctrine/annotations v1.1.2 Docblock Annotations Parser doctrine/cache v1.0 Caching library offering an object-oriented API for many cache backends doctrine/collections v1.1 Collections Abstraction library doctrine/common 2.4.0-RC4 Common Library for Doctrine projects doctrine/data-fixtures dev-master 6924952 Data Fixtures for all Doctrine Object Managers doctrine/dbal 2.4.0-RC2 Database Abstraction Layer doctrine/doctrine-bundle v1.2.0 Symfony DoctrineBundle doctrine/doctrine-fixtures-bundle dev-master 512fc0f Symfony DoctrineFixturesBundle doctrine/doctrine-migrations-bundle dev-master 5fc1167 Symfony DoctrineMigrationsBundle doctrine/inflector v1.0 Common String Manipulations with regard to casing and singular/plural rules. doctrine/lexer v1.0 Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers. doctrine/migrations dev-master ced3b41 Database Schema migrations using Doctrine DBAL doctrine/orm 2.4.0-RC2 Object-Relational-Mapper for PHP gedmo/doctrine-extensions v2.3.6 Doctrine2 behavioral extensions stof/doctrine-extensions-bundle dev-master 6577f23 Integration of the gedmo/doctrine-extensions with Symfony2 ```
admin added the Bug label 2026-01-22 14:15:25 +01:00
admin closed this issue 2026-01-22 14:15:26 +01:00
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by @ocramius:

Is the problem here the repository or just the trait method?

Can you please clean up the issue to insulate only the affected part? What is getId returning on that kind of object?

@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by @ocramius: Is the problem here the repository or just the trait method? Can you please clean up the issue to insulate only the affected part? What is `getId` returning on that kind of object?
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by entering:

Marco I will try to do better, I will try to do make a test case that proves this.

But i can leave here already more info:

  • There is an entity Campaign that have a Timezone (ManyToOne in Campaign side);
  • This entity Campaign is fetch (with lazy in all associations) and serialized and put in cache;
  • This entity Campaign don't have timezone itself, but $campaign->getTimezone()->getId() hit the return (int) parent::getId(); on proxy not making any query to get the timezone, in the case with trait the proxy code is different and it returns null
@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by entering: Marco I will try to do better, I will try to do make a test case that proves this. But i can leave here already more info: - There is an entity Campaign that have a Timezone (ManyToOne in Campaign side); - This entity Campaign is fetch (with lazy in all associations) and serialized and put in cache; - This entity Campaign don't have timezone itself, but $campaign->getTimezone()->getId() hit the return (int) parent::getId(); on proxy not making any query to get the timezone, in the case with trait the proxy code is different and it returns null
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by @ocramius:

[~entering] is the proxy in a detached state when you do this? What happens if (with an existing identifier) you do following?

var_dump($entityManager->getReference('Timezone', 123)->getId());

@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by @ocramius: [~entering] is the proxy in a detached state when you do this? What happens if (with an existing identifier) you do following? `var_dump($entityManager->getReference('Timezone', 123)->getId());`
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by entering:

var_dump ( $this->timezoneRepository->getEM()->getReference('EBCoreKernelBundle:Common\Timezone', 1)->getId() ); // 1

Marco yes is on detached mode, and I know that, I'm relying on the proxy to get the ID, because I don't want any queries being "issued", so I'm doing like

$campaign = $campaignRepository->findReadOnly(10); // hit cache

$timezoneRepository->findReadOnly($campaign->getTimezone()->getId() /** rely on proxy **/); // hit memcache

This just work in the last versions of Doctrine that have lazy getId(), but it looks that for traits something wrong happens on the generation of Proxy.

If on Entity timezone I use the trait but override the getId() everything works perfect again.

@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by entering: `var_dump ( $this->timezoneRepository->getEM()->getReference('EBCoreKernelBundle:Common\Timezone', 1)->getId() ); // 1` Marco yes is on detached mode, and I know that, I'm relying on the proxy to get the ID, because I don't want any queries being "issued", so I'm doing like `$campaign = $campaignRepository->findReadOnly(10); // hit cache` `$timezoneRepository->findReadOnly($campaign->getTimezone()->getId() /** rely on proxy **/); // hit memcache` This just work in the last versions of Doctrine that have lazy getId(), but it looks that for traits something wrong happens on the generation of Proxy. If on Entity timezone I use the trait but override the getId() everything works perfect again.
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by @ocramius:

[~entering] does this also happen with 2.3.x? (asking because the proxy generation logic was rewritten for 2.4)

@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by @ocramius: [~entering] does this also happen with 2.3.x? (asking because the proxy generation logic was rewritten for 2.4)
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by entering:

2.3 the proxy is quite different but the essence of the problem remains:

Proxy with trait (doesn't work, because as far as I know will try to make a query in detach mode):

    public function getId()
    {
        $this->**load();
        return parent::getId();
    }

Proxy without trait (works well):

    public function getId()
    {
        if ($this->*_isInitialized_* === false) {
            return (int) $this->_identifier["id"];
        }
        $this->**load();
        return parent::getId();
    }
@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by entering: 2.3 the proxy is quite different but the essence of the problem remains: Proxy with trait (doesn't work, because as far as I know will try to make a query in detach mode): ``` public function getId() { $this->**load(); return parent::getId(); } ``` Proxy without trait (works well): ``` public function getId() { if ($this->*_isInitialized_* === false) { return (int) $this->_identifier["id"]; } $this->**load(); return parent::getId(); } ```
Author
Owner

@doctrinebot commented on GitHub (Jul 16, 2013):

Comment created by @ocramius:

Ok, so at least I now know it's not an issue with the upgrade, but it was also borked before. Thanks for following along till here: I'll work on a patch as soon as I have time.

@doctrinebot commented on GitHub (Jul 16, 2013): Comment created by @ocramius: Ok, so at least I now know it's not an issue with the upgrade, but it was also borked before. Thanks for following along till here: I'll work on a patch as soon as I have time.
Author
Owner

@doctrinebot commented on GitHub (Feb 23, 2015):

Comment created by tPl0ch:

@ocramius

This just got a little bit hotter for us. We moved all our ID related code into a trait that is shared by most our entities. After deploying that we saw a dramatic rise in small id based queries to the database, which is related to this bug here.

We had to revert the changes for now, but I'd be happy to work on a fix if there still is a need.

Regards
Thomas

@doctrinebot commented on GitHub (Feb 23, 2015): Comment created by tPl0ch: @ocramius This just got a little bit hotter for us. We moved all our ID related code into a trait that is shared by most our entities. After deploying that we saw a dramatic rise in small id based queries to the database, which is related to this bug here. We had to revert the changes for now, but I'd be happy to work on a fix if there still is a need. Regards Thomas
Author
Owner

@doctrinebot commented on GitHub (Feb 23, 2015):

Comment created by tPl0ch:

See http://www.doctrine-project.org/jira/browse/DCOM-276

@doctrinebot commented on GitHub (Feb 23, 2015): Comment created by tPl0ch: See http://www.doctrine-project.org/jira/browse/[DCOM-276](http://www.doctrine-project.org/jira/browse/DCOM-276)
Author
Owner

@Jalle19 commented on GitHub (Dec 4, 2018):

The root cause seems to be that isShortIdentifierGetter() attempts to find the part of the source code where the getter is defined, then it tries to match the code snippet against a regular expression, and if there is a match the method returns true. The problem when traits are used is that the code snippet is the relevant source lines from the class that uses the trait, not the trait itself, hence the check fails and the getter is not eligible for proxying without lazy-loading.

@Jalle19 commented on GitHub (Dec 4, 2018): The root cause seems to be that `isShortIdentifierGetter()` attempts to find the part of the source code where the getter is defined, then it tries to match the code snippet against a regular expression, and if there is a match the method returns true. The problem when traits are used is that the code snippet is the relevant source lines from the class that uses the trait, not the trait itself, hence the check fails and the getter is not eligible for proxying without lazy-loading.
Author
Owner

@Ocramius commented on GitHub (Dec 4, 2018):

Likely fixed by https://github.com/doctrine/common/pull/861

@Ocramius commented on GitHub (Dec 4, 2018): Likely fixed by https://github.com/doctrine/common/pull/861
Author
Owner

@Ocramius commented on GitHub (Dec 4, 2018):

Will be handled by doctrine/common:1.11.0

@Ocramius commented on GitHub (Dec 4, 2018): Will be handled by `doctrine/common:1.11.0`
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#3206