You are currently viewing the 1.0 version of Doctrine ORM for PHP.

Introduction

Code Examples

The text in this book contains lots of PHP code examples. All starting and ending PHP tags have been removed to reduce the length of the book. Be sure to include the PHP tags when you copy and paste the examples.

What is Doctrine?

Doctrine is an object relational mapper (ORM) for PHP 5.2.3+ that sits on top of a powerful database abstraction layer (DBAL). One of its key features is the option to write database queries in a proprietary object oriented SQL dialect called Doctrine Query Language (DQL), inspired by Hibernates HQL. This provides developers with a powerful alternative to SQL that maintains flexibility without requiring unnecessary code duplication.

What is an ORM?

Object relational mapping is a technique used in programming languages when dealing with databases for translating incompatible data types in relational databases. This essentially allows for us to have a "virtual object database," that can be used from the programming language. Lots of free and commercial packages exist that allow this but sometimes developers chose to create their own ORM.

What is the Problem?

We are faced with many problems when building web applications. Instead of trying to explain it all it is best to read what Wikipedia has to say about object relational mappers.

Pulled from Wikipedia:

Data management tasks in object-oriented (OO) programming are typically implemented by manipulating objects, which are almost always non-scalar values. For example, consider an address book entry that represents a single person along with zero or more phone numbers and zero or more addresses. This could be modeled in an object-oriented implementation by a "person object" with "slots" to hold the data that comprise the entry: the person's name, a list (or array) of phone numbers, and a list of addresses. The list of phone numbers would itself contain "phone number objects" and so on. The address book entry is treated as a single value by the programming language (it can be referenced by a single variable, for instance). Various methods can be associated with the object, such as a method to return the preferred phone number, the home address, and so on.

However, many popular database products such as SQL DBMS can only store and manipulate scalar values such as integers and strings organized within tables.

The programmer must either convert the object values into groups of simpler values for storage in the database (and convert them back upon retrieval), or only use simple scalar values within the program. Object-relational mapping is used to implement the first approach.

The height of the problem is translating those objects to forms that can be stored in the database for easy retrieval, while preserving the properties of the objects and their relationships; these objects are then said to be persistent.

Minimum Requirements

Doctrine requires PHP >= 5.2.3+, although it doesn't require any external libraries. For database function call abstraction Doctrine uses PDO which comes bundled with the PHP official release that you get from www.php.net.

If you use a 3 in 1 package under windows like Uniform Server, MAMP or any other non-official package, you may be required to perform additional configurations.

Basic Overview

Doctrine is a tool for object-relational mapping in PHP. It sits on top of PDO and is itself divided into two main layers, the DBAL and the ORM. The picture below shows how the layers of Doctrine work together.

Doctrine Layers

The DBAL (Database Abstraction Layer) completes and extends the basic database abstraction/independence that is already provided by PDO. The DBAL library can be used standalone, if all you want is a powerful database abstraction layer on top of PDO. The ORM layer depends on the DBAL and therefore, when you load the ORM package the DBAL is already included.

Doctrine Explained

The following section tries to explain where Doctrine stands in the world of ORM tools. The Doctrine ORM is mainly built around the Active Record, Data Mapper and Meta Data Mapping patterns.

Through extending a specific base class named Doctrine_Record, all the child classes get the typical ActiveRecord interface (save/delete/etc.) and it allows Doctrine to easily participate in and monitor the lifecycles of your records. The real work, however, is mostly forwarded to other components, like the Doctrine_Table class. This class has the typical Data Mapper interface, createQuery(), find(id), findAll(), findBy*(), findOneBy*() etc. So the ActiveRecord base class enables Doctrine to manage your records and provides them with the typical ActiveRecord interface whilst the mapping footwork is done elsewhere.

The ActiveRecord approach comes with its typical limitations. The most obvious is the enforcement for a class to extend a specific base class in order to be persistent (a Doctrine_Record). In general, the design of your domain model is pretty much restricted by the design of your relational model. There is an exception though. When dealing with inheritance structures, Doctrine provides some sophisticated mapping strategies which allow your domain model to diverge a bit from the relational model and therefore give you a bit more freedom.

Doctrine is in a continuous development process and we always try to add new features that provide more freedom in the modeling of the domain. However, as long as Doctrine remains mainly an ActiveRecord approach, there will always be a pretty large, (forced) similarity of these two models.

The current situation is depicted in the following picture.

Relational Bounds

As you see in the picture, the domain model can't drift far away from the bounds of the relational model.

After mentioning these drawbacks, it's time to mention some advantages of the ActiveRecord approach. Apart from the (arguably slightly) simpler programming model, it turns out that the strong similarity of the relational model and the Object Oriented (OO) domain model also has an advantage: It makes it relatively easy to provide powerful generation tools, that can create a basic domain model out of an existing relational schema. Further, as the domain model can't drift far from the relational model due to the reasons above, such generation and synchronization tools can easily be used throughout the development process. Such tools are one of Doctrine's strengths.

We think that these limitations of the ActiveRecord approach are not that much of a problem for the majority of web applications because the complexity of the business domains is often moderate, but we also admit that the ActiveRecord approach is certainly not suited for complex business logic (which is often approached using Domain-Driven Design) as it simply puts too many restrictions and has too much influence on your domain model.

