1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
<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>
<sect3 id="features-general">
<title>
General Features
</title>
<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>
</sect3>
<sect3 id="features-abstraction">
<title>
Database Abstraction
</title>
<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>
<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.
It runs on both windows and *nix based platforms.
</para>
<para>
For database abstraction Doctrine uses PDO which is bundled with php by
default. You will need PDO support for whatever database you intend to
use, and if you want to be able to run the included unit tests, you
will need SQLite support.
</para>
<para>
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/trac.
</para>
<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>
<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>
</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 <replaceable>doctrine</replaceable></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, you must first include the main
library file called 'Doctrine.php'.
</para>
<programlisting role="php"><![CDATA[
<?php
require_once('path-to-doctrine/lib/Doctrine.php');
?>]]></programlisting>
<para>
Doctrine supports <ulink
url="http://www.php.net/autoload">Autoloading</ulink> for including
files so that you don't have to include anything more then the base
file. There are two different strategies that can be used to do this,
as shown below.
</para>
<para>
You can use the <emphasis>__autoload</emphasis> function to call the
'Doctrine::autoload($class)' method, for example:
</para>
<programlisting role="php"><![CDATA[
<?php
function __autoload($class) {
Doctrine::autoload($class);
}
?>]]></programlisting>
<para>
If your project already uses autoload or you have other libraries
that use it, you can use <ulink
url="http://www.php.net/manual/en/function.spl-autoload-register.php">spl_autoload_register</ulink>
to register multiple autoloading functions.
</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 the most used doctrine
runtime components. Including this 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 thrown 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 don'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>