Creating Your Database and First Entity with Doctrine


In this first video we are going to get started with a hands-on tutorial using Doctrine with Symfony 3.

The first step we must take is to tell Doctrine how it can interact with our database. This is achieved by entering your database configuration parameters in the rather intuitively named parameters.yml file:

# app/config/parameters.yml
parameters:
    database_driver:    pdo_mysql
    database_host:      localhost
    database_name:      your_db_name_here
    database_user:      your_db_username_here
    database_password:  your_db_password_here

These values will be unique to your system.

What's interesting about these parameters is how they are used inside Symfony's configuration files (e.g. app/config/config.yml). Let's quickly take a look:

# app/config/config.yml
doctrine:
    dbal:
        driver:   '%database_driver%'
        host:     '%database_host%'
        dbname:   '%database_name%'
        user:     '%database_user%'
        password: '%database_password%'

Again, so far, so copy / paste from the Symfony documentation.

Where this gets interesting is how we can override these configuration values for different environments. If you look inside your app/config directory, you will see - by default - there are a number of configuration files:

  • config.yml
  • config_dev.yml
  • config_prod.yml
  • config_test.yml

Each of these maps directly to a given Symfony environment which are essentially different situations in which we might want to interact with our application. During development we can make use of the dev environment (also commonly called app_dev after the app_dev.php file in the web/ directory) which gives us access to the web debug toolbar, or the test environment for running our test suite etc.

The really smart thing is - we can selectively override individual pieces of config for any of these given environments. This is really cool.

An example might be that we have a different database name in our dev environment. We could set this up really easily:

# app/config/config_dev.yml

# Doctrine Configuration
doctrine:
    dbal:
        dbname:   "%test_database_name%"

Now all we need to do is add in the extra parameter to parameters.yml:

# app/config/parameters.yml

parameters:
    # etc
    database_name:      your_db_name_here
    database_user:      your_db_username_here
    database_password:  your_db_password_here

    test_database_name:     a_test_db

And now the development environment works identically to production / other environments, but uses a separate database. This is awesome.

Once these parameters have been added, and assuming the provided username / password combination matches a user with the relevant database privileges, you should be able to run:

php bin/console doctrine:database:create

And Doctrine will go ahead and create your database, as named in your parameters.yml file for you.

You may be wondering though - how do I make it create my development environment database? Good question:

php bin/console doctrine:database:create --env=dev
# equivalent to
php bin/console doctrine:database:create -e=dev

There are a number of other Doctrine commands we can use, and we will cover only a small number of them in this series:

php bin/console

Will list out all the commands that are available in your application, not just for Doctrine but in general.

Entities

You can't talk about Doctrine without talking about Entities.

As I mentioned in the course description, there are a large number of new terms to know and use when using Doctrine. 'Entity' is the most commonly used one by far.

Doctrine's documentation describes entities as:

Entities are PHP Objects that can be identified over many requests by a unique identifier or primary key. These classes don’t need to extend any abstract base class or interface. An entity class must not be final or contain final methods. Additionally it must not implement clone nor wakeup, unless it does so safely.

An entity contains persistable properties. A persistable property is an instance variable of the entity that is saved into and retrieved from the database by Doctrine’s data mapping capabilities.

A basic way to think about an entity is that it is a PHP class that represents a record from your database. This isn't strictly true. An entity can be made up of data from multiple tables. But it's a good place to start, just be aware that it's not technically correct.

An entity is a class with an ID. This is exactly like a row in your database that has an ID.

An entity contains mapping information (usually by way of annotations) that tell Doctrine which fields in your PHP class map to which columns in your database table. Likewise, it will contain mapping information to tell Doctrine which table this entity represents.

An entity usually looks something like this:

<?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;

Entities generally have singular names. RedditPost not RedditPosts. This makes sense a little later when working with entities.

Doctrine will guess at your table name from your entity name, but I always like to specify a table name, and use the plural version of my entity name. This is just personal preference.

I'd advise to type out these annotations for the first 10 or more times you create an entity. It is a little laborious, but it drills it into your fingers for future reference. There is a handy PHPStorm plugin for Symfony that can make this a little easier for you though.

For reference, the list of available property mapping and mapping types are available on the Doctrine documentation. Just be aware, when copying from the Doctrine documentation, that they do not use the @ORM prefix to the annotation, like we do in Symfony land - e.g.:

// official Doctrine docs:

/** @Column(name="`number`", type="integer") */
private $number;

// vs Symfony style:

/** @ORM\Column(name="`number`", type="integer") */
private $number;

Once you have created an entity like the above, there is another Doctrine command that we can run from the command line to create a table for the entity:

php bin/console doctrine:schema:update --force

If you don't include the --force flag then you will do a 'dry-run' where nothing happens, but you get to see what would have happened. Useful to validate before you run the real command.

Assuming this all went well, then now you should have a brand new, empty table in your database called reddit_posts, just waiting for you to add some data. Which is exactly what we shall do in the very next video.

Automated Builds

As mentioned in this video series, I use a tool called Ansible for all my server builds. This is partly because I do a heck of a lot of new server setup for all my tutorial series, but also in a large part because Ansible helps not only automate, but document the process of any particular server.

This is a more advanced devops topic, and definitely not required to work with Symfony at all. But it is cool, and if you're into that sort of thing, then I highly recommend Ansible as a build tool.

Code For This Course

Get the code for this course.

Episodes