536 lines
19 KiB
XML
536 lines
19 KiB
XML
<?xml version="1.0" encoding='ISO-8859-1'?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
|
|
|
|
[
|
|
<!ENTITY version "2.0">
|
|
]>
|
|
|
|
<book id="doctrinebook">
|
|
|
|
<bookinfo>
|
|
<title>Doctrine Documentation</title>
|
|
<author>
|
|
<firstname>Konsta</firstname>
|
|
<surname>Vesterinen</surname>
|
|
<authorblurb>The creator and lead developer.</authorblurb>
|
|
</author>
|
|
<author>
|
|
<firstname>Ian</firstname>
|
|
<othername>P.</othername>
|
|
<surname>Christian</surname>
|
|
<email>pookey@pookey.co.uk</email>
|
|
<authorblurb>Junior developer and documentation maintainer.</authorblurb>
|
|
</author>
|
|
<copyright>
|
|
<holder>Doctrine Project</holder>
|
|
<year>2007</year>
|
|
</copyright>
|
|
<legalnotice id="legalnotice">
|
|
<para>
|
|
The contents of this document are licensed under the Creative Commons
|
|
<ulink url="http://creativecommons.org/licenses/by-sa/2.0/">Attribution-ShareAlike License</ulink>.
|
|
</para>
|
|
</legalnotice>
|
|
|
|
<abstract>
|
|
<para>
|
|
Documentation for the PHP Doctrine project.
|
|
</para>
|
|
<para>
|
|
This document was generated <?dbtimestamp format="Y-m-d H:M:S"?>.
|
|
</para>
|
|
</abstract>
|
|
</bookinfo>
|
|
|
|
<chapter id="introduction">
|
|
<title>Introduction</title>
|
|
<sect1 id="about-doctrine">
|
|
<title>About Doctrine</title>
|
|
<para>
|
|
Doctrine is a Object Relational Mapping and database abstraction
|
|
framework for PHP. The DBAL part of Doctrine derives from MDB2. The key
|
|
idea is to provide very intuitive and easy-to-use persistency solution
|
|
(eg. RoR ActiveRecord) with all the advanced features from the more
|
|
heavy-weight solutions (eg. Hibernate).
|
|
</para>
|
|
<para>
|
|
Doctrine Query Language implements EJB 3 OQL specificiation and expands
|
|
it a bit further (it has special LIMIT and OFFSET clauses).
|
|
</para>
|
|
<sect2 id="intro-example">
|
|
<title>Example</title>
|
|
<para>
|
|
You might not understand exactly what's happening at this stage, but
|
|
this example is to give you a general idea of the power of Doctrine.
|
|
</para>
|
|
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
|
|
// include the doctrine library
|
|
require_once('lib/Doctrine.php');
|
|
|
|
// register the doctrine autoload function
|
|
spl_autoload_register(array('Doctrine', 'autoload'));
|
|
|
|
// define the user class
|
|
class User extends Doctrine_Record {
|
|
public function setTableDefinition() {
|
|
// set 'user' table columns, note that
|
|
// id column is always auto-created
|
|
|
|
$this->hasColumn('name','string',30);
|
|
$this->hasColumn('username','string',20);
|
|
$this->hasColumn('password','string',16);
|
|
$this->hasColumn('created','integer',11);
|
|
}
|
|
}
|
|
|
|
// create a new user
|
|
$user = new User();
|
|
$user->username = "pookey";
|
|
$user->password = "a password!";
|
|
$user->created = time();
|
|
|
|
// save the user
|
|
$user->save();
|
|
|
|
// lets find the user....
|
|
$query = new Doctrine_Query();
|
|
$query->query('SELECT u.* FROM User u WHERE u.username = ?');
|
|
$users = $query->execute(array('pookey'));
|
|
if (count($users))
|
|
{
|
|
// we found our user!
|
|
}
|
|
else
|
|
{
|
|
// we didn't find our user, oh no!
|
|
}
|
|
?>]]></programlisting>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="features">
|
|
<title>Features</title>
|
|
<para>
|
|
General Features
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>Fully object-oriented following best practices and design patterns</listitem>
|
|
<listitem>Multiple databases</listitem>
|
|
<listitem>Database connection pooling with connection-record -registry</listitem>
|
|
<listitem>Runtime configuration (no XML needed!)</listitem>
|
|
<listitem>Very modular structure (only uses the needed features)</listitem>
|
|
<listitem>The runtime components can be compiled into a single fileM</listitem>
|
|
<listitem>Leveled configuration (attributes can be set at global, connection and table levels)</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
Database Abstraction
|
|
</para>
|
|
<itemizedlist>
|
|
<listitem>A DSN (data source name) or array format for specifying database servers</listitem>
|
|
<listitem>Datatype abstraction and on demand datatype conversion</listitem>
|
|
<listitem>supports PDO</listitem>
|
|
<listitem>Database query profiling</listitem>
|
|
<listitem>Query caching</listitem>
|
|
<listitem>Sequence / autoincrement emulation</listitem>
|
|
<listitem>Replace emulation</listitem>
|
|
<listitem>RDBMS management methods (creating, dropping, altering)</listitem>
|
|
<listitem>SQL function call abstraction</listitem>
|
|
<listitem>SQL expression abstraction</listitem>
|
|
<listitem>Pattern matching abstraction</listitem>
|
|
<listitem>Portable error codes</listitem>
|
|
<listitem>Nested transactions</listitem>
|
|
<listitem>Transaction isolation abstraction</listitem>
|
|
<listitem>Transaction savepoint abstraction</listitem>
|
|
<listitem>Index/Unique Key/Primary Key support</listitem>
|
|
<listitem>Ability to read the information schema</listitem>
|
|
<listitem>Reverse engineering schemas from an existing database</listitem>
|
|
<listitem>LIMIT / OFFSET emulation </listitem>
|
|
</itemizedlist>
|
|
|
|
<sect3 id="features-orm">
|
|
<title>
|
|
Object Relational Mapping
|
|
</title>
|
|
<sect4 id="features-orm-general">
|
|
<title>
|
|
General Features
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>Validators</listitem>
|
|
<listitem>Transactional errorStack for easy retrieval of all errors</listitem>
|
|
<listitem>EventListeners</listitem>
|
|
<listitem>UnitOfWork pattern (easy saving of all pending objects)</listitem>
|
|
<listitem>Uses ActiveRecord pattern</listitem>
|
|
<listitem>State-wise records and transactions</listitem>
|
|
<listitem>Importing existing database schemas to Doctrine ActiveRecord objects</listitem>
|
|
<listitem>Exporting Doctrine ActiveRecords to database (= automatic table creation)</listitem>
|
|
</itemizedlist>
|
|
</sect4>
|
|
<sect4 id="features-orm-mapping">
|
|
<title>
|
|
Mapping
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>Composite, Natural, Autoincremented and Sequential identifiers</listitem>
|
|
<listitem>PHP Array / Object data types for columns (automatic serialization/unserialization)</listitem>
|
|
<listitem>Gzip datatype for all databases</listitem>
|
|
<listitem>Emulated enum datatype for all databases</listitem>
|
|
<listitem>Datatype abstraction</listitem>
|
|
<listitem>Column aggregation inheritance</listitem>
|
|
<listitem>One-class-one-table inheritance as well as One-table</listitem>
|
|
<listitem>One-to-many, many-to-one, one-to-one and many-to-many relations</listitem>
|
|
<listitem>Self-referencing relations even for association table relations</listitem>
|
|
<listitem>Relation aliases</listitem>
|
|
</itemizedlist>
|
|
</sect4>
|
|
|
|
<sect4 id="features-orm-population">
|
|
<title>
|
|
Object population
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>DQL (Doctrine Query Language), an EJB 3 spec compliant OQL</listitem>
|
|
<listitem>The limit-subquery-algorithm</listitem>
|
|
<listitem>OO-style query API for both DQL and raw SQL</listitem>
|
|
<listitem>Object population from database views</listitem>
|
|
<listitem>Object population through raw SQL</listitem>
|
|
</itemizedlist>
|
|
</sect4>
|
|
|
|
<sect4 id="features-orm-locking">
|
|
<title>
|
|
Transactions and locking
|
|
</title>
|
|
<itemizedlist>
|
|
<listitem>Pessimistic offline locking</listitem>
|
|
<listitem>Savepoints, transaction isolation levels and nested transactions</listitem>
|
|
<listitem>Transactional query optimization (gathering of DELETE statements) </listitem>
|
|
</itemizedlist>
|
|
</sect4>
|
|
</sect3>
|
|
</sect1>
|
|
|
|
<sect1 id="requirements">
|
|
<title>Requirements</title>
|
|
<para>
|
|
Doctrine requires PHP >= 5.1, and it doesn't require any external libraries.
|
|
</para>
|
|
<para>
|
|
For database abstraction Doctrine uses PDO which is bundled with php by
|
|
default. Doctrine also requires a little adodb-hack for table creation,
|
|
which comes with doctrine.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="community">
|
|
<title>Community</title>
|
|
<para>
|
|
Doctrine has 3 mailing lists, an IRC channel, a forum, and a wiki.
|
|
</para>
|
|
<sect2 id="community-forum">
|
|
<title>Forum</title>
|
|
<para>
|
|
The Doctrine forum can be found here:
|
|
<ulink url="http://www.phpbbserver.com/phpdoctrine/">http://www.phpbbserver.com/phpdoctrine/</ulink>
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="community-mailinglist">
|
|
<title>Mailing Lists</title>
|
|
<para>
|
|
The 'user' mailing list is for discussing the usage of doctrine.
|
|
To subscribe to this list, send a blank email to
|
|
<email>doctrine-user+subscribe@lists.pengus.net</email>
|
|
</para>
|
|
<para>
|
|
The 'dev' mailing list is used for discussion of the development
|
|
of doctrine. To subscribe to this list, send a blank email to
|
|
<email>doctrine-dev+subscribe@lists.pengus.net</email>
|
|
</para>
|
|
<para>
|
|
The 'svn' mailing list is a read-only list, which users and developers
|
|
can subscribe to to receive commit logs to the SVN repository. This
|
|
list is quite high traffic, as every commit to the repository results
|
|
in an email containing the changelog entry and diffs of the changed
|
|
files.
|
|
To subscribe to this list, send a blank email to
|
|
<email>doctrine-svn+subscribe@lists.pengus.net</email>
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="community-irc">
|
|
<title>IRC</title>
|
|
<para>
|
|
The #doctrine IRC channel can be found on the freenode network. The fastest way of getting bugs fixed and features being implemented is joining our irc channel and pointing out the issue to one of the developers.
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="community-wiki">
|
|
<title>Wiki and Trac</title>
|
|
<para>
|
|
A wiki/trac install can be found at <ulink
|
|
url="http://doctrine.pengus.net/trac">http://doctrine.pengus.net/trac</ulink>
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="contributing">
|
|
<title>Contributing/Reporting Bugs</title>
|
|
<para>
|
|
Doctrine is constantly under development, and is always happy for new
|
|
developers to contribute to the project.
|
|
</para>
|
|
<para>
|
|
To get an account on trac to submit bugs and make suggestions, or to get
|
|
access to commit to the SVN repository, please visit the IRC channel, or
|
|
email the users mailing list.
|
|
</para>
|
|
<para>
|
|
If you are unsure as to wether you have found a bug or not, please
|
|
consider joining us on IRC, or maining the user mailing list to confirm
|
|
your problem.
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="installation">
|
|
<title>Installation</title>
|
|
<para>
|
|
As of the time of writing, there is no stable release of doctrine. That is not to say
|
|
that it's unstable, but simply that the best way to install it is to aquire it from
|
|
SVN.
|
|
</para>
|
|
<para>
|
|
To get the latest copy, simple check out 'trunk' from SVN. You will
|
|
need <ulink url="http://subversion.tigris.org/">subversion</ulink>
|
|
install to check out doctrine. If you are unable to install subversion
|
|
for whatever reason, see below for details on downloading a snapshot.
|
|
</para>
|
|
<screen>
|
|
<prompt>bash $</prompt><command>mkdir <replaceable>doctrine</replaceable></command>
|
|
<prompt>bash $</prompt><command>cd <replacable>doctrine</replacable></command>
|
|
<prompt>bash $</prompt><command>svn checkout http://doctrine.pengus.net/svn/trunk .</command>
|
|
</screen>
|
|
<para>
|
|
Daily snapshots can be found at
|
|
<ulink url="http://doctrine.pengus.net/downloads/">http://doctrine.pengus.net/downloads/</ulink>
|
|
and the latest daily snapshot can always be found at
|
|
<ulink url="http://doctrine.pengus.net/downloads/latest-snapshot.tar.gz">http://doctrine.pengus.net/downloads/latest-snapshot.tar.gz</ulink>
|
|
</para>
|
|
</sect1>
|
|
|
|
<sect1 id="include-and-autoload">
|
|
<title>Include and autoload</title>
|
|
<para>
|
|
In order to use Doctrine in your project it must first be included.
|
|
</para>
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
require_once('path-to-doctrine/lib/Doctrine.php');
|
|
?>]]></programlisting>
|
|
<para>
|
|
Doctrine support <ulink
|
|
url="http://www.php.net/autoload">Autoloading</ulink> for including
|
|
files so that you do not have to include anything more then the base
|
|
file. There are two different strategies that can be used to do this:
|
|
</para>
|
|
|
|
<para>
|
|
If you do use the <emphasis>__autoload</emphasis> function for your own
|
|
logic you can use it.
|
|
</para>
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
function __autoload($class) {
|
|
Doctrine::autoload($class);
|
|
}
|
|
?>]]></programlisting>
|
|
|
|
<para>
|
|
If your project uses autoload and/or you have other libraries that use
|
|
it you could use <ulink
|
|
url="http://www.php.net/manual/en/function.spl-autoload-register.php">spl_autoload_register</ulink>
|
|
to register more then one autoloading function.
|
|
</para>
|
|
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
spl_autoload_register(array('Doctrine', 'autoload'));
|
|
?>]]></programlisting>
|
|
</sect1>
|
|
|
|
<sect1 id="compiling">
|
|
<title>Compiling</title>
|
|
<para>
|
|
Compiling is a method for making a single file of most used doctrine
|
|
runtime components including the compiled file instead of multiple files
|
|
(in worst cases dozens of files) can improve performance by an order of
|
|
magnitude.
|
|
</para>
|
|
<para>
|
|
In cases where this might fail, a Doctrine_Exception is throw detailing
|
|
the error.
|
|
</para>
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
Doctrine::compile();
|
|
|
|
// on some other script:
|
|
require_once('path_to_doctrine/Doctrine.compiled.php');
|
|
?>]]></programlisting>
|
|
</sect1>
|
|
|
|
<sect1 id="new-project">
|
|
<title>Starting a new project</title>
|
|
<para>
|
|
Doctrine_Record is the basic component of every doctrine-based project.
|
|
There should be atleast one Doctrine_Record for each of your database
|
|
tables. Doctrine_Record follows the <ulink
|
|
url="http://www.martinfowler.com/eaaCatalog/activeRecord.html">Active
|
|
Record pattern</ulink>
|
|
</para>
|
|
<para>
|
|
Doctrine auto-creates database tables and always adds a primary key
|
|
column named 'id' to tables that doesn't have any primary keys
|
|
specified. The only thing you need to do to create database tables is
|
|
defining a class which extends Doctrine_Record and setting a
|
|
setTableDefinition method with hasColumn() method calls.
|
|
</para>
|
|
<para>
|
|
Below is a short example:
|
|
</para>
|
|
<para>
|
|
We want to create a database table called 'user' with columns
|
|
id(primary key), name, username, password and created. Provided that
|
|
you have already installed Doctrine these few lines of code are all you
|
|
need:
|
|
</para>
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
|
|
require_once('lib/Doctrine.php');
|
|
|
|
spl_autoload_register(array('Doctrine', 'autoload'));
|
|
|
|
class User extends Doctrine_Record {
|
|
public function setTableDefinition() {
|
|
// set 'user' table columns, note that
|
|
// id column is always auto-created
|
|
|
|
$this->hasColumn('name','string',30);
|
|
$this->hasColumn('username','string',20);
|
|
$this->hasColumn('password','string',16);
|
|
$this->hasColumn('created','integer',11);
|
|
}
|
|
}
|
|
?>]]></programlisting>
|
|
<para>
|
|
We now have a user model that supports basic CRUD opperations!
|
|
</para>
|
|
</sect1>
|
|
</chapter>
|
|
|
|
<chapter id="connection-management">
|
|
<title>Connection Management</title>
|
|
</chapter>
|
|
|
|
<chapter id="object-relational-mapping">
|
|
<title>Object Relational Mapping</title>
|
|
</chapter>
|
|
|
|
<chapter id="working-with-objects">
|
|
<title>Working With Objects</title>
|
|
</chapter>
|
|
|
|
<chapter id="configuration">
|
|
<title>Configuration</title>
|
|
</chapter>
|
|
|
|
<chapter id="advanced-components">
|
|
<title>Advanced Components</title>
|
|
</chapter>
|
|
|
|
<chapter id="dql">
|
|
<title>DQL (Doctrine Query Lanaguage)</title>
|
|
<sect1 id="dql-intro">
|
|
<title>Introduction</title>
|
|
<para>
|
|
Doctrine Query Language(DQL) is an Object Query Language created for helping users in complex object retrieval.
|
|
</para>
|
|
<para>
|
|
You should always consider using DQL(or raw SQL) when retrieving relational data efficiently (eg. when fetching users and their phonenumbers).
|
|
</para>
|
|
<para>
|
|
When compared to using raw SQL, DQL has several benefits:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem><para>From the start it has been designed to retrieve records(objects) not result set rows.</para></listitem>
|
|
<listitem><para>DQL understands relations so you don't have to type manually sql joins and join conditions.</para></listitem>
|
|
<listitem><para>DQL is portable on different databases</para></listitem>
|
|
<listitem><para>DQL has some very complex built-in algorithms like (the record limit algorithm) which can help developer to efficiently retrieve objects.</para></listitem>
|
|
<listitem><para>It supports some functions that can save time when dealing with one-to-many, many-to-many relational data with conditional fetching.</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>
|
|
If the power of DQL isn't enough, you should consider using the rawSql API for object population.
|
|
</para>
|
|
|
|
<programlisting role="php"><![CDATA[
|
|
<?php
|
|
// DO NOT USE THE FOLLOWING CODE
|
|
// (using many sql queries for object population):
|
|
|
|
$users = $conn->getTable('User')->findAll();
|
|
foreach($users as $user) {
|
|
print $user->name."\n";
|
|
foreach($user->Phonenumber as $phonenumber) {
|
|
print $phonenumber."\n";
|
|
}
|
|
}
|
|
|
|
// same thing implemented much more efficiently:
|
|
// (using only one sql query for object population)
|
|
|
|
$users = $conn->query("FROM User.Phonenumber");
|
|
foreach($users as $user) {
|
|
print $user->name."\n";
|
|
foreach($user->Phonenumber as $phonenumber) {
|
|
print $phonenumber."\n";
|
|
}
|
|
}
|
|
?>]]></programlisting>
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
<chapter id="native-sql">
|
|
<title>Native SQL</title>
|
|
</chapter>
|
|
|
|
<chapter id="transactions">
|
|
<title>Transactions</title>
|
|
</chapter>
|
|
|
|
<chapter id="caching">
|
|
<title>Caching</title>
|
|
</chapter>
|
|
|
|
<chapter id="database-abstraction">
|
|
<title>Database Abstraction</title>
|
|
</chapter>
|
|
|
|
<chapter id="technology">
|
|
<title>Technology</title>
|
|
</chapter>
|
|
|
|
<chapter id="real-world-examples">
|
|
<title>Real World Examples</title>
|
|
</chapter>
|
|
|
|
<chapter id="coding-standards">
|
|
<title>Coding Standards</title>
|
|
</chapter>
|
|
|
|
</book>
|