Doctrine is a great tool to drive the persistence of simple or moderately complex domain models(1) and you may even find that it's a good choice for complex domain models if you consider the trade-off between making your domain model more database-centric and implementing all the mapping on your own (because at the time of this writing we are not aware of any powerful ORM tools for PHP that are not based on an ActiveRecord approach).

(1) Note that complexity != size. A domain model can be pretty large without being complex and vice versa. Obviously, larger domain models have a greater probability of being complex.

Now you already know a lot about what Doctrine is and what it is not. If you would like to dive in now and get started right away, jump straight to the next chapter "Getting Started".

Key Concepts

The Doctrine Query Language (DQL) is an object query language. It let's you express queries for single objects or full object graphs, using the terminology of your domain model: class names, field names, relations between classes, etc. This is a powerful tool for retrieving or even manipulating objects without breaking the separation of the domain model (field names, class names, etc) from the relational model (table names, column names, etc). DQL looks very much like SQL and this is intended because it makes it relatively easy to grasp for people knowing SQL. There are, however, a few very important differences you should always keep in mind:

Take this example DQL query:


FROM User u
LEFT JOIN u.Phonenumbers where u.level > 1

The things to notice about this query:

  • We select from classes and not tables. We are selecting from the User class/model.
  • We join along associations (u.Phonenumbers)
  • We can reference fields (u.level)
  • There is no join condition (ON x.y = y.x). The associations between your classes and how these are expressed in the database are known to Doctrine (You need to make this mapping known to Doctrine, of course. How to do that is explained later in the Defining Models chapter.).

DQL expresses a query in the terms of your domain model (your classes, the attributes they have, the relations they have to other classes, etc.).

It's very important that we speak about classes, fields and associations between classes here. User is not a table / table name . It may be that the name of the database table that the User class is mapped to is indeed named User but you should nevertheless adhere to this differentiation of terminology. This may sound nit picky since, due to the ActiveRecord approach, your relational model is often very similar to your domain model but it's really important. The column names are rarely the same as the field names and as soon as inheritance is involved, the relational model starts to diverge from the domain model. You can have a class User that is in fact mapped to several tables in the database. At this point it should be clear that talking about "selecting from the User table" is simply wrong then. And as Doctrine development continues there will be more features available that allow the two models to diverge even more.

Further Reading

For people new to object-relational mapping and (object-oriented) domain models we recommend the following literature:

The books by Martin Fowler cover a lot of the basic ORM terminology, the different approaches of modeling business logic and the patterns involved.

Another good read is about Domain Driven Design. Though serious Domain-Driven Design is currently not possible with Doctrine, this is an excellent resource for good domain modeling, especially in complex business domains, and the terminology around domain models that is pretty widespread nowadays is explained in depth (Entities, Value Objects, Repositories, etc).

Conclusion

Well, now that we have given a little educational reading about the methodologies and principals behind Doctrine we are pretty much ready to dive in to everything that is Doctrine. Lets dive in to setting up Doctrine in the Getting Started chapter.

Getting Started

Checking Requirements

First we need to make sure that you can run Doctrine on your server. We can do this one of two ways:

First create a small PHP script named phpinfo.php and upload it somewhere on your web server that is accessible to the web:

phpinfo();

Now execute it from your browser by going to http://localhost/phpinfo.php. You will see a list of information detailing your PHP configuration. Check that your PHP version is >= 5.2.3 and that you have PDO and the desired drivers installed.

You can also check your PHP installation has the necessary requirements by running some commands from the terminal. We will demonstrate in the next example.

Check that your PHP version is >= 5.2.3 with the following command:

$ php -v

Now check that you have PDO and the desired drivers installed with the following command:

$ php -i

You could also execute the phpinfo.php from the command line and get the same result as the above example:

$ php phpinfo.php

Checking the requirements are required in order to run the examples used throughout this documentation.

Installing

Currently it is possible to install Doctrine four different ways that are listed below:

  • SVN (subversion)
  • SVN externals
  • PEAR Installer
  • Download PEAR Package

It is recommended to download Doctrine via SVN (subversion), because in this case updating is easy. If your project is already under version control with SVN, you should choose SVN externals.

If you wish to just try out Doctrine in under 5 minutes, the sandbox package is recommended. We will discuss the sandbox package in the next section.

Sandbox

Doctrine also provides a special package which is a zero configuration Doctrine implementation for you to test Doctrine without writing one line of code. You can download it from the download page.

The sandbox implementation is not a recommend implementation for a production application. It's only purpose is for exploring Doctrine and running small tests.

SVN

It is highly recommended that you use Doctrine via SVN and the externals option. This option is the best as you will receive the latest bug fixes from SVN to ensure the best experience using Doctrine.

Installing

To install Doctrine via SVN is very easy. You can download any version of Doctrine from the SVN server: http://svn.doctrine-project.org

To check out a specific version you can use the following command from your terminal:

svn co http://svn.doctrine-project.org/branches/1.0 .

If you do not have a SVN client, chose one from the list below. Find the Checkout option and enter http://svn.doctrine-project.org/1.0 in the path or repository url parameter. There is no need for a username or password to check out Doctrine.

Updating

