DDC-3392: Add a way to use a custom instantiator in ClassMetadataInfo #4190

Closed
opened 2026-01-22 14:37:00 +01:00 by admin · 4 comments
Owner

Originally created by @doctrinebot on GitHub (Nov 13, 2014).

Originally assigned to: @Ocramius on GitHub.

Jira issue originally created by user rekam:

Hi,

In my project, I'm using a home made container of dependencies, that I use sometimes in my entities. I found very useful to use EntityListeners and EntityResolver to be able, on PostLoad event, to inject dependencies into the models.

Thinking of that, should it be a good idea to implement some custom instantiators that could do this, using the model's constructor?

Here's a quick example:

class MyInstantiator implements \Doctrine\Instantiator\InstantiatorInterface {

    private $container;

    public function **construct($container) {
        $this->container = $container;
    }

    public function instantiate($className) {
        // return a new model instance, with it's dependencies
        return $this->container->get($classname);
    }

}

// set default instantiator in entity manager
// container = your dependencies container
$entityManager->setDefaultInstantiator(new MyInstantiator($container));

Now in ClassMetadataInfo class, the instantiator cannot be overridden. Check these lines below. Instantiator is private and created via [new] in constructor and in wakeup method. Do we need to override ClassMetadataInfo to achieve this?

class ClassMetadataInfo implements ClassMetadata
{
    ...

    /****
     * @var \Doctrine\Instantiator\InstantiatorInterface|null
     */
    private $instantiator;

    /****
     * Initializes a new ClassMetadata instance that will hold the object-relational mapping
     * metadata of the class with the given name.
     *
     * @param string              $entityName     The name of the entity class the new instance is used for.
     * @param NamingStrategy|null $namingStrategy
     */
    public function **construct($entityName, NamingStrategy $namingStrategy = null)
    {
        $this->name = $entityName;
        $this->rootEntityName = $entityName;
        $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy();
        $this->instantiator   = new Instantiator();
    }

    // ...

    /****
     * Restores some state that can not be serialized/unserialized.
     *
     * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService
     *
     * @return void
     */
    public function wakeupReflection($reflService)
    {
        // Restore ReflectionClass and properties
        $this->reflClass    = $reflService->getClass($this->name);
        $this->instantiator = $this->instantiator ?: new Instantiator();

        // ...
    }
    // ...
}

Thanks,

Originally created by @doctrinebot on GitHub (Nov 13, 2014). Originally assigned to: @Ocramius on GitHub. Jira issue originally created by user rekam: Hi, In my project, I'm using a home made container of dependencies, that I use sometimes in my entities. I found very useful to use EntityListeners and EntityResolver to be able, on PostLoad event, to inject dependencies into the models. Thinking of that, should it be a good idea to implement some custom instantiators that could do this, using the model's constructor? Here's a quick example: ``` class MyInstantiator implements \Doctrine\Instantiator\InstantiatorInterface { private $container; public function **construct($container) { $this->container = $container; } public function instantiate($className) { // return a new model instance, with it's dependencies return $this->container->get($classname); } } // set default instantiator in entity manager // container = your dependencies container $entityManager->setDefaultInstantiator(new MyInstantiator($container)); ``` Now in ClassMetadataInfo class, the instantiator cannot be overridden. Check these lines below. Instantiator is private and created via [new] in constructor and in wakeup method. Do we need to override ClassMetadataInfo to achieve this? ``` class ClassMetadataInfo implements ClassMetadata { ... /**** * @var \Doctrine\Instantiator\InstantiatorInterface|null */ private $instantiator; /**** * Initializes a new ClassMetadata instance that will hold the object-relational mapping * metadata of the class with the given name. * * @param string $entityName The name of the entity class the new instance is used for. * @param NamingStrategy|null $namingStrategy */ public function **construct($entityName, NamingStrategy $namingStrategy = null) { $this->name = $entityName; $this->rootEntityName = $entityName; $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy(); $this->instantiator = new Instantiator(); } // ... /**** * Restores some state that can not be serialized/unserialized. * * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService * * @return void */ public function wakeupReflection($reflService) { // Restore ReflectionClass and properties $this->reflClass = $reflService->getClass($this->name); $this->instantiator = $this->instantiator ?: new Instantiator(); // ... } // ... } ``` Thanks,
admin added the Improvement label 2026-01-22 14:37:00 +01:00
admin closed this issue 2026-01-22 14:37:01 +01:00
Author
Owner

@doctrinebot commented on GitHub (Nov 13, 2014):

Comment created by @ocramius:

This is exactly the type of dependency that you DO NOT want in an entity.

Don't do this, it's discouraged and it will likely cause only headaches.

Marking as Won't Fix.

@doctrinebot commented on GitHub (Nov 13, 2014): Comment created by @ocramius: This is exactly the type of dependency that you DO NOT want in an entity. Don't do this, it's discouraged and it will likely cause only headaches. Marking as `Won't Fix`.
Author
Owner

@doctrinebot commented on GitHub (Nov 13, 2014):

Issue was closed with resolution "Won't Fix"

@doctrinebot commented on GitHub (Nov 13, 2014): Issue was closed with resolution "Won't Fix"
Author
Owner

@doctrinebot commented on GitHub (Nov 13, 2014):

Comment created by rekam:

Thanks for your feedback. I'm playing with this design pattern since a few days only, so I'm not quite confident about what is or isn't "good".

So your approach is to add a listener to the entity and manage all dependencies in the listener class? Can we say that's a best practice, or even a rule, to not ask for any dependency in any method of any entity?

Have a nice evening

@doctrinebot commented on GitHub (Nov 13, 2014): Comment created by rekam: Thanks for your feedback. I'm playing with this design pattern since a few days only, so I'm not quite confident about what is or isn't "good". So your approach is to add a listener to the entity and manage all dependencies in the listener class? Can we say that's a best practice, or even a rule, to not ask for any dependency in any method of any entity? Have a nice evening
Author
Owner

@doctrinebot commented on GitHub (Nov 13, 2014):

Comment created by @ocramius:

{quote}So your approach is to add a listener to the entity and manage all dependencies in the listener class?{quote}

The idea is to NOT have dependencies in entities at all. It is arguably not necessarily an absolute, but it's a good practice to let entities only be aware of their siblings.

See also http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/

@doctrinebot commented on GitHub (Nov 13, 2014): Comment created by @ocramius: {quote}So your approach is to add a listener to the entity and manage all dependencies in the listener class?{quote} The idea is to NOT have dependencies in entities at all. It is arguably not necessarily an absolute, but it's a good practice to let entities only be aware of their siblings. See also http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#4190