Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #13 from jeserkin/master

Edit event-listeners.rst, caching.rst, migrations.rst, extensions.rst, utilities.rst, unit-testing.rst
  • Loading branch information...
commit de2d052a97b594f8af9e0458ed18f4bd736a2e0f 2 parents 34c642c + 2b36a35
Dominic Scheirlinck dominics authored
203 source/en/manual/caching.rst
View
@@ -6,20 +6,23 @@ Caching
Introduction
============
-``Doctrine_Cache`` offers an intuitive and easy-to-use query caching
+:php:class:`Doctrine_Cache` offers an intuitive and easy-to-use query caching
solution. It provides the following things:
- Multiple cache backends to choose from (including Memcached, APC and
Sqlite)
-- Advanced options for fine-tuning. ``Doctrine_Cache`` has many
+- Advanced options for fine-tuning. :php:class:`Doctrine_Cache` has many
options for fine-tuning performance.
All the cache drivers are instantiated like the following:
- // bootstrap.php
+::
-// ... $options = array();
-:code:`cacheDriver = new Doctrine_Cache_Memcache(`\ options);
+ // bootstrap.php
+
+ // ...
+ $options = array();
+ $cacheDriver = new Doctrine_Cache_Memcache( $options );
.. note::
@@ -41,13 +44,23 @@ PECL extension.
You can instantiate the Memcache cache driver with the following code:
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... $servers = array( 'host' => 'localhost', 'port' => 11211,
-'persistent' => true );
+ // ...
+ $servers = array(
+ 'host' => 'localhost',
+ 'port' => 11211,
+ 'persistent' => true
+ );
-$cacheDriver = new Doctrine\_Cache\_Memcache(array( 'servers' =>
-$servers, 'compression' => false ) );
+ $cacheDriver = new Doctrine_Cache_Memcache(
+ array(
+ 'servers' => $servers,
+ 'compression' => false
+ )
+ );
.. note::
@@ -55,15 +68,17 @@ $servers, 'compression' => false ) );
Available options for Memcache driver:
-\|\|~ Option \|\|~ Data Type \|\|~ Default Value \|\|~ Description \|\|
-\|\| ``servers`` \|\| ``array`` \|\| ``array(array('host' =>
-'localhost','port' => 11211, 'persistent' => true))`` \|\| An array of
-memcached servers ; each memcached server is described by an associative
-array : ``'host' => (string)`` : the name of the memcached server,
-``'port' => (int)`` : the port of the memcached server, ``'persistent'
-=> (bool)`` : use or not persistent connections to this memcached server
-\|\| \|\| ``compression`` \|\| ``boolean`` \|\| ``false`` \|\| ``true``
-if you want to use on-the-fly compression \|\|
+=============== ============ ============================================================================= ======================================================
+Option Data Type Default Value Description
+=============== ============ ============================================================================= ======================================================
+``servers`` ``array`` ``array(array('host' => 'localhost','port' => 11211, 'persistent' => true))`` An array of memcached servers ; each memcached
+ server is described by an associative array :
+ ``'host' => (string)`` : the name of the memcached
+ server, ``'port' => (int)`` : the port of the
+ memcached server, ``'persistent' => (bool)`` : use
+ or not persistent connections to this memcached server
+``compression`` ``boolean`` ``false`` ``true`` if you want to use on-the-fly compression
+=============== ============ ============================================================================= ======================================================
---
APC
@@ -76,9 +91,12 @@ Doctrine stores cache records in shared memory.
You can instantiate the APC cache driver with the following code:
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... $cacheDriver = new Doctrine\_Cache\_Apc();
+ // ...
+ $cacheDriver = new Doctrine_Cache_Apc();
--
Db
@@ -89,11 +107,14 @@ some fast flat-file based database is used (such as sqlite).
You can instantiate the database cache driver with the following code:
- // bootstrap.php
+::
+
+ // bootstrap.php
+
+ // ...
+ $cacheConn = Doctrine_Manager::connection( new PDO( 'sqlite::memory:' ) );
+ $cacheDriver = new Doctrine_Cache_Db( array( 'connection' => $cacheConn ) );
-// ... $cacheConn = Doctrine\_Manager::connection(new
-PDO('sqlite::memory:')); $cacheDriver = new
-Doctrine\_Cache\_Db(array('connection' => $cacheConn));
==========================
Query Cache & Result Cache
@@ -108,39 +129,21 @@ process, as well as the end results of DQL queries (the data). These two
caching mechanisms can greatly increase performance. Consider the
standard workflow of DQL query execution:
-Init new DQL query
-``````````````````
-
-Parse DQL query
-```````````````
-
-Build database specific SQL query
-`````````````````````````````````
-
-Execute the SQL query
-`````````````````````
-
-Build the result set
-````````````````````
-
-Return the result set
-`````````````````````
+ - Init new DQL query
+ - Parse DQL query
+ - Build database specific SQL query
+ - Execute the SQL query
+ - Build the result set
+ - Return the result set
Now these phases can be very time consuming, especially phase 4 which
sends the query to your database server. When Doctrine query cache is
being used only the following phases occur:
-Init new DQL query
-``````````````````
-
-Execute the SQL query (grabbed from the cache)
-``````````````````````````````````````````````
-
-Build the result set
-````````````````````
-
-Return the result set
-`````````````````````
+ - Init new DQL query
+ - Execute the SQL query (grabbed from the cache)
+ - Build the result set
+ - Return the result set
If a DQL query has a valid cache entry the cached SQL query is used,
otherwise the phases 2-3 are executed normally and the result of these
@@ -163,11 +166,8 @@ and always use placeholders instead.
When using a result cache things get even better. Then your query
process looks as follows (assuming a valid cache entry is found):
-Init new DQL query
-``````````````````
-
-Return the result set
-`````````````````````
+ - Init new DQL query
+ - Return the result set
As you can see, the result cache implies the query cache shown
previously. You should always consider using a result cache if the data
@@ -182,7 +182,7 @@ Using the Query Cache
^^^^^^^^^^^^^^^^^^^^^
You can set a connection or manager level query cache driver by using
-the ``Doctrine\_Core::ATTR\_QUERY_CACHE`` attribute. Setting a
+the ``Doctrine_Core::ATTR_QUERY_CACHE`` attribute. Setting a
connection level cache driver means that all queries executed with this
connection use the specified cache driver whereas setting a manager
level cache driver means that all connections (unless overridden at
@@ -190,10 +190,12 @@ connection level) will use the given cache driver.
**Setting a manager level query cache driver:**
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... $manager->setAttribute(Doctrine\_Core::ATTR\_QUERY\_CACHE,
-$cacheDriver);
+ // ...
+ $manager->setAttribute( Doctrine_Core::ATTR_QUERY_CACHE, $cacheDriver );
.. note::
@@ -202,10 +204,12 @@ $cacheDriver);
**Setting a connection level cache driver:**
- // bootstrap.php
+::
-// ... $conn->setAttribute(Doctrine\_Core::ATTR\_QUERY\_CACHE,
-$cacheDriver);
+ // bootstrap.php
+
+ // ...
+ $conn->setAttribute( Doctrine_Core::ATTR_QUERY_CACHE, $cacheDriver );
^^^^^^^^^^^
Fine Tuning
@@ -217,8 +221,10 @@ cache driver by calling ``useQueryCache()`` and pass it an instance of a
valid Doctrine cache driver. This rarely makes sense for the query cache
but is possible:
- $q = Doctrine\_Query::create() ->useQueryCache(new
-Doctrine\_Cache\_Apc());
+::
+
+ $q = Doctrine_Query::create()
+ ->useQueryCache(new Doctrine_Cache_Apc() );
------------
Result Cache
@@ -229,7 +235,7 @@ Using the Result Cache
^^^^^^^^^^^^^^^^^^^^^^
You can set a connection or manager level result cache driver by using
-``Doctrine\_Core::ATTR\_RESULT_CACHE``. Setting a connection level
+``Doctrine_Core::ATTR_RESULT_CACHE``. Setting a connection level
cache driver means that all queries executed with this connection use
the specified cache driver whereas setting a manager level cache driver
means that all connections (unless overridden at connection level) will
@@ -237,41 +243,51 @@ use the given cache driver.
**Setting a manager level cache driver:**
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... $manager->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE,
-$cacheDriver);
+ // ...
+ $manager->setAttribute( Doctrine_Core::ATTR_RESULT_CACHE, $cacheDriver );
**Setting a connection level cache driver:**
- // bootstrap.php
+::
-// ... $conn->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE,
-$cacheDriver);
+ // bootstrap.php
+
+ // ...
+ $conn->setAttribute( Doctrine_Core::ATTR_RESULT_CACHE, $cacheDriver );
Usually the cache entries are valid for only some time. You can set
global value for how long the cache entries should be considered valid
-by using ``Doctrine\_Core::ATTR\_RESULT\_CACHE_LIFESPAN``.
+by using ``Doctrine_Core::ATTR_RESULT_CACHE_LIFESPAN``.
-**Set the lifespan as one hour (60 seconds \* 60 minutes = 1 hour = 3600
+**Set the lifespan as one hour (60 seconds * 60 minutes = 1 hour = 3600
secs):**
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ...
-$manager->setAttribute(Doctrine\_Core::ATTR\_RESULT\_CACHE\_LIFESPAN,
-3600);
+ // ...
+ $manager->setAttribute( Doctrine_Core::ATTR_RESULT_CACHE_LIFESPAN, 3600 );
Now as we have set a cache driver for use we can make a DQL query use it
by calling the ``useResultCache()`` method:
**Fetch blog post titles and the number of comments:**
- $q = Doctrine\_Query::create() ->select('b.title, COUNT(c.id) count')
-->from('BlogPost b') ->leftJoin('b.Comments c') ->limit(10)
-->useResultCache(true);
+::
+
+ $q = Doctrine_Query::create()
+ ->select( 'b.title, COUNT(c.id) count' )
+ ->from( 'BlogPost b' )
+ ->leftJoin( 'b.Comments c' )
+ ->limit( 10 )
+ ->useResultCache( true );
-$blogPosts = $q->execute();
+ $blogPosts = $q->execute();
^^^^^^^^^^^
Fine Tuning
@@ -282,13 +298,18 @@ attributes can be overriden at the query level. You can override the
cache driver by calling ``useCache()`` and pass it an instance of a
valid Doctrine cache driver.
- $q = Doctrine\_Query::create() ->useResultCache(new
-Doctrine\_Cache\_Apc());
+::
+
+ $q = Doctrine_Query::create()
+ ->useResultCache(new Doctrine_Cache_Apc() );
Also you can override the lifespan attribute by calling
``setResultCacheLifeSpan()``:
- $q = Doctrine\_Query::create() ->setResultCacheLifeSpan(60 \* 30);
+::
+
+ $q = Doctrine_Query::create()
+ ->setResultCacheLifeSpan( 60 * 30 );
==========
Conclusion
@@ -299,7 +320,7 @@ development and production environments. There are no adverse affects to
using it and it will only help the performance of your application.
The caching feature is the second to last feature we will discuss in
-this book before wrapping things up by discussing things like the [doc
-technology technologies used in Doctrine], [doc coding-standards coding
-standards] and [doc unit-testing unit testing]. Lets move on to discuss
-the last feature of Doctrine, [doc migrations :name].
+this book before wrapping things up by discussing things like
+the :doc:`technology`, :doc:`coding-standards`
+and :doc:`unit-testing`. Lets move on to discuss
+the last feature of Doctrine, :doc:`migrations`.
789 source/en/manual/event-listeners.rst
View
@@ -15,22 +15,23 @@ components. Listeners are separate classes whereas hooks are empty
template methods within the listened class.
Hooks are simpler than event listeners but they lack the separation of
-different aspects. An example of using ``Doctrine_Record`` hooks:
-
- // models/BlogPost.php
-
-class BlogPost extends Doctrine\_Record { // ...
+different aspects. An example of using :php:class:`Doctrine_Record` hooks:
::
- public function preInsert($event)
+ // models/BlogPost.php
+
+ class BlogPost extends Doctrine_Record
{
- $invoker = $event->getInvoker();
+ // ...
- $invoker->created = date('Y-m-d', time());
- }
+ public function preInsert($event)
+ {
+ $invoker = $event->getInvoker();
-}
+ $invoker->created = date('Y-m-d', time());
+ }
+ }
.. note::
@@ -41,17 +42,22 @@ class BlogPost extends Doctrine\_Record { // ...
Now you can use the above model with the following code assuming we
added a ``title``, ``body`` and ``created`` column to the model:
- // test.php
+::
+
+ // test.php
-// ... $blog = new BlogPost(); $blog->title = 'New title'; $blog->body =
-'Some content'; $blog->save();
+ // ...
+ $blog = new BlogPost();
+ $blog->title = 'New title';
+ $blog->body = 'Some content';
+ $blog->save();
-echo $blog->created;
+ echo $blog->created;
The above example will output the current date as PHP knows it.
-Each listener and hook method takes one parameter ``Doctrine_Event``
-object. ``Doctrine_Event`` object holds information about the event in
+Each listener and hook method takes one parameter :php:class:`Doctrine_Event`
+object. :php:class:`Doctrine_Event` object holds information about the event in
question and can alter the execution of the listened method.
For the purposes of this documentation many method tables are provided
@@ -66,170 +72,189 @@ Connection Listeners
====================
Connection listeners are used for listening the methods of
-``Doctrine_Connection`` and its modules (such as
-``Doctrine_Transaction``). All listener methods take one argument
-``Doctrine_Event`` which holds information about the listened event.
+:php:class:`Doctrine_Connection` and its modules (such as
+:php:class:`Doctrine_Transaction`). All listener methods take one argument
+:php:class:`Doctrine_Event` which holds information about the listened event.
-----------------------
Creating a New Listener
-----------------------
There are three different ways of defining a listener. First you can
-create a listener by making a class that inherits
-``Doctrine_EventListener``:
-
- class MyListener extends Doctrine\_EventListener { public function
-preExec(Doctrine\_Event $event) {
+create a listener by making a class that inherits :php:class:`Doctrine_EventListener`:
::
- }
+ class MyListener extends Doctrine_EventListener
+ {
+ public function preExec( Doctrine_Event $event )
+ {
-}
+ }
+ }
-Note that by declaring a class that extends ``Doctrine_EventListener``
+Note that by declaring a class that extends :php:class:`Doctrine_EventListener`
you don't have to define all the methods within the
-``Doctrine\_EventListener_Interface``. This is due to a fact that
-``Doctrine_EventListener`` already has empty skeletons for all these
+:php:class:`Doctrine_EventListener_Interface`. This is due to a fact that
+:php:class:`Doctrine_EventListener` already has empty skeletons for all these
methods.
Sometimes it may not be possible to define a listener that extends
-``Doctrine_EventListener`` (you might have a listener that inherits
+:php:class:`Doctrine_EventListener` (you might have a listener that inherits
some other base class). In this case you can make it implement
-``Doctrine\_EventListener_Interface``.
-
- class MyListener implements Doctrine\_EventListener\_Interface { public
-function preTransactionCommit(Doctrine\_Event $event) {} public function
-postTransactionCommit(Doctrine\_Event $event) {}
+:php:class:`Doctrine_EventListener_Interface`.
::
- public function preTransactionRollback(Doctrine_Event $event) {}
- public function postTransactionRollback(Doctrine_Event $event) {}
+ class MyListener implements Doctrine_EventListener_Interface
+ {
+ public function preTransactionCommit( Doctrine_Event $event ) {}
+ public function postTransactionCommit( Doctrine_Event $event ) {}
- public function preTransactionBegin(Doctrine_Event $event) {}
- public function postTransactionBegin(Doctrine_Event $event) {}
+ public function preTransactionRollback( Doctrine_Event $event ) {}
+ public function postTransactionRollback( Doctrine_Event $event ) {}
- public function postConnect(Doctrine_Event $event) {}
- public function preConnect(Doctrine_Event $event) {}
+ public function preTransactionBegin( Doctrine_Event $event ) {}
+ public function postTransactionBegin( Doctrine_Event $event ) {}
- public function preQuery(Doctrine_Event $event) {}
- public function postQuery(Doctrine_Event $event) {}
+ public function postConnect( Doctrine_Event $event ) {}
+ public function preConnect( Doctrine_Event $event ) {}
- public function prePrepare(Doctrine_Event $event) {}
- public function postPrepare(Doctrine_Event $event) {}
+ public function preQuery( Doctrine_Event $event ) {}
+ public function postQuery( Doctrine_Event $event ) {}
- public function preExec(Doctrine_Event $event) {}
- public function postExec(Doctrine_Event $event) {}
+ public function prePrepare( Doctrine_Event $event ) {}
+ public function postPrepare( Doctrine_Event $event ) {}
- public function preError(Doctrine_Event $event) {}
- public function postError(Doctrine_Event $event) {}
+ public function preExec( Doctrine_Event $event ) {}
+ public function postExec( Doctrine_Event $event ) {}
- public function preFetch(Doctrine_Event $event) {}
- public function postFetch(Doctrine_Event $event) {}
+ public function preError( Doctrine_Event $event ) {}
+ public function postError( Doctrine_Event $event ) {}
- public function preFetchAll(Doctrine_Event $event) {}
- public function postFetchAll(Doctrine_Event $event) {}
+ public function preFetch( Doctrine_Event $event ) {}
+ public function postFetch( Doctrine_Event $event ) {}
- public function preStmtExecute(Doctrine_Event $event) {}
- public function postStmtExecute(Doctrine_Event $event) {}
+ public function preFetchAll( Doctrine_Event $event ) {}
+ public function postFetchAll( Doctrine_Event $event ) {}
-}
+ public function preStmtExecute( Doctrine_Event $event ) {}
+ public function postStmtExecute( Doctrine_Event $event ) {}
+ }
.. caution::
- All listener methods must be defined here otherwise PHP
- throws fatal error.
+ All listener methods must be defined here otherwise PHP throws fatal error.
The third way of creating a listener is a very elegant one. You can make
-a class that implements ``Doctrine_Overloadable``. This interface has
-only one method: ``\__call()``, which can be used for catching *all*
+a class that implements :php:class:`Doctrine_Overloadable`. This interface has
+only one method: ``__call()``, which can be used for catching *all*
the events.
- class MyDebugger implements Doctrine\_Overloadable { public function
-\_\_call($methodName, $args) { echo $methodName . ' called !'; } }
+::
+
+ class MyDebugger implements Doctrine_Overloadable
+ {
+ public function __call( $methodName, $args )
+ {
+ echo $methodName . ' called !';
+ }
+ }
-------------------
Attaching listeners
-------------------
-You can attach the listeners to a connection with setListener().
+You can attach the listeners to a connection with ``setListener()``.
+
+::
+
+ $conn->setListener( new MyDebugger() );
- $conn->setListener(new MyDebugger());
+If you need to use multiple listeners you can use ``addListener()``.
-If you need to use multiple listeners you can use addListener().
+::
- $conn->addListener(new MyDebugger()); $conn->addListener(new
-MyLogger());
+ $conn->addListener( new MyDebugger() );
+ $conn->addListener( new MyLogger() );
--------------------
Pre and Post Connect
--------------------
-All of the below listeners are invoked in the ``Doctrine_Connection``
-class. And they are all passed an instance of ``Doctrine_Event``.
+All of the below listeners are invoked in the :php:class:`Doctrine_Connection`
+class. And they are all passed an instance of :php:class:`Doctrine_Event`.
-\|\|~ Methods \|\|~ Listens \|\|~ Params \|\| \|\| ``preConnect()`` \|\|
-``connection()`` \|\| \|\| \|\| ``postConnect()`` \|\| ``connection()``
-\|\| \|\|
+================= ================ ==============
+Methods Listens Params
+================= ================ ==============
+``preConnect()`` ``connection()``
+``postConnect()`` ``connection()``
+================= ================ ==============
---------------------
Transaction Listeners
---------------------
-All of the below listeners are invoked in the ``Doctrine_Transaction``
-class. And they are all passed an instance of ``Doctrine_Event``.
-
-\|\|~ Methods \|\|~ Listens \|\|~ Params \|\| \|\|
-``preTransactionBegin()`` \|\| ``beginTransaction()`` \|\| \|\| \|\|
-``postTransactionBegin()`` \|\| ``beginTransaction()`` \|\| \|\| \|\|
-``preTransactionRollback()`` \|\| ``rollback()`` \|\| \|\| \|\|
-``postTransactionRollback()`` \|\| ``rollback()`` \|\| \|\| \|\|
-``preTransactionCommit()`` \|\| ``commit()`` \|\| \|\| \|\|
-``postTransactionCommit()`` \|\| ``commit()`` \|\| \|\| \|\|
-``preCreateSavepoint()`` \|\| ``createSavepoint()`` \|\| ``savepoint``
-\|\| \|\| ``postCreateSavepoint()`` \|\| ``createSavepoint()`` \|\|
-``savepoint`` \|\| \|\| ``preRollbackSavepoint()`` \|\|
-``rollbackSavepoint()`` \|\| ``savepoint`` \|\| \|\|
-``postRollbackSavepoint()`` \|\| ``rollbackSavepoint()`` \|\|
-``savepoint`` \|\| \|\| ``preReleaseSavepoint()`` \|\|
-``releaseSavepoint()`` \|\| ``savepoint`` \|\| \|\|
-``postReleaseSavepoint()`` \|\| ``releaseSavepoint()`` \|\|
-``savepoint`` \|\|
-
- class MyTransactionListener extends Doctrine\_EventListener { public
-function preTransactionBegin(Doctrine\_Event $event) { echo 'beginning
-transaction... '; }
+All of the below listeners are invoked in the :php:class:`Doctrine_Transaction`
+class. And they are all passed an instance of :php:class:`Doctrine_Event`.
+
+============================= ======================= =============
+Methods Listens Params
+============================= ======================= =============
+``preTransactionBegin()`` ``beginTransaction()``
+``postTransactionBegin()`` ``beginTransaction()``
+``preTransactionRollback()`` ``rollback()``
+``postTransactionRollback()`` ``rollback()``
+``preTransactionCommit()`` ``commit()``
+``postTransactionCommit()`` ``commit()``
+``preCreateSavepoint()`` ``createSavepoint()`` ``savepoint``
+``postCreateSavepoint()`` ``createSavepoint()`` ``savepoint``
+``preRollbackSavepoint()`` ``rollbackSavepoint()`` ``savepoint``
+``postRollbackSavepoint()`` ``rollbackSavepoint()`` ``savepoint``
+``preReleaseSavepoint()`` ``releaseSavepoint()`` ``savepoint``
+``postReleaseSavepoint()`` ``releaseSavepoint()`` ``savepoint``
+============================= ======================= =============
::
- public function preTransactionRollback(Doctrine_Event $event)
+ class MyTransactionListener extends Doctrine_EventListener
{
- echo 'rolling back transaction... ';
- }
+ public function preTransactionBegin( Doctrine_Event $event )
+ {
+ echo 'beginning transaction... ';
+ }
-}
+ public function preTransactionRollback( Doctrine_Event $event )
+ {
+ echo 'rolling back transaction... ';
+ }
+ }
-------------------------
Query Execution Listeners
-------------------------
-All of the below listeners are invoked in the ``Doctrine_Connection``
-and ``Doctrine\_Connection_Statement`` classes. And they are all passed
-an instance of ``Doctrine_Event``.
-
-\|\|~ Methods \|\|~ Listens \|\|~ Params \|\| \|\| ``prePrepare()`` \|\|
-``prepare()`` \|\| ``query`` \|\| \|\| ``postPrepare()`` \|\|
-``prepare()`` \|\| ``query`` \|\| \|\| ``preExec()`` \|\| ``exec()``
-\|\| ``query`` \|\| \|\| ``postExec()`` \|\| ``exec()`` \|\| ``query,
-rows`` \|\| \|\| ``preStmtExecute()`` \|\| ``execute()`` \|\| ``query``
-\|\| \|\| ``postStmtExecute()`` \|\| ``execute()`` \|\| ``query`` \|\|
-\|\| ``preExecute()`` \|\| ``execute()`` \* \|\| ``query`` \|\| \|\|
-``postExecute()`` \|\| ``execute()`` \* \|\| ``query`` \|\| \|\|
-``preFetch()`` \|\| ``fetch()`` \|\| ``query, data`` \|\| \|\|
-``postFetch()`` \|\| ``fetch()`` \|\| ``query, data`` \|\| \|\|
-``preFetchAll()`` \|\| ``fetchAll()`` \|\| ``query, data`` \|\| \|\|
-``postFetchAll()`` \|\| ``fetchAll()`` \|\| ``query, data`` \|\|
+All of the below listeners are invoked in the :php:class:`Doctrine_Connection`
+and :php:class:`Doctrine_Connection_Statement` classes. And they are all passed
+an instance of :php:class:`Doctrine_Event`.
+
+===================== =================== ===============
+Methods Listens Params
+===================== =================== ===============
+``prePrepare()`` ``prepare()`` ``query``
+``postPrepare()`` ``prepare()`` ``query``
+``preExec()`` ``exec()`` ``query``
+``postExec()`` ``exec()`` ``query,rows``
+``preStmtExecute()`` ``execute()`` ``query``
+``postStmtExecute()`` ``execute()`` ``query``
+``preExecute()`` ``execute()`` ***** ``query``
+``postExecute()`` ``execute()`` ***** ``query``
+``preFetch()`` ``fetch()`` ``query, data``
+``postFetch()`` ``fetch()`` ``query, data``
+``preFetchAll()`` ``fetchAll()`` ``query, data``
+``postFetchAll()`` ``fetchAll()`` ``query, data``
+===================== =================== ===============
.. note::
@@ -254,173 +279,211 @@ similar listener on table level it only gets invoked when the data of
that table is being hydrated.
Consider we have a class called ``User`` with the following fields:
-``first\_name``, ``last_name`` and ``age``. In the following example we
+``first_name``, ``last_name`` and ``age``. In the following example we
create a listener that always builds a generated field called
-``full\_name`` based on ``first\_name`` and ``last_name`` fields.
-
- // test.php
-
-// ... class HydrationListener extends Doctrine\_Record\_Listener {
-public function preHydrate(Doctrine\_Event $event) { $data =
-$event->data;
+``full_name`` based on ``first_name`` and ``last_name`` fields.
::
- $data['full_name'] = $data['first_name'] . ' ' . $data['last_name'];
- $event->data = $data;
- }
+ // test.php
-}
+ // ...
+ class HydrationListener extends Doctrine_Record_Listener
+ {
+ public function preHydrate( Doctrine_Event $event )
+ {
+ $data = $event->data;
+ $data['full_name'] = $data['first_name'] . ' ' . $data['last_name'];
+ $event->data = $data;
+ }
+ }
Now all we need to do is attach this listener to the ``User`` record and
fetch some users:
- // test.php
+::
+
+ // test.php
-// ... $userTable = Doctrine\_Core::getTable('User');
-$userTable->addRecordListener(new HydrationListener());
+ // ...
+ $userTable = Doctrine_Core::getTable('User');
+ $userTable->addRecordListener( new HydrationListener() );
-$q = Doctrine\_Query::create() ->from('User');
+ $q = Doctrine_Query::create()
+ ->from('User');
-$users = $q->execute();
+ $users = $q->execute();
-foreach ($users as $user) { echo $user->full\_name; }
+ foreach ( $users as $user )
+ {
+ echo $user->full_name;
+ }
================
Record Listeners
================
-``Doctrine_Record`` provides listeners very similar to
-``Doctrine_Connection``. You can set the listeners at global,
+:php:class:`Doctrine_Record` provides listeners very similar to
+:php:class:`Doctrine_Connection`. You can set the listeners at global,
connection and table level.
Here is a list of all available listener methods:
-All of the below listeners are invoked in the ``Doctrine_Record`` and
-``Doctrine_Validator`` classes. And they are all passed an instance of
-``Doctrine_Event``.
+All of the below listeners are invoked in the :php:class:`Doctrine_Record` and
+:php:class:`Doctrine_Validator` classes. And they are all passed an instance of
+:php:class:`Doctrine_Event`.
+
+================== ===============================================
+Methods Listens
+================== ===============================================
+``preSave()`` ``save()``
+``postSave()`` ``save()``
+``preUpdate()`` ``save()`` **when the record state is** ``DIRTY``
+``postUpdate()`` ``save()`` **when the record state is** ``DIRTY``
+``preInsert()`` ``save()`` **when the record state is** ``TDIRTY``
+``postInsert()`` ``save()`` **when the record state is** ``TDIRTY``
+``preDelete()`` ``delete()``
+``postDelete()`` ``delete()``
+``preValidate()`` ``validate()``
+``postValidate()`` ``validate()``
+================== ===============================================
-\|\|~ Methods \|\|~ Listens \|\| \|\| ``preSave()`` \|\| ``save()`` \|\|
-\|\| ``postSave()`` \|\| ``save()`` \|\| \|\| ``preUpdate()`` \|\|
-``save()`` when the record state is ``DIRTY`` \|\| \|\| ``postUpdate()``
-\|\| ``save()`` when the record state is ``DIRTY`` \|\| \|\|
-``preInsert()`` \|\| ``save()`` when the record state is ``TDIRTY`` \|\|
-\|\| ``postInsert()`` \|\| ``save()`` when the record state is
-``TDIRTY`` \|\| \|\| ``preDelete()`` \|\| ``delete()`` \|\| \|\|
-``postDelete()`` \|\| ``delete()`` \|\| \|\| ``preValidate()`` \|\|
-``validate()`` \|\| \|\| ``postValidate()`` \|\| ``validate()`` \|\|
Just like with connection listeners there are three ways of defining a
-record listener: by extending ``Doctrine\_Record_Listener``, by
-implementing ``Doctrine\_Record\_Listener_Interface`` or by
-implementing ``Doctrine_Overloadable``.
+record listener: by extending :php:class:`Doctrine_Record_Listener`, by
+implementing :php:class:`Doctrine_Record_Listener_Interface` or by
+implementing :php:class:`Doctrine_Overloadable`.
In the following we'll create a global level listener by implementing
-``Doctrine_Overloadable``:
-
- class Logger implements Doctrine\_Overloadable { public function
-\_\_call($m, $a) { echo 'caught event ' . $m;
+:php:class:`Doctrine_Overloadable`:
::
- // do some logging here...
- }
+ class Logger implements Doctrine_Overloadable
+ {
+ public function __call( $m, $a )
+ {
+ echo 'caught event ' . $m;
-}
+ // do some logging here...
+ }
+ }
Attaching the listener to manager is easy:
- $manager->addRecordListener(new Logger());
+::
+
+ $manager->addRecordListener( new Logger() );
Note that by adding a manager level listener it affects on all
connections and all tables / records within these connections. In the
following we create a connection level listener:
- class Debugger extends Doctrine\_Record\_Listener { public function
-preInsert(Doctrine\_Event $event) { echo 'inserting a record ...'; }
-
::
- public function preUpdate(Doctrine_Event $event)
+ class Debugger extends Doctrine_Record_Listener
{
- echo 'updating a record...';
- }
+ public function preInsert( Doctrine_Event $event )
+ {
+ echo 'inserting a record ...';
+ }
-}
+ public function preUpdate( Doctrine_Event $event )
+ {
+ echo 'updating a record...';
+ }
+ }
Attaching the listener to a connection is as easy as:
- $conn->addRecordListener(new Debugger());
+::
+
+ $conn->addRecordListener( new Debugger() );
Many times you want the listeners to be table specific so that they only
apply on the actions on that given table.
Here is an example:
- class Debugger extends Doctrine\_Record\_Listener { public function
-postDelete(Doctrine\_Event $event) { echo 'deleted ' .
-$event->getInvoker()->id; } }
+::
-Attaching this listener to given table can be done as follows:
+ class Debugger extends Doctrine_Record_Listener
+ {
+ public function postDelete( Doctrine_Event $event )
+ {
+ echo 'deleted ' . $event->getInvoker()->id;
+ }
+ }
- class MyRecord extends Doctrine\_Record { // ...
+Attaching this listener to given table can be done as follows:
::
- public function setUp()
+ class MyRecord extends Doctrine_Record
{
- $this->addListener(new Debugger());
+ // ...
+ public function setUp()
+ {
+ $this->addListener( new Debugger() );
+ }
}
-}
-
============
Record Hooks
============
-All of the below listeners are invoked in the ``Doctrine_Record`` and
-``Doctrine_Validator`` classes. And they are all passed an instance of
-``Doctrine_Event``.
-
-\|\|~ Methods \|\|~ Listens \|\| \|\| ``preSave()`` \|\| ``save()`` \|\|
-\|\| ``postSave()`` \|\| ``save()`` \|\| \|\| ``preUpdate()`` \|\|
-``save()`` when the record state is ``DIRTY`` \|\| \|\| ``postUpdate()``
-\|\| ``save()`` when the record state is ``DIRTY`` \|\| \|\|
-``preInsert()`` \|\| ``save()`` when the record state is ``TDIRTY`` \|\|
-\|\| ``postInsert()`` \|\| ``save()`` when the record state is
-``TDIRTY`` \|\| \|\| ``preDelete()`` \|\| ``delete()`` \|\| \|\|
-``postDelete()`` \|\| ``delete()`` \|\| \|\| ``preValidate()`` \|\|
-``validate()`` \|\| \|\| ``postValidate()`` \|\| ``validate()`` \|\|
+All of the below listeners are invoked in the :php:class:`Doctrine_Record` and
+:php:class:`Doctrine_Validator` classes. And they are all passed an instance of
+:php:class:`Doctrine_Event`.
+
+================== ==================================================
+Methods Listens
+================== ==================================================
+``preSave()`` ``save()``
+``postSave()`` ``save()``
+``preUpdate()`` ``save()`` **when the record state is** ``DIRTY``
+``postUpdate()`` ``save()`` **when the record state is** ``DIRTY``
+``preInsert()`` ``save()`` **when the record state is** ``TDIRTY``
+``postInsert()`` ``save()`` **when the record state is** ``TDIRTY``
+``preDelete()`` ``delete()``
+``postDelete()`` ``delete()``
+``preValidate()`` ``validate()``
+``postValidate()`` ``validate()``
+================== ==================================================
Here is a simple example where we make use of the ``preInsert()`` and
``preUpdate()`` methods:
- class BlogPost extends Doctrine\_Record { public function
-setTableDefinition() { $this->hasColumn('title', 'string', 200);
-$this->hasColumn('content', 'string'); $this->hasColumn('created',
-'date'); $this->hasColumn('updated', 'date'); }
-
::
- public function preInsert($event)
+ class BlogPost extends Doctrine_Record
{
- $this->created = date('Y-m-d', time());
- }
+ public function setTableDefinition()
+ {
+ $this->hasColumn( 'title', 'string', 200 );
+ $this->hasColumn( 'content', 'string' );
+ $this->hasColumn( 'created', 'date' );
+ $this->hasColumn( 'updated', 'date' );
+ }
- public function preUpdate($event)
- {
- $this->updated = date('Y-m-d', time());
- }
+ public function preInsert( $event )
+ {
+ $this->created = date( 'Y-m-d', time() );
+ }
-}
+ public function preUpdate( $event )
+ {
+ $this->updated = date( 'Y-m-d', time() );
+ }
+ }
=========
DQL Hooks
=========
Doctrine allows you to attach record listeners globally, on each
-connection, or on specific record instances. ``Doctrine_Query``
-implements ``preDql\*()`` hooks which are checked for on any attached
+connection, or on specific record instances. :php:class:`Doctrine_Query`
+implements ``preDql*()`` hooks which are checked for on any attached
record listeners and checked for on the model instance itself whenever a
query is executed. The query will check all models involved in the
``from`` part of the query for any hooks which can alter the query that
@@ -428,9 +491,13 @@ invoked the hook.
Here is a list of the hooks you can use with DQL:
-\|\|~ Methods \|\|~ Listens \|\| \|\| ``preDqlSelect()`` \|\| ``from()``
-\|\| \|\| ``preDqlUpdate()`` \|\| ``update()`` \|\| \|\|
-``preDqlDelete()`` \|\| ``delete()`` \|\|
+================== ================
+Methods Listens
+================== ================
+``preDqlSelect()`` ``from()``
+``preDqlUpdate()`` ``update()``
+``preDqlDelete()`` ``delete()``
+================== ================
Below is an example record listener attached directly to the model which
will implement the ``SoftDelete`` functionality for the ``User`` model.
@@ -444,88 +511,99 @@ will implement the ``SoftDelete`` functionality for the ``User`` model.
``$this->actAs('SoftDelete')`` in your ``Doctrine_Record::setUp()``
definition.
- class UserListener extends Doctrine\_EventListener { /\*\* \* Skip the
-normal delete options so we can override it with our own \* \* @param
-Doctrine\_Event $event \* @return void \*/ public function
-preDelete(Doctrine\_Event $event) { $event->skipOperation(); }
-
::
- /**
- * Implement postDelete() hook and set the deleted flag to true
- *
- * @param Doctrine_Event $event
- * @return void
- */
- public function postDelete(Doctrine_Event $event)
+ class UserListener extends Doctrine_EventListener
{
- $name = $this->_options['name'];
- $event->getInvoker()->$name = true;
- $event->getInvoker()->save();
- }
+ /**
+ * Skip the normal delete options so we can override it with our own
+ *
+ * @param Doctrine_Event $event
+ * @return void
+ */
+ public function preDelete( Doctrine_Event $event )
+ {
+ $event->skipOperation();
+ }
- /**
- * Implement preDqlDelete() hook and modify a dql delete query so it updates the deleted flag
- * instead of deleting the record
- *
- * @param Doctrine_Event $event
- * @return void
- */
- public function preDqlDelete(Doctrine_Event $event)
- {
- $params = $event->getParams();
- $field = $params['alias'] . '.deleted';
- $q = $event->getQuery();
- if ( ! $q->contains($field)) {
- $q->from('')->update($params['component'] . ' ' . $params['alias']);
- $q->set($field, '?', array(false));
- $q->addWhere($field . ' = ?', array(true));
+ /**
+ * Implement postDelete() hook and set the deleted flag to true
+ *
+ * @param Doctrine_Event $event
+ * @return void
+ */
+ public function postDelete( Doctrine_Event $event )
+ {
+ $name = $this->_options['name'];
+ $event->getInvoker()->$name = true;
+ $event->getInvoker()->save();
}
- }
- /**
- * Implement preDqlDelete() hook and add the deleted flag to all queries for which this model
- * is being used in.
- *
- * @param Doctrine_Event $event
- * @return void
- */
- public function preDqlSelect(Doctrine_Event $event)
- {
- $params = $event->getParams();
- $field = $params['alias'] . '.deleted';
- $q = $event->getQuery();
- if ( ! $q->contains($field)) {
- $q->addWhere($field . ' = ?', array(false));
+ /**
+ * Implement preDqlDelete() hook and modify a dql delete query so it updates the deleted flag
+ * instead of deleting the record
+ *
+ * @param Doctrine_Event $event
+ * @return void
+ */
+ public function preDqlDelete( Doctrine_Event $event )
+ {
+ $params = $event->getParams();
+ $field = $params['alias'] . '.deleted';
+ $q = $event->getQuery();
+
+ if ( ! $q->contains( $field ) )
+ {
+ $q->from('')->update( $params['component'] . ' ' . $params['alias'] );
+ $q->set( $field, '?', array(false) );
+ $q->addWhere( $field . ' = ?', array(true) );
+ }
}
- }
-}
+ /**
+ * Implement preDqlDelete() hook and add the deleted flag to all queries for which this model
+ * is being used in.
+ *
+ * @param Doctrine_Event $event
+ * @return void
+ */
+ public function preDqlSelect( Doctrine_Event $event )
+ {
+ $params = $event->getParams();
+ $field = $params['alias'] . '.deleted';
+ $q = $event->getQuery();
+
+ if ( ! $q->contains( $field ) )
+ {
+ $q->addWhere( $field . ' = ?', array(false) );
+ }
+ }
+ }
All of the above methods in the listener could optionally be placed in
the user class below. Doctrine will check there for the hooks as well:
- class User extends Doctrine\_Record { // ...
-
::
- public function preDqlSelect()
+ class User extends Doctrine_Record
{
// ...
- }
+ public function preDqlSelect()
+ {
+ // ...
+ }
- public function preDqlUpdate()
- {
- // ...
- }
+ public function preDqlUpdate()
+ {
+ // ...
+ }
- public function preDqlDelete()
- {
- // ...
+ public function preDqlDelete()
+ {
+ // ...
+ }
}
-}
-
In order for these dql callbacks to be checked, you must explicitly turn
them on. Because this adds a small amount of overhead for each query, we
have it off by default. We already enabled this attribute in an earlier
@@ -533,35 +611,52 @@ chapter.
Here it is again to refresh your memory:
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... $manager->setAttribute(Doctrine\_Core::ATTR\_USE\_DQL\_CALLBACKS,
-true);
+ // ...
+ $manager->setAttribute( Doctrine_Core::ATTR_USE_DQL_CALLBACKS, true );
Now when you interact with the User model it will take in to account the
deleted flag:
Delete user through record instance:
- $user = new User(); $user->username = 'jwage'; $user->password =
-'changeme'; $user->save(); $user->delete();
+::
+
+ $user = new User();
+ $user->username = 'jwage';
+ $user->password = 'changeme';
+ $user->save();
+ $user->delete();
.. note::
The above call to ``$user->delete()`` does not actually
delete the record instead it sets the deleted flag to true.
- $q = Doctrine\_Query::create() ->from('User u');
+::
+
+ $q = Doctrine_Query::create()
+ ->from('User u');
-echo $q->getSqlQuery();
+ echo $q->getSqlQuery();
+
+::
- SELECT u.id AS u**id, u.username AS u**username, u.password AS
-u**password, u.deleted AS u**deleted FROM user u WHERE u.deleted = ?
+ SELECT
+ u.id AS u**id,
+ u.username AS u**username,
+ u.password AS u**password,
+ u.deleted AS u**deleted
+ FROM user u
+ WHERE u.deleted = ?
.. note::
Notice how the ``"u.deleted = ?"`` was automatically added
- to the where condition with a parameter value of //true//.
+ to the where condition with a parameter value of **true**.
==================
Chaining Listeners
@@ -572,9 +667,12 @@ more than one listener can be attached for listening the same events.
The following example attaches two listeners for given connection:
In this example ``Debugger`` and ``Logger`` both inherit
-``Doctrine_EventListener``:
+:php:class:`Doctrine_EventListener`:
- $conn->addListener(new Debugger()); $conn->addListener(new Logger());
+::
+
+ $conn->addListener( new Debugger() );
+ $conn->addListener( new Logger() );
================
The Event object
@@ -587,72 +685,94 @@ Getting the Invoker
You can get the object that invoked the event by calling
``getInvoker()``:
- class MyListener extends Doctrine\_EventListener { public function
-preExec(Doctrine\_Event $event) { $event->getInvoker(); //
-Doctrine\_Connection } }
+::
+
+ class MyListener extends Doctrine_EventListener
+ {
+ public function preExec( Doctrine_Event $event )
+ {
+ $event->getInvoker(); // Doctrine_Connection
+ }
+ }
-----------
Event Codes
-----------
-``Doctrine_Event`` uses constants as event codes. Below is the list of
+:php:class:`Doctrine_Event` uses constants as event codes. Below is the list of
all available event constants:
-- ``Doctrine\_Event::CONN_QUERY``
-- ``Doctrine\_Event::CONN_EXEC``
-- ``Doctrine\_Event::CONN_PREPARE``
-- ``Doctrine\_Event::CONN_CONNECT``
-- ``Doctrine\_Event::STMT_EXECUTE``
-- ``Doctrine\_Event::STMT_FETCH``
-- ``Doctrine\_Event::STMT_FETCHALL``
-- ``Doctrine\_Event::TX_BEGIN``
-- ``Doctrine\_Event::TX_COMMIT``
-- ``Doctrine\_Event::TX_ROLLBACK``
-- ``Doctrine\_Event::SAVEPOINT_CREATE``
-- ``Doctrine\_Event::SAVEPOINT_ROLLBACK``
-- ``Doctrine\_Event::SAVEPOINT_COMMIT``
-- ``Doctrine\_Event::RECORD_DELETE``
-- ``Doctrine\_Event::RECORD_SAVE``
-- ``Doctrine\_Event::RECORD_UPDATE``
-- ``Doctrine\_Event::RECORD_INSERT``
-- ``Doctrine\_Event::RECORD_SERIALIZE``
-- ``Doctrine\_Event::RECORD_UNSERIALIZE``
-- ``Doctrine\_Event::RECORD\_DQL_SELECT``
-- ``Doctrine\_Event::RECORD\_DQL_DELETE``
-- ``Doctrine\_Event::RECORD\_DQL_UPDATE``
+- ``Doctrine_Event::CONN_QUERY``
+- ``Doctrine_Event::CONN_EXEC``
+- ``Doctrine_Event::CONN_PREPARE``
+- ``Doctrine_Event::CONN_CONNECT``
+- ``Doctrine_Event::STMT_EXECUTE``
+- ``Doctrine_Event::STMT_FETCH``
+- ``Doctrine_Event::STMT_FETCHALL``
+- ``Doctrine_Event::TX_BEGIN``
+- ``Doctrine_Event::TX_COMMIT``
+- ``Doctrine_Event::TX_ROLLBACK``
+- ``Doctrine_Event::SAVEPOINT_CREATE``
+- ``Doctrine_Event::SAVEPOINT_ROLLBACK``
+- ``Doctrine_Event::SAVEPOINT_COMMIT``
+- ``Doctrine_Event::RECORD_DELETE``
+- ``Doctrine_Event::RECORD_SAVE``
+- ``Doctrine_Event::RECORD_UPDATE``
+- ``Doctrine_Event::RECORD_INSERT``
+- ``Doctrine_Event::RECORD_SERIALIZE``
+- ``Doctrine_Event::RECORD_UNSERIALIZE``
+- ``Doctrine_Event::RECORD_DQL_SELECT``
+- ``Doctrine_Event::RECORD_DQL_DELETE``
+- ``Doctrine_Event::RECORD_DQL_UPDATE``
Here are some examples of hooks being used and the code that is
returned:
- class MyListener extends Doctrine\_EventListener { public function
-preExec(Doctrine\_Event $event) { $event->getCode(); //
-Doctrine\_Event::CONN\_EXEC } }
+::
+
+ class MyListener extends Doctrine_EventListener
+ {
+ public function preExec( Doctrine_Event $event )
+ {
+ $event->getCode(); // Doctrine_Event::CONN_EXEC
+ }
+ }
-class MyRecord extends Doctrine\_Record { public function
-preUpdate(Doctrine\_Event $event) { $event->getCode(); //
-Doctrine\_Event::RECORD\_UPDATE } }
+ class MyRecord extends Doctrine_Record
+ {
+ public function preUpdate( Doctrine_Event $event )
+ {
+ $event->getCode(); // Doctrine_Event::RECORD_UPDATE
+ }
+ }
-------------------
Getting the Invoker
-------------------
The method ``getInvoker()`` returns the object that invoked the given
-event. For example for event ``Doctrine\_Event::CONN_QUERY`` the
-invoker is a ``Doctrine_Connection`` object.
+event. For example for event ``Doctrine_Event::CONN_QUERY`` the
+invoker is a :php:class:`Doctrine_Connection` object.
Here is an example of using the record hook named ``preUpdate()`` that
-is invoked when a ``Doctrine_Record`` instance is saved and an update
+is invoked when a :php:class:`Doctrine_Record` instance is saved and an update
is issued to the database:
- class MyRecord extends Doctrine\_Record { public function
-preUpdate(Doctrine\_Event $event) { $event->getInvoker(); //
-Object(MyRecord) } }
+::
+
+ class MyRecord extends Doctrine_Record
+ {
+ public function preUpdate( Doctrine_Event $event )
+ {
+ $event->getInvoker(); // Object(MyRecord)
+ }
+ }
-------------------
Skip Next Operation
-------------------
-``Doctrine_Event`` provides many methods for altering the execution of
+:php:class:`Doctrine_Event` provides many methods for altering the execution of
the listened method as well as for altering the behavior of the listener
chain.
@@ -660,16 +780,17 @@ For some reason you may want to skip the execution of the listened
method. It can be done as follows (note that ``preExec()`` could be any
listener method):
- class MyListener extends Doctrine\_EventListener { public function
-preExec(Doctrine\_Event $event) { // some business logic, then:
-
::
- $event->skipOperation();
+ class MyListener extends Doctrine_EventListener
+ {
+ public function preExec( Doctrine_Event $event )
+ {
+ // some business logic, then:
+ $event->skipOperation();
+ }
}
-}
-
-----------------
Skip Next Listener
------------------
@@ -677,23 +798,23 @@ Skip Next Listener
When using a chain of listeners you might want to skip the execution of
the next listener. It can be achieved as follows:
- class MyListener extends Doctrine\_EventListener { public function
-preExec(Doctrine\_Event $event) { // some business logic, then:
-
::
- $event->skipNextListener();
+ class MyListener extends Doctrine_EventListener
+ {
+ public function preExec( Doctrine_Event $event )
+ {
+ // some business logic, then:
+ $event->skipNextListener();
+ }
}
-}
-
==========
Conclusion
==========
-Event listeners are a great feature in Doctrine and combined with [doc
-behaviors :name] they can provide some very complex functionality with a
+Event listeners are a great feature in Doctrine and combined with :doc:`behaviors` they can provide some very complex functionality with a
minimal amount of code.
Now we are ready to move on to discuss the best feature in Doctrine for
-improving performance, [doc caching :name].
+improving performance, :doc:`caching`.
69 source/en/manual/extensions.rst
View
@@ -10,29 +10,44 @@ naming, autoloading, etc.
In order to use the extensions you must first configure Doctrine to know
the path to where your extensions live:
- Doctrine\_Core::setExtensionsPath('/path/to/extensions');
+::
+
+ Doctrine_Core::setExtensionsPath( '/path/to/extensions' );
Lets checkout an existing extension from SVN to have a look at it. We'll
have a look at the ``Sortable`` extension which bundles a behavior for
your models which give you up and down sorting capabilities.
- $ svn co
-http://svn.doctrine-project.org/extensions/Sortable/branches/1.2-1.0/
-/path/to/extensions/Sortable
+.. code-block:: sh
+
+ $ svn co http://svn.doctrine-project.org/extensions/Sortable/branches/1.2-1.0/ /path/to/extensions/Sortable
If you have a look at ``/path/to/extensions/Sortable`` you will see a
directory structure that looks like the following:
- Sortable/ lib/ Doctrine/ Template/ Listener/ Sortable.php Sortable.php
-tests/ run.php Template/ SortableTestCase.php
+::
+
+ Sortable/
+ lib/
+ Doctrine/
+ Template/
+ Listener/
+ Sortable.php
+ Sortable.php
+ tests/
+ run.php
+ Template/
+ SortableTestCase.php
To test that the extension will run on your machine you can run the test
suite for the extension. All you need to do is set the ``DOCTRINE_DIR``
environment variable.
- $ export DOCTRINE\_DIR=/path/to/doctrine
+.. code-block:: sh
- .. note::
+ $ export DOCTRINE_DIR=/path/to/doctrine
+
+.. note::
The above path to Doctrine must be the path to the main
folder, not just the lib folder. In order to run the tests it must
@@ -40,18 +55,27 @@ environment variable.
It is possible now to run the tests for the ``Sortable`` extension:
- $ cd /path/to/extensions/Sortable/tests $ php run.php
+.. code-block:: sh
+
+ $ cd /path/to/extensions/Sortable/tests
+ $ php run.php
You should see the tests output the following showing the tests were
successful:
- Doctrine Unit Tests ===================
-Doctrine\_Template\_Sortable\_TestCase.............................................passed
+::
-Tested: 1 test cases. Successes: 26 passes. Failures: 0 fails. Number of
-new Failures: 0 Number of fixed Failures: 0
+ Doctrine Unit Tests
+ ===================
+ Doctrine_Template_Sortable_TestCase.............................................passed
-Tests ran in 1 seconds and used 13024.9414062 KB of memory
+ Tested: 1 test cases.
+ Successes: 26 passes.
+ Failures: 0 fails.
+ Number of new Failures: 0
+ Number of fixed Failures: 0
+
+ Tests ran in 1 seconds and used 13024.9414062 KB of memory
Now if you want to use the extension in your project you will need
register the extension with Doctrine and setup the extension autoloading
@@ -59,15 +83,22 @@ mechanism.
First lets setup the extension autoloading.
- // bootstrap.php
+::
+
+ // bootstrap.php
-// ... spl\_autoload\_register(array('Doctrine', 'extensionsAutoload'));
+ // ...
+ spl_autoload_register( array( 'Doctrine', 'extensionsAutoload' ) );
Now you can register the extension and the classes inside that extension
will be autoloaded.
- $manager->registerExtension('Sortable');
+::
+
+ $manager->registerExtension( 'Sortable' );
+
+.. note::
- **NOTE** If you need to register an extension from a different
+ If you need to register an extension from a different
location you can specify the full path to the extension directory as
- the second argument to the ``registerExtension()`` method.
+ the second argument to the ``registerExtension()`` method.
490 source/en/manual/migrations.rst
View
@@ -15,37 +15,46 @@ Before we learn how to create the migration classes lets take a look at
how we can run migrations so that we can implement them in our Doctrine
test environment in the next section.
-First lets create a new instance of ``Doctrine_Migration`` and pass it
+First lets create a new instance of :php:class:`Doctrine_Migration` and pass it
the path to our migration classes:
- $migration = new Doctrine\_Migration('/path/to/migration\_classes',
-$conn);
+::
+
+ $migration = new Doctrine_Migration( '/path/to/migration_classes', $conn );
.. note::
- Notice the second argument to the ``Doctrine_Migration``
- constructor. You can pass an optional ``Doctrine_Connection``
+ Notice the second argument to the :php:class:`Doctrine_Migration`
+ constructor. You can pass an optional :php:class:`Doctrine_Connection`
instance. If you do not pass the connection for the migration class
to use, it will simply grab the current connection.
Now we can migrate to the latest version by calling the ``migrate()``
method:
- $migration->migrate();
+::
+
+ $migration->migrate();
If you want to migrate to a specific version you can pass an argument to
``migrate()``. For example we can migrate to version 3 from 0:
- $migration->migrate(3);
+::
+
+ $migration->migrate( 3 );
Now you can migrate back to version 0 from 3:
- $migration->migrate(0);
+::
+
+ $migration->migrate( 0 );
If you want to get the current version of the database you can use the
``getCurrentVersion()`` method:
- echo $migration->getCurrentVersion();
+::
+
+ echo $migration->getCurrentVersion();
.. tip::
@@ -73,24 +82,27 @@ script in our Doctrine test environment named ``migrate.php``.
First we need to create a place for our migration classes to be stored
so lets create a directory named ``migrations``:
- $ mkdir migrations
+.. code-block:: sh
+
+ $ mkdir migrations
Now create the ``migrate.php`` script in your favorite editor and place
the following code inside:
- // migrate.php
+::
-require\_once('bootstrap.php');
+ // migrate.php
+ require_once('bootstrap.php');
-$migration = new Doctrine\_Migration('migrations');
-$migration->migrate();
+ $migration = new Doctrine_Migration( 'migrations' );
+ $migration->migrate();
=========================
Writing Migration Classes
=========================
Migration classes consist of a simple class that extends from
-``Doctrine_Migration``. You can define a ``up()`` and ``down()`` method
+:php:class:`Doctrine_Migration`. You can define a ``up()`` and ``down()`` method
that is meant for doing and undoing changes to a database for that
migration version.
@@ -106,59 +118,66 @@ your database starting from version 1.
For the first version lets create a new table named ``migration_test``:
- // migrations/1\_add\_table.php
-
-class AddTable extends Doctrine\_Migration\_Base { public function up()
-{ $this->createTable('migration\_test', array('field1' => array('type'
-=> 'string'))); }
-
::
- public function down()
+ // migrations/1_add_table.php
+ class AddTable extends Doctrine_Migration_Base
{
- $this->dropTable('migration_test');
+ public function up()
+ {
+ $this->createTable( 'migration_test', array( 'field1' => array( 'type' => 'string' ) ) );
+ }
+
+ public function down()
+ {
+ $this->dropTable( 'migration_test' );
+ }
}
-}
-
Now lets create a second version where we add a new column to the table
we added in the previous version:
- // migrations/2\_add\_column.php
-
-class AddColumn extends Doctrine\_Migration\_Base { public function up()
-{ $this->addColumn('migration\_test', 'field2', 'string'); }
-
::
- public function down()
+ // migrations/2_add_column.php
+ class AddColumn extends Doctrine_Migration_Base
{
- $this->removeColumn('migration_test', 'field2');
+ public function up()
+ {
+ $this->addColumn( 'migration_test', 'field2', 'string' );
+ }
+
+ public function down()
+ {
+ $this->removeColumn( 'migration_test', 'field2' );
+ }
}
-}
-
Finally, lets change the type of the ``field1`` column in the table we
created previously:
- // migrations/3\_change\_column.php
-
-class ChangeColumn extends Doctrine\_Migration\_Base { public function
-up() { $this->changeColumn('migration\_test', 'field2', 'integer'); }
-
::
- public function down()
+ // migrations/3_change_column.php
+ class ChangeColumn extends Doctrine_Migration_Base
{
- $this->changeColumn('migration_test', 'field2', 'string');
- }
-
-}
+ public function up()
+ {
+ $this->changeColumn( 'migration_test', 'field2', 'integer' );
+ }
+
+ public function down()
+ {
+ $this->changeColumn( 'migration_test', 'field2', 'string' );
+ }
+ }
Now that we have created the three migration classes above we can run
our ``migrate.php`` script we implemented earlier:
- $ php migrate.php
+.. code-block:: sh
+
+ $ php migrate.php
If you look in the database you will see that we have the table named
``migrate_test`` created and the version number in the
@@ -167,14 +186,19 @@ If you look in the database you will see that we have the table named
If you want to migrate back to where we started you can pass a version
number to the ``migrate()`` method in the ``migrate.php`` script:
- // migrate.php
+::
-// ... $migration = new Doctrine\_Migration('migrations');
-$migration->migrate(0);
+ // migrate.php
+
+ // ...
+ $migration = new Doctrine_Migration( 'migrations' );
+ $migration->migrate( 0 );
Now run the ``migrate.php`` script:
- $ php migrate.php
+.. code-block:: sh
+
+ $ php migrate.php
If you look in the database now, everything we did in the ``up()``
methods has been reversed by the contents of the ``down()`` method.
@@ -190,22 +214,36 @@ database in your migration classes.
Create Table
^^^^^^^^^^^^
- // ... public function up() { $columns = array( 'id' => array( 'type'
-=> 'integer', 'unsigned' => 1, 'notnull' => 1, 'default' => 0 ), 'name'
-=> array( 'type' => 'string', 'length' => 12 ), 'password' => array(
-'type' => 'string', 'length' => 12 ) );
-
::
+ // ...
+ public function up()
+ {
+ $columns = array(
+ 'id' => array(
+ 'type' => 'integer',
+ 'unsigned' => 1,
+ 'notnull' => 1,
+ 'default' => 0
+ ),
+ 'name' => array(
+ 'type' => 'string',
+ 'length' => 12
+ ),
+ 'password' => array(
+ 'type' => 'string',
+ 'length' => 12
+ )
+ );
+
$options = array(
- 'type' => 'INNODB',
- 'charset' => 'utf8'
+ 'type' => 'INNODB',
+ 'charset' => 'utf8'
);
- $this->createTable('table_name', $columns, $options);
+ $this->createTable( 'table_name', $columns, $options );
}
-
-// ...
+ // ...
.. note::
@@ -219,76 +257,122 @@ Create Table
Drop Table
^^^^^^^^^^
- // ... public function down() { $this->dropTable('table\_name'); } //
-...
+::
+
+ // ...
+ public function down()
+ {
+ $this->dropTable( 'table_name' );
+ }
+ // ...
^^^^^^^^^^^^
Rename Table
^^^^^^^^^^^^
- // ... public function up() { $this->renameTable('old\_table\_name',
-'new\_table\_name'); } // ...
+::
+
+ // ...
+ public function up()
+ {
+ $this->renameTable( 'old_table_name', 'new_table_name' );
+ }
+ // ...
^^^^^^^^^^^^^^^^^
Create Constraint
^^^^^^^^^^^^^^^^^
- // ... public function up() { $definition = array( 'fields' => array(
-'username' => array() ), 'unique' => true );
-
::
- $this->createConstraint('table_name', 'constraint_name', $definition);
- }
+ // ...
+ public function up()
+ {
+ $definition = array(
+ 'fields' => array(
+ 'username' => array()
+ ),
+ 'unique' => true
+ );
-// ...
+ $this->createConstraint( 'table_name', 'constraint_name', $definition );
+ }
+ // ...
^^^^^^^^^^^^^^^
Drop Constraint
^^^^^^^^^^^^^^^
-**Now the opposite ``down()`` would look like the following:**
+**Now the opposite** ``down()`` **would look like the following:**
+
+::
- // ... public function down() { $this->dropConstraint('table\_name',
-'constraint\_name'); } // ...
+ // ...
+ public function down()
+ {
+ $this->dropConstraint( 'table_name', 'constraint_name' );
+ }
+ // ...
^^^^^^^^^^^^^^^^^^
Create Foreign Key
^^^^^^^^^^^^^^^^^^
- // ... public function up() { $definition = array( 'local' =>
-'email\_id', 'foreign' => 'id', 'foreignTable' => 'email', 'onDelete' =>
-'CASCADE' );
-
::
- $this->createForeignKey('table_name', 'email_foreign_key', $definition);
- }
+ // ...
+ public function up()
+ {
+ $definition = array(
+ 'local' => 'email_id',
+ 'foreign' => 'id',
+ 'foreignTable' => 'email',
+ 'onDelete' => 'CASCADE',
+ );
-// ...
+ $this->createForeignKey( 'table_name', 'email_foreign_key', $definition );
+ }
+ // ...
The valid options for the ``$definition`` are:
-\|\|~ Name \|\|~ Description \|\| \|\| name \|\| Optional constraint
-name \|\| \|\| local \|\| The local field(s) \|\| \|\| foreign \|\| The
-foreign reference field(s) \|\| \|\| foreignTable \|\| The name of the
-foreign table \|\| \|\| onDelete \|\| Referential delete action \|\|
-\|\| onUpdate \|\| Referential update action \|\| \|\| deferred \|\|
-Deferred constraint checking \|\|
+============ ==============================
+Name Description
+============ ==============================
+name Optional constraint name
+local The local field(s)
+foreign The foreign reference field(s)
+foreignTable The name of the foreign table
+onDelete Referential delete action
+onUpdate Referential update action
+deferred Deferred constraint checking
+============ ==============================
^^^^^^^^^^^^^^^^
Drop Foreign Key
^^^^^^^^^^^^^^^^
- // ... public function down() { $this->dropForeignKey('table\_name',
-'email\_foreign\_key'); } // ...
+::
+
+ // ...
+ public function down()
+ {
+ $this->dropForeignKey( 'table_name', 'email_foreign_key' );
+ }
+ // ...
^^^^^^^^^^
Add Column
^^^^^^^^^^
- // ... public function up() { $this->addColumn('table\_name',
-'column\_name', 'string', $length, $options); } // ...
+::
+
+ // ...
+ public function up()
+ {
+ $this->addColumn( 'table_name', 'column_name', 'string', $length, $options );
+ }
+ // ...
^^^^^^^^^^^^^
Rename Column
@@ -300,8 +384,14 @@ Rename Column
operation. An exception is thrown if you try and rename a column
when using a sqlite connection.
- // ... public function up() { $this->renameColumn('table\_name',
-'old\_column\_name', 'new\_column\_name'); } // ...
+::
+
+ // ...
+ public function up()
+ {
+ $this->renameColumn( 'table_name', 'old_column_name', 'new_column_name' );
+ }
+ // ...
^^^^^^^^^^^^^
Change Column
@@ -309,16 +399,28 @@ Change Column
**Change any aspect of an existing column:**
- // ... public function up() { $options = array('length' => 1);
-$this->changeColumn('table\_name', 'column\_name', 'tinyint', $options);
-} // ...
+::
+
+ // ...
+ public function up()
+ {
+ $options = array( 'length' => 1 );
+ $this->changeColumn( 'table_name', 'column_name', 'tinyint', $options );
+ }
+ // ...
^^^^^^^^^^^^^
Remove Column
^^^^^^^^^^^^^
- // ... public function up() { $this->removeColumn('table\_name',
-'column\_name'); } // ...
+::
+
+ // ...
+ public function up()
+ {
+ $this->removeColumn( 'table_name', 'column_name' );
+ }
+ // ...
^^^^^^^^^^^^^^^^^^^^^^
Irreversible Migration
@@ -329,33 +431,51 @@ Irreversible Migration
Sometimes you may perform some operations in the ``up()``
method that cannot be reversed. For example if you remove a column
from a table. In this case you need to throw a new
- ``Doctrine\_Migration_IrreversibleMigrationException`` exception.
+ :php:class:`Doctrine_Migration_IrreversibleMigrationException` exception.
- // ... public function down() { throw new
-Doctrine\_Migration\_IrreversibleMigrationException( 'The remove column
-operation cannot be undone!' ); } // ...
+::
+
+ // ...
+ public function down()
+ {
+ throw new Doctrine_Migration_IrreversibleMigrationException( 'The remove column operation cannot be undone!' );
+ }
+ // ...
^^^^^^^^^
Add Index
^^^^^^^^^
- // ... public function up() { $options = array('fields' => array(
-'username' => array( 'sorting' => 'ascending' ), 'last\_login' =>
-array()));
-
::
- $this->addIndex('table_name', 'index_name', $options)
- }
+ // ...
+ public function up()
+ {
+ $options = array(
+ 'fields' => array(
+ 'username' => array(
+ 'sorting' => 'ascending'
+ ),
+ 'last_login' => array()
+ )
+ );
-// ...
+ $this->addIndex( 'table_name', 'index_name', $options );
+ }
+ // ...
^^^^^^^^^^^^
Remove Index
^^^^^^^^^^^^
- // ... public function down() { $this->removeIndex('table\_name',
-'index\_name'); } // ...
+::
+
+ // ...
+ public function down()
+ {
+ $this->removeIndex( 'table_name', 'index_name' );
+ }
+ // ...
-------------------
Pre and Post Hooks
@@ -368,28 +488,33 @@ We have hooks in place for this named ``preUp()``, ``postUp()``,
``preDown()``, and ``postDown()``. Define these methods and they will be
triggered:
- // migrations/1\_add\_table.php
-
-class AddTable extends Doctrine\_Migration\_Base { public function up()
-{ $this->createTable('migration\_test', array('field1' => array('type'
-=> 'string'))); }
-
::
- public function postUp()
+ // migrations/1_add_table.php
+ class AddTable extends Doctrine_Migration_Base
{
- $migrationTest = new MigrationTest();
- $migrationTest->field1 = 'Initial record created by migrations';
- $migrationTest->save();
+ public function up()
+ {
+ $this->createTable( 'migration_test', array(
+ 'field1' => array(
+ 'type' => 'string'
+ )
+ );
+ }
+
+ public function postUp()
+ {
+ $migrationTest = new MigrationTest();
+ $migrationTest->field1 = 'Initial record created by migrations';
+ $migrationTest->save();
+ }
+
+ public function down()
+ {
+ $this->dropTable( 'migration_test' );
+ }
}
- public function down()
- {
- $this->dropTable('migration_test');
- }
-
-}
-
.. note::
The above example assumes you have created and made
@@ -398,17 +523,28 @@ class AddTable extends Doctrine\_Migration\_Base { public function up()
``MigrationTest`` model can be used. We have provided the definition
of this model below.
- // models/MigrationTest.php
+::
-class MigrationTest extends Doctrine\_Record { public function
-setTableDefinition() { $this->hasColumn('field1', 'string'); } }
+ // models/MigrationTest.php
+ class MigrationTest extends Doctrine_Record
+ {
+ public function setTableDefinition()
+ {
+ $this->hasColumn( 'field1', 'string' );
+ }
+ }
Here is the same example in YAML format. You can read more about YAML in
-the [doc yaml-schema-files :name] chapter:
+the :doc:`yaml-schema-files` chapter:
- # schema.yml
+.. code-block:: yaml
-MigrationTest: columns: field1: string
+ ---
+ # schema.yml
+
+ MigrationTest:
+ columns:
+ field1: string
-------------------
Up/Down Automation
@@ -427,21 +563,30 @@ first argument of functions like ``column``, ``table``, etc.
Here is an example where we automate the adding and removing of a column
- class MigrationTest extends Doctrine\_Migration\_Base { public function
-migrate($direction) { :code:`this->column(`\ direction, 'table\_name',
-'column\_name', 'string', '255'); } }
+::
+
+ class MigrationTest extends Doctrine_Migration_Base
+ {
+ public function migrate( $direction )
+ {
+ $this->column( $direction, 'table_name', 'column_name', 'string', '255' );
+ }
+ }
Now when we run up with the above migration, the column will be added
and when we run down the column will be removed.
Here is a list of the following migration methods that can be automated:
-\|\|~ Automate Method Name \|\|~ Automates \|\| \|\| table() \|\|
-createTable()/dropTable() \|\| \|\| constraint() \|\|
-createConstraint()/dropConstraint() \|\| \|\| foreignKey() \|\|
-createForeignKey()/dropForeignKey() \|\| \|\| column() \|\|
-addColumn()/removeColumn() \|\| \|\| index() \|\|
-addInex()/removeIndex() \|\|
+==================== =======================================
+Automate Method Name Automates
+==================== =======================================
+**table()** **createTable()/dropTable()**
+**constraint()** **createConstraint()/dropConstraint()**
+**foreignKey()** **createForeignKey()/dropForeignKey()**
+**column()** **addColumn()/removeColumn()**
+**index()** **addInex()/removeIndex()**
+==================== =======================================
----------------------
Generating Migrations
@@ -460,7 +605,9 @@ From Database
To generate a set of migrations from the existing database connections
it is simple, just use ``Doctrine_Core::generateMigrationsFromDb()``.
- Doctrine\_Core::generateMigrationsFromDb('/path/to/migration/classes');
+::
+
+ Doctrine_Core::generateMigrationsFromDb( '/path/to/migration/classes' );
^^^^^^^^^^^^^^^^^^^^
From Existing Models
@@ -470,9 +617,9 @@ To generate a set of migrations from an existing set of models it is
just as simple as from a database, just use
``Doctrine_Core::generateMigrationsFromModels()``.
+::
-Doctrine\_Core::generateMigrationsFromModels('/path/to/migration/classes',
-'/path/to/models');
+ Doctrine_Core::generateMigrationsFromModels( '/path/to/migration/classes', '/path/to/models' );
^^^^^^^^^
Diff Tool
@@ -487,50 +634,63 @@ changes.
The diff tool is simple to use. It accepts a "from" and a "to" and they
can be one of the following:
-- Path to yaml schema files
-- Name of an existing database connection
-- Path to an existing set of models
+ - Path to yaml schema files
+ - Name of an existing database connection
+ - Path to an existing set of models
A simple example would be to create two YAML schema files, one named
``schema1.yml`` and another named ``schema2.yml``.
The ``schema1.yml`` contains a simple ``User`` model:
- # schema1.yml
+.. code-block:: yaml
+
+ ---
+ # schema1.yml
-User: columns: username: string(255) password: string(255)
+ User:
+ columns:
+ username: string(255)
+ password: string(255)
Now imagine we modify the above schema and want to add a
``email_address`` column:
- # schema1.yml
+.. code-block:: yaml
-User: columns: username: string(255) password: string(255)
-email\_address: string(255)
+ ---
+ # schema1.yml
+
+ User:
+ columns:
+ username: string(255)
+ password: string(255)
+ email_address: string(255)
Now we can easily generate a migration class which will add the new
column to our database:
+::
-Doctrine\_Core::generateMigrationsFromDiff('/path/to/migration/classes',
-'/path/to/schema1.yml', '/path/to/schema2.yml');
-
-This will produce a file at the path
-``/path/to/migration/classes/1236199329_version1.php``
+ Doctrine_Core::generateMigrationsFromDiff( '/path/to/migration/classes', '/path/to/schema1.yml', '/path/to/schema2.yml' );
- class Version1 extends Doctrine\_Migration\_Base { public function up()
-{ $this->addColumn('user', 'email\_address', 'string', '255', array ());
-}
+This will produce a file at the path ``/path/to/migration/classes/1236199329_version1.php``
::
- public function down()
+ class Version1 extends Doctrine_Migration_Base
{
- $this->removeColumn('user', 'email_address');
+ public function up()
+ {
+ $this->addColumn( 'user', 'email_address', 'string', '255', array() );
+ }
+
+ public function down()
+ {
+ $this->removeColumn( 'user', 'email_address' );
+ }
}
-}
-
Now you can easily migrate your database and add the new column!
==========
@@ -544,4 +704,4 @@ schema.
Migrations are the last feature of Doctrine that we will discuss in this
book. The final chapters will discuss some other topics that will help
you be a better Doctrine developers on a day-to-day basis. First lets
-discuss some of the other [doc utilities :name] that Doctrine provides.
+discuss some of the other :doc:`utilities` that Doctrine provides.
233 source/en/manual/unit-testing.rst
View
@@ -3,7 +3,7 @@ Unit Testing
************
Doctrine is programmatically tested using UnitTests. You can read more
-about unit testing [http://en.wikipedia.org/wiki/Unit\_testing here] on
+about unit testing `here <http://en.wikipedia.org/wiki/Unit_testing>`_ on
Wikipedia.
=============
@@ -13,16 +13,28 @@ Running tests
In order to run the tests that come with doctrine you need to check out
the entire project, not just the lib folder.
- $ svn co http://svn.doctrine-project.org/branches/1.2
-/path/to/co/doctrine
+.. code-block:: sh
+
+ $ svn co http://svn.doctrine-project.org/branches/1.2 /path/to/co/doctrine
Now change directory to the checked out copy of doctrine.
- $ cd /path/to/co/doctrine
+.. code-block:: sh
+
+ $ cd /path/to/co/doctrine
You should see the following files and directories listed.
- CHANGELOG COPYRIGHT lib/ LICENSE package.xml tests/ tools/ vendor/
+::
+
+ CHANGELOG
+ COPYRIGHT
+ lib/
+ LICENSE
+ package.xml
+ tests/
+ tools/
+ vendor/
.. tip::
@@ -42,7 +54,10 @@ To run tests on the command line, you must have php-cli installed.
Navigate to the ``/path/to/co/doctrine/tests`` folder and execute the
``run.php`` script:
- $ cd /path/to/co/doctrine/tests $ php run.php
+.. code-block:: sh
+
+ $ cd /path/to/co/doctrine/tests
+ $ php run.php
This will print out a progress bar as it is running all the unit tests.
When it is finished it will report to you what has passed and failed.
@@ -51,11 +66,15 @@ The CLI has several options available for running specific tests, groups
of tests or filtering tests against class names of test suites. Run the
following command to check out these options.
- $ php run.php -help
+.. code-block:: sh
+
+ $ php run.php -help
You can run an individual group of tests like this:
- $ php run.php --group data\_dict
+.. code-block:: sh
+
+ $ php run.php --group data_dict
-------
Browser
@@ -67,10 +86,12 @@ variables.
For example:
-- ``http://localhost/doctrine/tests/run.php``
-- ``http://localhost/doctrine/tests/run.php?filter=Limit&group[]=query&group[]=record``
+- `http://localhost/doctrine/tests/run.php <http://localhost/doctrine/tests/run.php>`_
+- `http://localhost/doctrine/tests/run.php?filter=Limit&group[]=query&group[]=record <http://localhost/doctrine/tests/run.php?filter=Limit&group[]=query&group[]=record>`_
+
+.. caution::
- **CAUTION** Please note that test results may very depending on your
+ Please note that test results may very depending on your
environment. For example if ``php.ini`` ``apc.enable_cli`` is set
to 0 then some additional tests may fail.
@@ -81,41 +102,52 @@ Writing Tests
When writing your test case, you can copy ``TemplateTestCase.php`` to
start off. Here is a sample test case:
- class Doctrine\_Sample\_TestCase extends Doctrine\_UnitTestCase {
-public function prepareTables() { $this->tables[] = "MyModel1";
-$this->tables[] = "MyModel2"; parent::prepareTables(); }
-
::
- public function prepareData()
+ class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
- $this->myModel = new MyModel1();
- //$this->myModel->save();
+ public function prepareTables()
+ {
+ $this->tables[] = "MyModel1";
+ $this->tables[] = "MyModel2";
+
+ parent::prepareTables();
+ }
+
+ public function prepareData()
+ {
+ $this->myModel = new MyModel1();
+ //$this->myModel->save();
+ }
+
+ public function testInit()
+ {
+
+ }
+
+ // This produces a failing test
+ public function testTest()
+ {
+ $this->assertTrue( $this->myModel->exists() );
+ $this->assertEqual( 0, 1 );
+ $this->assertIdentical( 0, '0' );
+ $this->assertNotEqual( 1, 2 );
+ $this->assertTrue( ( 5 < 1 ) );
+ $this->assertFalse( (1 > 2 ) );
+ }
}
- public function testInit()
+ class Model1 extends Doctrine_Record
{
-
}
- // This produces a failing test
- public function testTest()
+ class Model2 extends Doctrine_Record
{
- $this->assertTrue($this->myModel->exists());
- $this->assertEqual(0, 1);
- $this->assertIdentical(0, '0');
- $this->assertNotEqual(1, 2);
- $this->assertTrue((5 < 1));
- $this->assertFalse((1 > 2));
}
-}
-
-class Model1 extends Doctrine\_Record { }
-
-class Model2 extends Doctrine\_Record { }
+.. note::
- **NOTE** The model definitions can be included directly in the test
+ The model definitions can be included directly in the test
case file or they can be put in
``/path/to/co/doctrine/tests/models`` and they will be autoloaded
for you.
@@ -123,7 +155,9 @@ class Model2 extends Doctrine\_Record { }
Once you are finished writing your test be sure to add it to ``run.php``
like the following.
- $test->addTestCase(new Doctrine\_Sample\_TestCase());
+::
+
+ $test->addTestCase( new Doctrine_Sample_TestCase() );
Now when you execute run.php you will see the new failure reported to
you.
@@ -139,14 +173,18 @@ the ``/path/to/co/doctrine/tests/Ticket/`` folder.
You can create a new ticket test case easily from the CLI:
- $ php run.php --ticket 9999
+.. code-block:: sh
+
+ $ php run.php --ticket 9999
If the ticket number 9999 doesn't already exist then the blank test case
-class will be generated for you at
-``/path/to/co/doctrine/tests/Ticket/9999TestCase.php``.
+class will be generated for you at ``/path/to/co/doctrine/tests/Ticket/9999TestCase.php``.
+
+::
- class Doctrine\_Ticket\_9999\_TestCase extends Doctrine\_UnitTestCase {
-}
+ class Doctrine_Ticket_9999_TestCase extends Doctrine_UnitTestCase
+ {
+ }
-------------------
Methods for testing
@@ -156,15 +194,27 @@ Methods for testing
Assert Equal
^^^^^^^^^^^^
- // ... public function test1Equals1() { $this->assertEqual(1, 1); } //
-...
+::
+
+ // ...
+ public function test1Equals1()
+ {
+ $this->assertEqual( 1, 1 );
+ }
+ // ...
^^^^^^^^^^^^^^^^
Assert Not Equal
^^^^^^^^^^^^^^^^
- // ... public function test1DoesNotEqual2() { $this->assertNotEqual(1,
-2); } // ...
+::
+
+ // ...
+ public function test1DoesNotEqual2()
+ {
+ $this->assertNotEqual( 1, 2 );
+ }
+ // ...
^^^^^^^^^^^^^^^^
Assert Identical
@@ -174,10 +224,18 @@ The ``assertIdentical()`` method is the same as the ``assertEqual()``
except that its logic is stricter and uses the ``===`` for comparing the
two values.
- // ... public function testAssertIdentical() {
-$this->assertIdentical(1, '1'); } // ...
+::
+
+ // ...
+ public function testAssertIdentical()
+ {
+ $this->assertIdentical( 1, '1' );
+ }
+ // ...
+
+.. note::
- **NOTE** The above test would fail obviously because the first
+ The above test would fail obviously because the first
argument is the number 1 casted as PHP type integer and the second
argument is the number 1 casted as PHP type string.
@@ -185,15 +243,27 @@ $this->assertIdentical(1, '1'); } // ...
Assert True
^^^^^^^^^^^
- // ... public function testAssertTrue() { $this->assertTrue(5 > 2); }