Updating Doctrine with SVN is just as easy as installing. Simply execute the following command from your terminal:

$ svn update

SVN Externals

If your project is already under version control with SVN, then it is recommended that you use SVN externals to install Doctrine.

You can start by navigating to your checked out project in your terminal:

$ cd /var/www/my_project

Now that you are under your checked out project, you can execute the following command from your terminal and setup Doctrine as an SVN external:

$ svn propedit svn:externals lib/vendor

The above command will open your editor and you need to place the following text inside and save:

doctrine http://svn.doctrine-project.org/branches/1.0/lib

Now you can install Doctrine by doing an svn update:

$ svn update

It will download and install Doctrine at the following path: /var/www/my_project/lib/vendor/doctrine

Don't forget to commit your change to the SVN externals.

$ svn commit

PEAR Installer

Doctrine also provides a PEAR server for installing and updating Doctrine on your servers. You can easily install Doctrine with the following command:

$ pear install pear.phpdoctrine.org/Doctrine-1.0.x

Replace the above 1.0.x with the version you wish to install. For example "1.0.6".

Download Pear Package

If you do not wish to install via PEAR or do not have PEAR installed, you can always just manually download the package from the website. Once you download the package to your server you can extract it using the following command under linux.

$ tar xzf Doctrine-1.0.6.tgz

Implementing

Now that you have Doctrine in your hands, we are ready to implement Doctrine in to our application. This is the first step towards getting started with Doctrine.

First create a directory named doctrine_test. This is where we will place all our test code:

$ mkdir doctrine_test
$ cd doctrine_test

Including Doctrine Libraries

The first thing we must do is find the Doctrine.php file containing the core class so that we can require it in to our application. The Doctrine.php file is in the lib folder from when you downloaded Doctrine in the previous section.

We need to move the Doctrine libraries in to the doctrine_test directory into a folder in doctrine_test/lib/vendor/doctrine:

$ mkdir lib
$ mkdir lib/vendor
$ mkdir lib/vendor/doctrine
$ mv /path/to/doctrine/lib doctrine

Or if you are using SVN, you can use externals:

$ svn co http://svn.doctrine-project.org/branches/1.0/lib lib/vendor/doctrine

Now add it to your svn externals:

$ svn propedit svn:externals lib/vendor

It will open up your editor and place the following inside and save:

doctrine http://svn.doctrine-project.org/branches/1.0/lib

Now when you do SVN update you will get the Doctrine libraries updated:

$ svn update lib/vendor

Require Doctrine Base Class

We need to create a php script for bootstrapping Doctrine and all the configuration for it. Create a file named bootstrap.php and place the following code in the file:

// bootstrap.php

/**
 * Bootstrap Doctrine.php, register autoloader specify
 * configuration attributes and load models.
 */

require_once(dirname(__FILE__) . '/lib/vendor/doctrine/Doctrine.php');

Register Autoloader

Now that we have the Doctrine class present, we need to register the class autoloader function in the bootstrap file:

// bootstrap.php

// ...
spl_autoload_register(array('Doctrine', 'autoload'));

Lets also create the singleton Doctrine_Manager instance and assign it to a variable named $manager:

// bootstrap.php

// ...
$manager = Doctrine_Manager::getInstance();

Autoloading Explained

You can read about the PHP autoloading on the php website. Using the autoloader allows us to lazily load classes as they are requested instead of pre-loading all classes. This is a huge benefit to performance.

The way the Doctrine autoloader works is simple. Because our class names and paths are related, we can determine the path to a Doctrine class based on its name.

Imagine we have a class named Doctrine_Some_Class and we instantiate an instance of it:

$class = new Doctrine_Some_Class();

The above code will trigger a call to the Doctrine::autoload() function and pass it the name of the class instantiated. The class name string is manipulated and transformed in to a path and required. Below is some pseudo code that shows how the class is found and required:

class Doctrine
{
    public function autoload($className)
    {
        $classPath = str_replace('_', '/', $className) . '.php';
        $path = '/path/to/doctrine/' . $classPath;
        require_once($path);
        return true;
    }
}

In the above example the Doctrine_Some_Class can be found at /path/to/doctrine/Doctrine/Some/Class.php.

Obviously the real Doctrine::autoload() function is a bit more complex and has some error checking to ensure the file exists but the above code demonstrates how it works.

Bootstrap File

We will use this bootstrap class in later chapters and sections so be sure to create it!

The bootstrap file we have created should now look like the following:

// bootstrap.php

/**
 * Bootstrap Doctrine.php, register autoloader specify
 * configuration attributes and load models.
 */

