How to Retrieve Data From The Database


In this video we are going to get started with reading data from the MySQL database, which in turn will populate (hydrate) the entity class properties, giving us objects to represent the data in our database.

I know from experience, that this sounds confusing. So lets break it down.

In the previous video we created our RedditPost entity. We also covered how an entity is an object with an ID - much like a row in a database table - that is a PHP class representation of data from the database.

Let's quickly review that entity:

<?php

// src/AppBundle/Entity/RedditPost.php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="reddit_posts")
 */
class RedditPost
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $title;

We covered how the annotations tell Doctrine how our class properties match up to the various columns in our database tables.

Doctrine will use this annotation information when it is pulling data out of our database tables to re-populate / reconstruct one or more entities as dictated by our queries. The proper term for this is hydration.

The way I remember this is to think of an empty jug (our defined, yet empty entity class), and Doctrine 'pours' the data back into the entity / jug, filling it back up / hydrating it. Yeah, bit whacky, but it works for me.

We then used a command to create our database, and reddit_post database table from this entity information.

Given a regular SQL database management client (SequelPro on Mac, SQLYog on Windows, PHPMyAdmin etc), we can then inspect the database and its table, and see how the entity information maps to the created database and table structures.

We can also manually insert some information into the newly created reddit_post table. From the database's perspective, it neither knows nor cares that we are going to be representing its data using an ORM like Doctrine. We just add in data using the client (SequelPro, SQLYog, etc) like normal.

Once we've added some data into the database table, the next logical step seems to me to be retrieving (or Reading from cRud terminology) some or all of that data, and displaying it in our Twig template.

Lets do that now.

We're going to start by placing the majority of our logic inside our Controller action. This is not such a good idea as it gets very messy rather quickly in larger applications. But for demo purposes, and until we cover alternatives in more depth in a future video, we will go with this approach for the moment.

I'm going to assume you have either completed, or have the equivalent knowledge to the content covered in the Beginner Friendly Hands-on Symfony 3 Tutorial series.

<?php

// src/AppBundle/Controller/RedditController.php

namespace AppBundle\Controller;

use AppBundle\Entity\RedditPost;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class RedditController extends Controller
{
    /**
     * @Route("/", name="list")
     */
    public function listAction()
    {
        $posts = $this->getDoctrine()->getRepository('AppBundle:RedditPost')->findAll();

        return $this->render(':reddit:index.html.twig', [
            'posts' => $posts
        ]);
    }

To render this out, we will need a simple Twig template:

<!-- app/Resources/views/reddit/index.html.twig -->

{% extends '::base.html.twig' %}

{% block body %}

    <ul>
        {% for post in posts %}
        <li>{{ post.title }}</li>
        {% endfor %}
    </ul>

{% endblock %}

Let's quickly recap this:

$this->getDoctrine()->getRepository('AppBundle:RedditPost')->findAll();

Our class RedditController is extending Symfony\Bundle\FrameworkBundle\Controller\Controller. By extending this abstract Controller class, we gain access to many convenience methods.

A quick aside: a class being abstract simply means we cannot use it directly. That is, we cannot use Symfony's base Controller class as a real Controller in our application. We can only extend from it.

One common mistake I see amongst beginners to Symfony is that they then expect all of these methods - especially getDoctrine() to be available in any class inside a Symfony application. Not so. It is only available because we are extending a class where that getDoctrine() method exists.

By calling getDoctrine(), our code will reach out to the Service Container and ask for the doctrine service. So long as Doctrine is configured properly (which it will be, if you are using the Symfony standard edition), this method will return the Doctrine Registry service.

One of the methods on this Doctrine Registry is getRepository(), which itself is a shortcut to getting the entity manager, and then getting the requested repository.

Now, this is not something you need to fully understand to actually use this command. It's just nice to know at this stage. The reason I mention it is because often you will see this:

$em = $this->getDoctrine()->getEntityManager();
$result = $em->getRepository('AppBundle:SomeEntity')->find(3); // or whatever

And I used to wonder what the difference was between:

$this->getDoctrine()->getEntityManager()->getRepository('AppBundle:SomeEntity')

and

$this->getDoctrine()->getRepository('AppBundle:SomeEntity')

And it turns out - not much. Just convenience. So, something to be aware of, as this syntax crops up again and again.

The syntax for getRepository is interesting.

You can use the long name of the entity:

AppBundle\Entity\RedditPost

or

AppBundle:RedditPost

But you can only use the short hand syntax (AppBundle:RedditPost) if you follow the convention of putting your entities in the src/YourBundleName/Entity directory. The short hand syntax expects entities to live in the entity directory.

At this stage, providing we have passed in a valid entity, we get access to a bunch of methods on the EntityRepository right away:

  • find - returns individual object
  • findAll - returns array of objects
  • findBy - returns array of objects
  • findOneBy - returns individual object

Are the main ones that we will use initially.

For the purposes of this video we only need findAll, as we simply want to retrieve all the records back from the the reddit_post table and display them on the page.

In the next video we will continue on with the remaining parts of CRUD - creating, updating, and deleting.

Code For This Course

Get the code for this course.

Episodes