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 objectfindAll
- returns array of objectsfindBy
- returns array of objectsfindOneBy
- 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.