require_once(dirname(__FILE__) . '/lib/vendor/doctrine/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();

This new bootstrapping file will be referenced several times in this book as it is where we will make changes to our implementation as we learn how to use Doctrine step by step.

The configuration attributes mentioned above are a feature in Doctrine used for configuring and controlling functionality. You will learn more about attributes and how to get/set them in the Configuration chapter.

Test Script

Now lets create a simple test script that we can use to run various tests as we learn about the features of Doctrine.

Create a new file in the doctrine_test directory named test.php and place the following code inside:

// test.php

require_once('bootstrap.php');

echo Doctrine::getPath();

Now you can execute the test script from your command line. This is how we will perform tests with Doctrine throughout the chapters so make sure it is working for you! It should output the path to your Doctrine installation.

$ php test.php
/path/to/doctrine/lib

Conclusion

Phew! This was our first chapter where we actually got into some code. As you saw, first we were able to check that our server can actually run Doctrine. Then we learned all the different ways we can download and install Doctrine. Lastly we learned how to implement Doctrine by setting up a small test environment that we will use to perform some exercises in the remaining chapters of the book.

Now lets move on and get our first taste of Doctrine connections in the Introduction to Connections chapter.

Introduction to Connections

DSN, the Data Source Name

In order to connect to a database through Doctrine, you have to create a valid DSN (Data Source Name).

Doctrine supports both PEAR DB/MDB2 like data source names as well as PDO style data source names. The following section deals with PEAR like data source names. If you need more info about the PDO-style data source names see the documentation on PDO.

The DSN consists in the following parts:

DSN part Description
phptype Database backend used in PHP (i.e. mysql , pgsql etc.)
dbsyntax Database used with regards to SQL syntax etc.
protocol Communication protocol to use ( i.e. tcp, unix etc.)
hostspec Host specification (hostname[:port])
database Database to use on the DBMS server
username User name for login
password Password for login
proto_opts Maybe used with protocol
option Additional connection options in URI query string format. Options are separated by ampersand (&). The Following table shows a non complete list of options:

List of options

Name Description
charset Some backends support setting the client charset.
new_link Some RDBMS do not create new connections when connecting to the same host multiple times. This option will attempt to force a new connection.

The DSN can either be provided as an associative array or as a string. The string format of the supplied DSN is in its fullest form:

phptype(dbsyntax)://username:password@protocol+hostspec/database?option=value

Most variations are allowed:

phptype://username:password@protocol+hostspec:110//usr/db_file.db
phptype://username:password@hostspec/database
phptype://username:password@hostspec
phptype://username@hostspec
phptype://hostspec/database
phptype://hostspec
phptype:///database
phptype:///database?option=value&anotheroption=anothervalue
phptype(dbsyntax)
phptype

The currently supported PDO database drivers are:

Driver name Supported databases
fbsql FrontBase
ibase InterBase / Firebird (requires PHP 5)
mssql Microsoft SQL Server (NOT for Sybase. Compile PHP --with-mssql)
mysql MySQL
mysqli MySQL (supports new authentication protocol) (requires PHP 5)
oci Oracle 7/8/9/10
pgsql PostgreSQL
querysim QuerySim
sqlite SQLite 2

A second DSN format supported is

phptype(syntax)://user:pass@protocol(proto_opts)/database

If your database, option values, username or password contain characters used to delineate DSN parts, you can escape them via URI hex encodings:

Character Hex Code
: %3a
/ %2f
@ %40
+ %2b
( %28
) %29
? %3f
= %3d
& %26

Please note, that some features may be not supported by all database drivers.

Examples

Example 1. Connect to database through a socket

mysql://user@unix(/path/to/socket)/pear

Example 2. Connect to database on a non standard port

pgsql://user:pass@tcp(localhost:5555)/pear

If you use, the IP address 127.0.0.1, the port parameter is ignored (default: 3306).

Example 3. Connect to SQLite on a Unix machine using options

sqlite:////full/unix/path/to/file.db?mode=0666

Example 4. Connect to SQLite on a Windows machine using options

sqlite:///c:/full/windows/path/to/file.db?mode=0666

Example 5. Connect to MySQLi using SSL

mysqli://user:pass@localhost/pear?key=client-key.pem&cert=client-cert.pem

Opening New Connections

Opening a new database connection in Doctrine is very easy. If you wish to use PDO you can just initialize a new PDO object.

Remember our bootstrap.php file we created in the Getting Started chapter? Under the code where we registered the Doctrine autoloader we are going to instantiate our new connection:

// bootstrap.php

// ...
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';

$dbh = new PDO($dsn, $user, $password);
$conn = Doctrine_Manager::connection($dbh);

Directly passing a PDO instance to Doctrine_Manager::connection() will not allow Doctrine to be aware of the username and password for the connection, since their is no way to retrieve it from an existing PDO instance. The username and password is required in order for Doctrine to be able to create and drop databases. To get around this you can manually set the username and password option directly on the $conn object.

// bootstrap.php

// ...
$conn->setOption('username', $user);
$conn->setOption('password', $password);

Lazy Database Connecting

Lazy-connecting to database can save a lot of resources. There might be many times where you don't need an actual database connection, hence its always recommended to use lazy-connecting (that means Doctrine will only connect to database when needed).

This feature can be very useful when using for example page caching, hence not actually needing a database connection on every request. Remember connecting to database is an expensive operation.

In the example below we will show you when you create a new Doctrine connection, the connection to the database isn't created until it is actually needed.

// bootstrap.php

// ...

// At this point no actual connection to the database is created
$conn = Doctrine_Manager::connection('mysql://username:password@localhost/test');

// The first time the connection is needed, it is instantiated
// This query triggers the connection to be created
$conn->execute('SHOW TABLES');

Testing your Connection

After reading the previous sections of this chapter, you should now know how to create a connection. So, lets modify our bootstrap file to include the initialization of a connection. For this example we will just be using a sqlite memory database but you can use whatever type of database connection you prefer.

Add your database connection to bootstrap.php and it should look something like the following:

/**
 * Bootstrap Doctrine.php, register autoloader and specify
 * configuration attributes
 */

require_once('../doctrine/branches/1.0/lib/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();

$conn = Doctrine_Manager::connection('sqlite::memory:', 'doctrine');

To test the connection lets modify our test.php script and perform a small test. Since we create a variable name $conn, that variable is available to the test script so lets setup a small test to make sure our connection is working:

First lets create a test table and insert a record:

// test.php

// ...
$conn->export->createTable('test', array('name' => array('type' => 'string')));
$conn->execute('INSERT INTO test (name) VALUES (?)', array('jwage'));

Now lets execute a simple SELECT query from the test table we just created to make sure the data was inserted and that we can retrieve it:

// test.php

// ...
$stmt = $conn->prepare('SELECT * FROM test');
$stmt->execute();
$results = $stmt->fetchAll();
print_r($results);

Execute test.php from your terminal and you should see:

$ php test.php
Array
(
    [0] => Array
        (
            [name] => jwage
            [0] => jwage
        )

)

Conclusion

Great! Now we learned some basic operations of Doctrine connections. We have modified our Doctrine test environment to have a new connection. This is required because the examples in the coming chapters will require a connection.

Lets move on to the Configuration chapter and learn how you can control functionality and configurations using the Doctrine attribute system.

Configuration

Doctrine controls configuration of features and functionality using attributes. In this section we will discuss how to set and get attributes as well as an overview of what attributes exist for you to use to control Doctrine functionality.

Levels of Configuration

Doctrine has a three-level configuration structure. You can set configuration attributes at a global, connection and table level. If the same attribute is set on both lower level and upper level, the uppermost attribute will always be used. So for example if a user first sets default fetchmode in global level to Doctrine::FETCH_BATCH and then sets a table fetchmode to Doctrine::FETCH_LAZY, the lazy fetching strategy will be used whenever the records of that table are being fetched.

  • Global level - The attributes set in global level will affect every connection and every table in each connection.
  • Connection level - The attributes set in connection level will take effect on each table in that connection.
  • Table level - The attributes set in table level will take effect only on that table.

In the following example we set an attribute at the global level:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);

In the next example above we override the global attribute on given connection:

// bootstrap.php

// ...
$conn->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_NONE);

