120K Views

Doctrine Proxy Objects and Lazy Loading

Doctrine is a Object Relational Mapper (ORM) that sits on top of a powerful Database Abstraction Layer (DBAL). When you’ve been working with Symfony (+ Doctrine) for a while, you’re bound to have come across Doctrine’s Proxy Objects.

public function setSubjects(\ProxyBundle\Entity\Subjects $subjects = null)
{
    $this->subjects = $subjects;

    return $this;
}

If you’ve ever generated an entity which is associated with another entity, and have taken a look at the arguments for the function associated with that entity in the generated entity file, you might have noticed the extra backslash before the type declaration for the function argument. In this case, ‘\‘ before ‘ProxyBundle\Entity\Subjects‘. If you’re like me, you might have wondered about that backslash, and you need to know about Doctrine’s Proxy Objects to understand it’s purpose.

On a general day-to-day basis, a developer shouldn’t be bothered by a proxy object, they should be transparent to your code. And Doctrine accomplishes that perfectly. I remember the first time I actually had to take a look at them was when I ran into an issue with the cache. You don’t need to know what Proxy Objects are and what they help accomplish, but it sure helps to know. That’s what we’ll be talking about today.

Doctrine Proxy Objects:

Doctrine’s Proxy Objects are based primarily on two Design Patterns: Proxy Pattern, and Lazy Loading Pattern.

According to the documentation:

A proxy object is an object that is put in place or used instead of the “real” object. A proxy object can add behavior to the object being proxied without that object being aware of it. In Doctrine 2, proxy objects are used to realize several features but mainly for transparent lazy-loading.

Proxy objects with their lazy-loading facilities help to keep the subset of objects that are already in memory connected to the rest of the objects. This is an essential property as without it there would always be fragile partial objects at the outer edges of your object graph.

To put it in simple term, a proxy object is simply a wrapper object that extends the functionality of the base entity class and provides it with lazy loading abilities. When you fetch an entity from a database, the base entity is fully initialized, except the entities that are associated with it. These entities are then partially loaded and wrapped into a proxy object. At this point, only the id of the associated entity is known. Then when we further access a method or property of this proxied object, Doctrine will make a request to the database to load that property if it’s not already loaded.

Like said before, this happens fully transparent to your application due to the fact that the proxy extends your entity class. So whenever you persist or flush your entities to the Database, you don’t need to worry about whether you have a proxy object or the actual entity. You can refer the Doctrine Documentation to know more about the internals of Doctrine and how they approach in optimizing your queries.

Why Proxy Objects?

There’s really not much to proxy objects. It’s simply a wrapper object that sits on top of the base entity and extends it to include lazy-loading functionalities. The main benefit this functionality provides is in optimising your database queries. When you’re executing big queries, or fetching a large amount of data from the database, Doctrine steps in and loads only the data that is needed at the time, reducing the execution time. Then when further properties are accessed from these entities, Doctrine will load them from the database if they are not already loaded.

The problem that remains is that you need to know when you’re making too many database request to load individual properties when it makes sense to load the entire entity itself. Of course, this depends on how you model your application so it pays to know when to load entities through proxy objects and when to load entities through eager fetching.

By default, when you fetch an entity from the database, they are fully initialised, but the associated entities are only partially loaded. Moreover, if you know the id of base entity, you can partially load it without initializing any of it’s properties. To do so:

$entityManager = $this->getDoctrine()->getManager();
$user = $entityManager->getReference('ProxyBundle:User', 1);

Here, you’d be setting a reference to the target entity.

By default, associated entities are lazy loaded, as said before. However, if you require them to be initialized completely, you could simply set fetch: EAGER, as shown below:

ProxyBundle\Entity\User:
    type: entity
    oneToOne:
        subjects:
            targetEntity: ProxyBundle\Entity\Subjects
            fetch: EAGER
            joinColumn:
                name: subjects_id
                referencedColumnName: id
                onDelete : cascade
    table: null
    repositoryClass: ProxyBundle\Repository\UserRepository
    id:
        id:
            type: integer
            id: true
            generator:
                strategy: AUTO
    fields:
        firstName:
            type: string
            length: 255
        lastName:
            type: string
            length: 255
            nullable: true
        age:
            type: integer
        gender:
            type: string
            length: 255

With fetch: EAGER, instead of being lazy loaded, the associated entities will be fully initialized.

Partial Objects:

A lot of people may confuse Partial Objects with Proxy Objects and it’s important to know the difference between the two. A partial object is an object whose state is not fully initialized after being reconstituted from the database and that is disconnected from the rest of its data.

In contrast to proxy objects, the use of partial objects is generally discouraged. When working with partial objects, one needs to be aware of properties and methods which are safely accessible and ones which aren’t. Moreover, fields that are not retrieved from the database will not be updated by the EntityManager’s UnitOfWork even if they get changed in your objects. This is in contrast to proxy objects, where even if you access a method or property which are not initialized, they are safely accessible since they’ll be loaded from the database due to the proxy.

You can learn more about Partial Objects here.

Category(s) Doctrine UVdesk
. . .

Comment (1)

Add Your Comment

  • Roman Malovanyi
    Thanks, great article!
  • css.php