Please Provide At Least Two (2) Written References


Let's imagine a situation where you know of a list of available objects that can be related to your current object. And by knowing what's in that list ahead of time, you can use the id of each list item / element to quickly update another object with this data, rather than involve an expensive database lookup for each list item or element.

That's a little high level, so let's make the example more concrete.

We have just written a brand new Blog Post. This isn't our first rodeo as it transpires, we've been creating content on our blog now for a long time. During that time we've come up with some Categories that our Posts routinely fall under.

We live in Symfony2 Framework Land.

When loading up our User Interface, we could proactively pull out a list of all available Categories, and present them to the ourselves in our role as user-land role of Author, in a list of checkboxes, nicely spruced up with a bit of bootstrap CSS. Anyway, the designers can make it look nice.

We do our query:

$categories = $qb->select('c')
  ->from('AppBundle:Categories', 'c')
  ->getQuery()
  ->useResultCache(true)
  ->getResult();

(if ->useResultCache(true) is new to you, be sure to check out the video for using Doctrine's Cache)

We do all the twiggy stuff, or display out another way, in whatever way takes your fancy / whatever javascript framework is cool this week, but ultimately we know the list of possibilities we are going to get back are already in our list of available choices. We'd likely use the Form and the Validation Components to ensure this.

Ensuring these id's exist is pretty important.

So we display the Categories off somehow, and the Author picks, say, three Categories to associate with this particular Post.

As part of keeping our entity associations in check, we might have a function like this, ready to do our dirty work, over and over again:

<?php
// src/AppBundle/Entity/Post.php
// ** snip **

    /**
     * @ORM\ManyToMany(targetEntity="Post", inversedBy="categories")
     * @ORM\JoinTable(name="posts_categories")
     **/
    private $categories;

    public function __construct()
    {
        $this->categories = new ArrayCollection();
    }

    public function addToCategory(Category $category = null)
    {
        if ( ! $this->categories->contains($category)) {
            $this->categories->add($category);
        }

        return $this;
    }

    public function removeFromCategory(Category $category)
    {
        if ($this->categories->contains($category)) {
            $category->removeFromPost($this);
            $this->categories->removeElement($category);
        }

        return $this;
    }

As we've already run the initial query to pull out our list of available Categories for displaying the UI, we've more than likely included the Category' id field as part of the UI list. Our Author has picked a few Categories, and now we just want to associate the Category and the Post.

We don't need to pull out the full, usable Category object from the database, that's just wasteful.

Foxy Proxy

Instead, we can use the Categoryies id, which from our Post's point of view is a Foriegn Key, to get a Reference to the Category object, and use that Reference instead.

This saves us from having to do a query to look up the Category again before we can call addToCategory on our Post.

We can, instead, change our call entirely from:

$category = $em->getRepository('AppBundle:Category')->find($categoryId);

to

$category = $em->getRepository('AppBundle\Entity\Category', $categoryId);

Instead of retrieving a full Category object, Doctrine will now return a Reference or proxy of the Category with id of whatever id you specified in $categoryId.

You can use $category in exactly the same way, regardless of whichever method you choose.

However, if $categoryId is not a valid Category, well, you're in for a bad time.

Confession Time

I'm gunna be totally honest. I consider this a high probability premature optimisation.

There are places this could be useful. But those places would require a specific solution to a really specific problem - in this case, it might be useful if you were running a growing BlogSpot or Wordpress.com-esque style site.

A site that specialises in running blogs for others, and implementing this could be the difference between being able to continue running on one, or a small few VPS servers, versus having to splunk out wads on a more powerful spec.

If it moves the bottom line in your business, do this. If it doesn't, don't bother, their are likely juicier fish to fry.

Geek Out

Whilst this technique may not be inherently useful to you in your every day coding, it is interesting for one more reason - other than having an additional string to your bow that is.

We already know that when we do our Doctrine Lazy Loading we aren't really pulling back an entire object graph.

That is to say, if we do a query for Post with id of 36, the resulting Post object won't also pull back fully hydrated Category, Author, and any other objects that it has associations with.

Doctrine actually does this internally by using References. That same sort we just learned how to use.

Pretty cool, if nothing else than to learn a little bit more about how Doctrine works internally.

Code For This Course

Get the code for this course.

Episodes