In the last example we override once again the connection level attribute in the table level:

// bootstrap.php

// ...
$table = Doctrine::getTable('User');

$table->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);

We haven't introduced the above used Doctrine::getTable() method. You will learn more about the table objects used in Doctrine in the Table section of the next chapter.

Portability

Each database management system (DBMS) has it's own behaviors. For example, some databases capitalize field names in their output, some lowercase them, while others leave them alone. These quirks make it difficult to port your applications over to another database type. Doctrine strives to overcome these differences so your applications can switch between DBMS's without any changes. For example switching from sqlite to mysql.

The portability modes are bitwised, so they can be combined using | and removed using ^. See the examples section below on how to do this.

You can read more about the bitwise operators on the PHP website.

Portability Mode Attributes

Below is a list of all the available portability attributes and the description of what each one does:

Name Description
PORTABILITY_ALL Turn on all portability features. This is the default setting.
PORTABILITY_DELETE_COUNT Force reporting the number of rows deleted. Some DBMS's don't count the number of rows deleted when performingsimple DELETE FROM tablename queries. This mode tricks such DBMS's into telling the count by adding WHERE 1=1 to the end of DELETE queries.
PORTABILITY_EMPTY_TO_NULL Convert empty strings values to null in data in and output. Needed because Oracle considers empty strings to be null, while most other DBMS's know the difference between empty and null.
PORTABILITY_ERRORS Makes certain error messages in certain drivers compatible with those from other DBMS's
PORTABILITY_FIX_ASSOC_FIELD_NAMES This removes any qualifiers from keys in associative fetches. Some RDBMS, like for example SQLite, will by default use the fully qualified name for a column in assoc fetches if it is qualified in a query.
PORTABILITY_FIX_CASE Convert names of tables and fields to lower or upper case in all methods. The case depends on the field_case option that may be set to either CASE_LOWER (default) or CASE_UPPER
PORTABILITY_NONE Turn off all portability features.
PORTABILITY_NUMROWS Enable hack that makes numRows() work in Oracle.
PORTABILITY_EXPR Makes DQL API throw exceptions when non-portable expressions are being used.
PORTABILITY_RTRIM Right trim the data output for all data fetches. This does not applied in drivers for RDBMS that automatically right trim values of fixed length character values, even if they do not right trim value of variable length character values.

Examples

Now we can use the setAttribute() method to enable portability for lowercasing and trimming with the following code:

// bootstrap.php

// ...
$conn->setAttribute('portability',
        Doctrine::PORTABILITY_FIX_CASE | Doctrine::PORTABILITY_RTRIM);

Enable all portability options except trimming

// bootstrap.php

// ...
$conn->setAttribute('portability',
        Doctrine::PORTABILITY_ALL ^ Doctrine::PORTABILITY_RTRIM);

Identifier quoting

