scribble

Xujiajun Blog

About Blog Email GitHub

26 May 2014
Databases and Doctrine [第8天]

One of the most common and challenging tasks for any application involves persisting and reading information to and from a database. Fortunately, Symfony comes integrated with Doctrine, a library whose sole goal is to give you powerful tools to make this easy. In this chapter, you’ll learn the basic philosophy behind Doctrine and see how easy working with a database can be.

Tips:

Doctrine is totally decoupled from Symfony and using it is optional. This chapter is all about the Doctrine ORM, which aims to let you map objects to a relational database (such as MySQL, PostgreSQL or Microsoft SQL). If you prefer to use raw database queries, this is easy, and explained in the “How to use Doctrine’s DBAL Layer” cookbook entry. You can also persist data to MongoDB using Doctrine ODM library. For more information, read the “DoctrineMongoDBBundle” documentation.

A Simple Example: A Product¶

The easiest way to understand how Doctrine works is to see it in action. In this section, you’ll configure your database, create a Product object, persist it to the database and fetch it back out.

Tips:

Code along with the Example If you want to follow along with the example in this chapter, create an AcmeStoreBundle via:

$ php app/console generate:bundle --namespace=Acme/StoreBundle

Configuring the Database¶

Before you really begin, you’ll need to configure your database connection information. By convention, this information is usually configured in an app/config/parameters.yml file:

# app/config/parameters.yml
parameters:
    database_driver:    pdo_mysql
    database_host:      localhost
    database_name:      test_project
    database_user:      root
    database_password:  password

# ...

Tips:

Defining the configuration via parameters.yml is just a convention. The parameters defined in that file are referenced by the main configuration file when setting up Doctrine:

YAML:

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

By separating the database information into a separate file, you can easily keep different versions of the file on each server. You can also easily store database configuration (or any sensitive information) outside of your project, like inside your Apache configuration, for example. For more information, see How to Set External Parameters in the Service Container.

Now that Doctrine knows about your database, you can have it create the database for you:

$ php app/console doctrine:database:create

Tips:

Setting up the Database to be UTF8

One mistake even seasoned developers make when starting a Symfony2 project is forgetting to setup default charset and collation on their database, ending up with latin type collations, which are default for most databases. They might even remember to do it the very first time, but forget that it’s all gone after running a relatively common command during development:

$ php app/console doctrine:database:drop --force
$ php app/console doctrine:database:create

There’s no way to configure these defaults inside Doctrine, as it tries to be as agnostic as possible in terms of environment configuration. One way to solve this problem is to configure server-level defaults.

Setting UTF8 defaults for MySQL is as simple as adding a few lines to your configuration file (typically my.cnf):

[mysqld]
collation-server = utf8_general_ci
character-set-server = utf8

Tips:

If you want to use SQLite as your database, you need to set the path where your database file should be stored:

# app/config/config.yml
doctrine:
    dbal:
        driver: pdo_sqlite
        path: "%kernel.root_dir%/sqlite.db"
        charset: UTF8

Creating an Entity Class¶

Suppose you’re building an application where products need to be displayed. Without even thinking about Doctrine or databases, you already know that you need a Product object to represent those products. Create this class inside the Entity directory of your AcmeStoreBundle:

/ src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;

class Product
{
    protected $name;

    protected $price;

    protected $description;
}

The class - often called an “entity”, meaning a basic class that holds data - is simple and helps fulfill the business requirement of needing products in your application. This class can’t be persisted to a database yet - it’s just a simple PHP class.

Once you learn the concepts behind Doctrine, you can have Doctrine create simple entity classes for you. This will ask you interactive questions to help you build any entity:

$ php app/console doctrine:generate:entity

Add Mapping Information¶

Doctrine allows you to work with databases in a much more interesting way than just fetching rows of a column-based table into an array. Instead, Doctrine allows you to persist entire objects to the database and fetch entire objects out of the database. This works by mapping a PHP class to a database table, and the properties of that PHP class to columns on the table:

For Doctrine to be able to do this, you just have to create “metadata”, or configuration that tells Doctrine exactly how the Product class and its properties should be mapped to the database. This metadata can be specified in a number of different formats including YAML, XML or directly inside the Product class via annotations:

Annotations

// src/Acme/StoreBundle/Entity/Product.php
namespace Acme\StoreBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

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

    /**
     * @ORM\Column(type="string", length=100)
     */
    protected $name;

    /**
     * @ORM\Column(type="decimal", scale=2)
     */
    protected $price;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;
}

Til next time,
Xujiajun at 07:39

scribble

About Blog Email GitHub