Verification: a143cc29221c9be0

Php bin console make migration

Installation

It is very simple to install Doctrine on your Symfony project. Thanks to Symfony Flex, we can simply use the following command:

// Install Doctrine
$ composer require doctrine

This package comes with a database access layer (DAL), but also with a migrations component, which helps to migrate production databases.

The database connection settings can simply be done via environment variable in the .env file.

The Flex recipe for the installed component created a config YAML file, too. There you can specify all your settings, if you want to change the default behaviour.

You will also see, that you have some more commands available with bin/console. One of them is able to create a database for you:

// Create a database using doctrine
php bin/console doctrine:database:create

Add Entities

To add some tables and rows to the database, you have to create an entity in your project. The entity is a POPO with doctrine annotations. Entities can be created by hand, but the recommended way is to use the Symfony Maker Bundle:

// Install Symfony Maker Bundle
$ composer require maker

With this component installed, you can easily create entities via the following bin/console command:

// Create a doctrine entity
$ php bin/console make:entity

This gives you an PHP class (and a repository class, we will cover later on) with some annotations, which tell Doctrine, that it is not just a normal PHP class, but a Doctrine entity.

Since Doctrine is an ORM this PHP classes will have a corresponding database table for persisting the data.

The annotations will look something like this and are mostly self explained:

/**
 * @ORM\Entity(repositoryClass="App\Repository\ExampleClassRepository")
 */
class ExampleClass
{
...

The generated class can be modified by our needs! We can add, remove, rename etc. every property we want.

Migrate Database

So, how do we get our database tables, that correspond to our entity?
Every database update is done in two steps:

  1. Generate a migrations file
  2. Use the migrations file to update the database.
// Create a migrations file, that holds the database migration queries
$ php bin/console make:migration

// Use the generated migrations file and migrate the database
$ php bin/console make:migrations:migrate

Of course, you can modify the generated file according to your needs any time. These CLI tools only support us in our work. We can use them and then customise their output. In fact it is highly recommended to check the database update statement in the migrations file always.

Doctrine also remembers, how your database looks like. It creates a migration table in your database and inserts the version number of the generated migration file, so that it is always aware of the actual status of your database. You can check that out by printing the status of doctrine migrations to the terminal.

// Status of the database
& php bin/console doctrine:migrations:status

You will use this two steps each and every time you change one of your entities and therefore have to change your database. Make sure you commit your migrations files to your VCS (hopefully Git), to be aware of all changes you have done.

Save data

The next thing you normally want to do is saving some data. You can do this by autowiring the corresponding Doctrine service into your controller, since we are working in the Symfony universe. To find the service, use the autowiring overview:

// Search for the EntityManagerInterface in the autowiring overview
$ php bin/console debug:autowiring

The EntityManagerInterface is the service you want to use. Use this class, to run the two saving functions:

  • persist($new\_entity_instance) – This puts the entity you want to save into a queue of queries, that should be written to the database.
  • flush() – This executes all the queries within this queue.

This way, you will save all your data. The ID of the new database entry will automatically be added to the $new_entity_instance variable via Reflection API.

To have a look into your database, you can either use your database directly or use the bin/console command. You can use SQL oder DQL to query the database.

// Query the database with SQL
$ php bin/console doctrine:query:sql "SELECT * FROM some_table"

Query data

Querying data is also done by using the EntityManagerInterface. But this time, you want to have the repository class of the entity.

...
// $entity_manager is the autowired instance of EntityManagerInterface
$example_class_repository = $entity_manager->getRepository(ExampleClass:class);
...

This repository can then use methods to query the database. These methods are for example:

  • find(...)
  • findAll(...)
  • findBy(...)

The repository can handle normal "standard" queries by default with this built-in functions. For custom queries you just have to create more methods in the repository class. The queries can then be written in SQL or DQL (Doctrine Query Language). The second option is necessary, because Doctrine supports more than one database and therefore translates the query from DQL to the underlying query language of the database. DQL uses the names of the entities and their variables, instead of the table and column names like SQL, because Doctrine is an ORM and wants you to work with objects.

You can create DQLs simply by typing them by yourself or use the QueryBuilder class to help you with this. A function in the repository might then look like this:


/**
 * Method, that fetches something from the database by using the QueryBuilder.
 */
public function example_method_that_fetches_something()
    {
        return $this->createQueryBuilder('a')
            ->andWhere('a.memberVariable IS NOT NULL')
            ->orderBy('a.memberVariable', 'DESC')
            ->getQuery()
            ->getResult()
        ;
    }

The repository class can simply be used, as like a service, because they are also registered as services within Symfony, since it is located in the ./src/ directory. If you generate the entity with the Maker Bundle, you will find your repositories under ./src/Repository/. So you can just autowire them anywhere.

Generate test data

In order to generate test data, we can use two doctrine components, that can be installed via a Flex alias. The ORM fixture feature:

// Install ORM frixture feature
$ composer require orm-fixtures --dev

We can use the tool via bin/console again, but first we use the Maker Bundle to create a fixture.

// Create a new Fixture class
$ php bin/console make:fixtures

In this class, we can create an entity and persist() it. The code gets executed, when we call the following command.
Attention: This will clear the database first.

// Seed the database with our fixture data
$ php bin/console doctrine:fixtures:load

The logic that is used to generate the entities can be modified, for example to have a base class, that provides some helper methods, that are necessary more often.

Generate fake or random data

If you do not want to create every entity by yourself, you can just create a for loop to generate more than one at a time. Additionally it is a good idea to fake the data and not hardcode them. For example, the text of a member variable of an entity should probably vary for different entities. This can be done with the Faker component.

// Install the Faker component
$ composer require fzaninotto/faker --dev

Faker is able to generate random values of all kind. Visit the Github page for more information. For sure, you can use it in your fixtures classes to generate a valid set of seed data in your development or test environment.

Of course, the Faker project is independent of Symfony and Doctrine, but is a good tool in this case.

Timestamps

If you ever have the need of an updated and created timestamp on your entities and therefore in your database, you can just implement this by your own. Another way of doing this is to use the "timestampable" feature of the StofDoctrineExtensionsBundle. To install the component use the following command:

// Install the exentsion
$ composer require antishov/doctrine-extensions-bundle

You can use this on different ways, but the easiest is to add the TimestampableEntity trait within your entity. With this, you will have the two new fields, that get updated accordingly with the database events through the Doctrine event subscriber system.