You can quote the db identifiers (table and field names) with quoteIdentifier(). The delimiting style depends on which database driver is being used.

Just because you CAN use delimited identifiers, it doesn't mean you SHOULD use them. In general, they end up causing way more problems than they solve. Anyway, it may be necessary when you have a reserved word as a field name (in this case, we suggest you to change it, if you can).

Some of the internal Doctrine methods generate queries. Enabling the quote_identifier attribute of Doctrine you can tell Doctrine to quote the identifiers in these generated queries. For all user supplied queries this option is irrelevant.

Portability is broken by using the following characters inside delimited identifiers:

Name Character Driver
backtick ` MySQL
double quote " Oracle
brackets [ or ] Access

Delimited identifiers are known to generally work correctly under the following drivers: Mssql, Mysql, Oracle, Pgsql, Sqlite and Firebird.

When using the Doctrine::ATTR_QUOTE_IDENTIFIER option, all of the field identifiers will be automatically quoted in the resulting SQL statements:

// bootstrap.php

// ...
$conn->setAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER, true);

Will result in a SQL statement that all the field names are quoted with the backtick '`' operator (in MySQL).

SELECT 
*
FROM sometable
WHERE `id` = '123'

As opposed to:

SELECT 
*
FROM sometable
WHERE id = '123'

Exporting

The export attribute is used for telling Doctrine what it should export when exporting classes to your database for creating your tables.

If you don't want to export anything when exporting you can use:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_NONE);

For exporting tables only (but not constraints) you can use on of the following:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_TABLES);

You can also use the following syntax as it is the same as the above:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_EXPORT,
  Doctrine::EXPORT_ALL ^ Doctrine::EXPORT_CONSTRAINTS);

For exporting everything (tables and constraints) you can use:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_ALL);

Naming convention attributes

Naming convention attributes affect the naming of different database related elements such as tables, indexes and sequences. Basically every naming convention attribute has affect in both ways. When importing schemas from the database to classes and when exporting classes into database tables.

So for example by default Doctrine naming convention for indexes is %s_idx. Not only do the indexes you set get a special suffix, also the imported classes get their indexes mapped to their non-suffixed equivalents. This applies to all naming convention attributes.

Index name format

Doctrine::ATTR_IDXNAME_FORMAT can be used for changing the naming convention of indexes. By default Doctrine uses the format [name]_idx. So defining an index called 'ageindex' will actually be converted into 'ageindex_idx'.

You can change the index naming convention with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_IDXNAME_FORMAT, '%s_index');

Sequence name format

Similar to Doctrine::ATTR_IDXNAME_FORMAT, Doctrine::ATTR_SEQNAME_FORMAT can be used for changing the naming convention of sequences. By default Doctrine uses the format [name]_seq, hence creating a new sequence with the name of mysequence will lead into creation of sequence called mysequence_seq.

You can change the sequence naming convention with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_SEQNAME_FORMAT, '%s_sequence');

Table name format

The table name format can be changed the same as the index and sequence name format with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_TBLNAME_FORMAT, '%s_table');

Database name format

The database name format can be changed the same as the index, sequence and table name format with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_DBNAME_FORMAT, 'myframework_%s');

Validation attributes

Doctrine provides complete control over what it validates. The validation procedure can be controlled with Doctrine::ATTR_VALIDATE.

The validation modes are bitwised, so they can be combined using | and removed using ^. See the examples section below on how to do this.

Validation mode constants

Name Description
VALIDATE_NONE Turns off the whole validation procedure.
VALIDATE_LENGTHS Makes Doctrine validate all field lengths.
VALIDATE_TYPES Makes Doctrine validate all field types. Doctrine does loose type validation. This means that for example string with value '13.3' will not pass as an integer but '13' will.
VALIDATE_CONSTRAINTS Makes Doctrine validate all field constraints such as notnull, email etc.
VALIDATE_ALL Turns on all validations.

Validation by default is turned off so if you wish for your data to be validated you will need to enable it. Some examples of how to change this configuration are provided below.

Examples

You can turn on all validations by using the Doctrine::VALIDATE_ALL attribute with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);

You can also configure Doctrine to validate lengths and types, but not constraints with the following code:

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_VALIDATE,
  Doctrine::VALIDATE_LENGTHS | Doctrine::VALIDATE_TYPES);

Optional String Syntax

You can optionally specify attribute names and values as strings. Below is an example. This is allowed as a convenience to shorten the syntax and make it easier to type.

// bootstrap.php

// ...
$conn->setAttribute('validate', 'none');

Internally when strings are used they are converted to the constants and used.

Conclusion

Now we have gone over some of the most common attributes used to configure Doctrine. Some of these attributes may not apply to you ever or you may not understand what you could use them for now. As you read the next chapters you will see which attributes you do and don't need to use and things will begin to make more sense.

If you saw some attributes you wanted to change the value above, then you should have added it to your bootstrap.php file and it should look something like the following now:

/**
 * Bootstrap Doctrine.php, register autoloader and specify
 * configuration attributes
 */

require_once('../doctrine/branches/1.0/lib/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
$manager = Doctrine_Manager::getInstance();

$conn = Doctrine_Manager::connection('sqlite::memory:', 'doctrine');

$manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);
$manager->setAttribute(Doctrine::ATTR_EXPORT, Doctrine::EXPORT_ALL);
$manager->setAttribute(Doctrine::ATTR_MODEL_LOADING, Doctrine::MODEL_LOADING_CONSERVATIVE);

Now we are ready to move on to the next chapter where we will learn everything their is to know about Doctrine Connections.

Connections

Introduction

From the start Doctrine has been designed to work with multiple connections. Unless separately specified Doctrine always uses the current connection for executing the queries.

In this chapter we will demonstrate how to create and work with Doctrine connections.

Opening Connections

Doctrine_Manager provides the static method Doctrine_Manager::connection() which opens new connections.

In this example we will show you to open a new connection:

// test.php

// ...
$conn = Doctrine_Manager::connection('mysql://username:password@localhost/test', 'connection 1');

Retrieve Connections

If you use the Doctrine_Manager::connection() method and don't pass any arguments it will return the current connection:

// test.php

// ...
$conn2 = Doctrine_Manager::connection();

if ($conn === $conn2) {
    echo 'Doctrine_Manager::connection() returns the current connection';
}

Current Connection

The current connection is the last opened connection. In the next example we will show how you can get the current connection from the Doctrine_Manager instance:

// test.php

// ...
$conn2 = Doctrine_Manager::connection('mysql://username2:password2@localhost/test2', 'connection 2');

if ($conn2 === $manager->getCurrentConnection()) {
    echo 'Current connection is the connection we just created!';
}

Change Current Connection

You can change the current connection by calling Doctrine_Manager::setCurrentConnection().

// test.php

// ...
$manager->setCurrentConnection('connection 1');

echo $manager->getCurrentConnection()->getName(); // connection 1

Iterating Connections

You can iterate over the opened connections by simply passing the manager object to a foreach clause. This is possible since Doctrine_Manager implements special IteratorAggregate interface.

The IteratorAggregate is a special PHP interface for implementing iterators in to your objects.

// test.php

// ...
foreach($manager as $conn) {
    echo $conn->getName() . "\n";
}

Get Connection Name

You can easily get the name of a Doctrine_Connection instance with the following code:

// test.php

// ...
$conn = Doctrine_Manager::connection();

$name = $manager->getConnectionName($conn);

echo $name; // connection 1

Close Connection

You can easily close a connection and remove it from the Doctrine connection registry with the following code:

// test.php

// ...
$conn = Doctrine_Manager::connection();

$manager->closeConnection($conn);

If you wish to close the connection but not remove it from the Doctrine connection registry you can use the following code instead:

// test.php

// ...
$conn = Doctrine_Manager::connection();
$conn->close();

Get All Connections

You can retrieve an array of all the registered connections by using the Doctrine_Manager::getConnections() method like below:

// test.php

// ...
$conns = $manager->getConnections();
foreach ($conns as $conn) {
    echo $conn->getName() . "\n";
}

The above is essentially the same as iterating over the Doctrine_Manager object like we did earlier. Here it is again:

// test.php

// ...
foreach ($manager as $conn) {
    echo $conn->getName() . "\n";
}

Count Connections

You can easily get the number of connections from a Doctrine_Manager object since it implements the Countable interface.

// test.php

// ...
$num = count($manager);

echo $num;

The above is the same as doing:

// test.php

// ...
$num = $manager->count();

Creating and Dropping Database

When you create connections using Doctrine, you gain the ability to easily create and drop the databases related to those connections.

This is as simple as using some functions provided in the Doctrine_Manager or Doctrine_Connection classes.

The following code will iterate over all instantiated connections and call the dropDatabases()/createDatabases() function on each one:

// test.php

// ...
$manager->createDatabases();

$manager->dropDatabases();

Drop/create database for specific connection

You can easily drop or create the database for a specific Doctrine_Connection instance by calling the dropDatabase()/createDatabase() function on the connection instance with the following code:

// test.php

// ...
$conn->createDatabase();

$conn->dropDatabase();

Conclusion

Now that we have learned all about Doctrine connections we should be ready to dive right in to models in the Introduction to Models chapter. We will learn a little bit about Doctrine models first. Then we will start to have some fun and create our first test models and see what kind of magic Doctrine can provide for you.

Introduction to Models

Introduction

At the lowest level, Doctrine represents your database schema with a set of PHP classes. These classes define the schema and behavior of your model.

A basic model that represents a user in a web application might look something like this.

class User extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('username', 'string', 255);
        $this->hasColumn('password', 'string', 255);
    }

    public function setUp()
    {
        $this->actAs('Timestampable');
    }
}

We aren't actually going to use the above class definition, it is only meant to be an example. We will generate our first class definition from an existing database table later in this chapter.

Each Doctrine_Record child class can have a setTableDefinition() and setUp() method. The setTableDefinition() method is for defining columns, indexes and other information about the schema of tables. The setUp() method is for attaching behaviors and defining relationships between Doctrine_Record child classes. In the above example we are enabling the Timestampable behavior which adds some automagic functionality. You will learn more about what all can be used in these functions in the Defining Models chapter.

Generating Models

Doctrine offers ways to generate these classes to make it easier to get started using Doctrine.

Generating from existing databases is only meant to be a convenience for getting started. After you generate from the database you will have to tweak it and clean things up as needed.

Existing Databases

A common case when looking for ORM tools like Doctrine is that the database and the code that access it is growing large/complex. A more substantial tool is needed than manual SQL code.

Doctrine has support for generating Doctrine_Record classes from your existing database. There is no need for you to manually write all the Doctrine_Record classes for your domain model.

Making the first import

Let's consider we have a mysql database called doctrine_test with a single table named user. The user table has been created with the following sql statement:

CREATE TABLE user (
   id bigint(20) NOT NULL auto_increment,
   first_name varchar(255) default NULL,
   last_name varchar(255) default NULL,
   username varchar(255) default NULL,
   password varchar(255) default NULL,
   type varchar(255) default NULL,
   is_active tinyint(1) default '1',
   is_super_admin tinyint(1) default '0',
   created_at TIMESTAMP,
   updated_at TIMESTAMP,
   PRIMARY KEY  (id)
) ENGINE=InnoDB

Now we would like to convert it into Doctrine_Record class. With Doctrine this is easy! Remember our test script we created in the Getting Started chapter? We're going to use that generate our models.

First we need to modify our bootstrap.php to use the MySQL database instead of sqlite memory:

// bootstrap.php

// ...
$conn = Doctrine_Manager::connection('mysql://root:mys3cr3et@localhost/doctrine_test', 'doctrine');
// ...

You can use the $conn->createDatabase() method to create the database if it does not already exist and the connected user has permission to create databases. Then use the above provided CREATE TABLE statement to create the table.

Now we need a place to store our generated classes so lets create a directory named models in the doctrine_test directory:

$ mkdir doctrine_test/models

Now we just need to add the code to our test.php script to generate the model classes:

// test.php

// ...
Doctrine::generateModelsFromDb('models', array('doctrine'), array('generateTableClasses' => true));

The generateModelsFromDb method only requires one parameter and it is the import directory (the directory where the generated record files will be written to). The second argument is an array of database connection names to generate models for, and the third is the array of options to use for the model building.

That's it! Now there should be a file called BaseUser.php in your doctrine_test/models/generated directory. The file should look like the following:

// models/generated/BaseUser.php

/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
abstract class BaseUser extends Doctrine_Record
{
  public function setTableDefinition()
  {
    $this->setTableName('user');
    $this->hasColumn('id', 'integer', 8, array('type' => 'integer', 'length' => 8, 'primary' => true, 'autoincrement' => true));
    $this->hasColumn('first_name', 'string', 255, array('type' => 'string', 'length' => 255));
    $this->hasColumn('last_name', 'string', 255, array('type' => 'string', 'length' => 255));
    $this->hasColumn('username', 'string', 255, array('type' => 'string', 'length' => 255));
    $this->hasColumn('password', 'string', 255, array('type' => 'string', 'length' => 255));
    $this->hasColumn('type', 'string', 255, array('type' => 'string', 'length' => 255));
    $this->hasColumn('is_active', 'integer', 1, array('type' => 'integer', 'length' => 1, 'default' => '1'));
    $this->hasColumn('is_super_admin', 'integer', 1, array('type' => 'integer', 'length' => 1, 'default' => '0'));
    $this->hasColumn('created_at', 'timestamp', null, array('type' => 'timestamp', 'notnull' => true));
    $this->hasColumn('updated_at', 'timestamp', null, array('type' => 'timestamp', 'notnull' => true));
  }
}

You should also have a file called User.php in your doctrine_test/models directory. The file should look like the following:

// models/User.php

/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class User extends BaseUser
{

}

Doctrine will automatically generate a skeleton Doctrine_Table class for the model at doctrine_test/models/UserTable.php because we passed the option generateTableClasses with a value of true. The file should look like the following:

// models/UserTable.php

/**
 * This class has been auto-generated by the Doctrine ORM Framework
 */
class UserTable extends Doctrine_Table
{

}

You can place custom functions inside the User and UserTable classes to customize the functionality of your models. Below are some examples:

// models/User.php

// ...
class User extends BaseUser
{
    public function setPassword($password)
    {
        return $this->_set('password', md5($password));
    }
}

In order for the above password accessor overriding to work properly you must enabled the auto_accessor_override attribute in your bootstrap.php file like done below.

// bootstrap.php

// ...
$manager->setAttribute(Doctrine::ATTR_AUTO_ACCESSOR_OVERRIDE, true);

Now when you try and set a users password it will be md5 encrypted. First we need to modify our bootstrap.php file to include some code for autoloading our models from the models directory:

// bootstrap.php

// ...
Doctrine::loadModels('models');

The model loading is fully explained later in the Autoloading Models section of this chapter.

Now we can modify test.php to include some code which will test the changes we made to the File model:

// test.php

// ...

$user = new User();
$user->username = 'jwage';
$user->password = 'changeme';

echo $user->password; // outputs md5 hash and not changeme

Now when you execute test.php from your terminal you should see the following:

$ php test.php
4cb9c8a8048fd02294477fcb1a41191a

Here is an example of some custom functions you might add to the UserTable class:

// models/UserTable.php

// ...
class UserTable extends Doctrine_Table
{
    public function getCreatedToday()
    {
        $today = da