+++ Introduction

{{Doctrine_Db}} is a wrapper for PDO database object. Why should you consider using {{Doctrine_Db}} instead of PDO? 

# It provides efficient eventlistener architecture, hence its easy to add new aspects to existing methods like on-demand-caching
# {{Doctrine_Db}} lazy-connects database. Creating an instance of {{Doctrine_Db}} doesn't directly connect database, hence {{Doctrine_Db}} fits perfectly for application using for example page caching.
# It has many short cuts for commonly used fetching methods like {{Doctrine_Db::fetchOne()}}.
# Supports PEAR-like data source names as well as PDO data source names.


+++ Connecting to a database


{{Doctrine_Db}} allows both PEAR-like DSN (data source name) as well as PDO like DSN as constructor parameters.

Getting an instance of {{Doctrine_Db}} using PEAR-like DSN:

<code type="php">
// using PEAR like dsn for connecting pgsql database

$dbh = new Doctrine_Db('pgsql://root:password@localhost/mydb');

// using PEAR like dsn for connecting mysql database

$dbh = new Doctrine_Db('mysql://root:password@localhost/test');
</code>

Getting an instance of {{Doctrine_Db}} using PDO-like DSN (PDO mysql driver):

<code type="php">
$dbh = new Doctrine_Db('mysql:host=localhost;dbname=test', 
                        $user, $pass);
</code>

Getting an instance of {{Doctrine_Db}} using PDO-like DSN (PDO sqlite with memory tables):

<code type="php">
$dbh = new Doctrine_Db('sqlite::memory:');
</code>

Handling connection errors:

<code type="php">
try {
   $dbh = new Doctrine_Db('mysql:host=localhost;dbname=test', 
                           $user, $pass);
   foreach ($dbh->query('SELECT * FROM foo') as $row) {
     print_r($row);
   }
   $dbh = null;
} catch (PDOException $e) {
   print 'Error!: ' . $e->getMessage() . '
';
   die();
}
</code>


+++ Using event listeners

{{Doctrine_Db}} has a pluggable event listener architecture. It provides before and after listeners for all relevant methods. Every listener method takes one parameter: a {{Doctrine_Db_Event}} object, which holds info about the occurred event.

Every listener object must either implement the {{Doctrine_Db_EventListener_Interface}} or {{Doctrine_Overloadable}} interface. Using {{Doctrine_Overloadable}} interface only requires you to implement {{__call()}} which is then used for listening all the events.  

<code type="php">
class OutputLogger extends Doctrine_Overloadable {
    public function __call($m, $a) {
        print $m . ' called!';
    }
}
</code>

For convience you may want to make your listener class extend {{Doctrine_Db_EventListener}} which has empty listener methods, hence allowing you not to define all the listener methods by hand. The following listener, 'MyLogger', is used for listening only {{onPreQuery}} and {{onQuery}} methods.

<code type="php">
class MyLogger extends Doctrine_Db_EventListener {
    public function onPreQuery(Doctrine_Db_Event $event) {
        print 'database is going to be queried!';
    }
    public function onQuery(Doctrine_Db_Event $event) {
        print 'executed: ' . $event->getQuery();
    }
}
</code>

Now the next thing we need to do is bind the eventlistener objects to our database handler.

<code type="php">
// using PDO dsn for connecting sqlite memory table

$dbh = Doctrine_Db::getConnection('sqlite::memory:');

class MyLogger extends Doctrine_Db_EventListener {
    public function onPreQuery(Doctrine_Db_Event $event) {
        print "database is going to be queried!";
    }
    public function onQuery(Doctrine_Db_Event $event) {
        print "executed: " . $event->getQuery();
    }
}

$dbh->setListener(new MyLogger());

$dbh->query("SELECT * FROM foo"); 
// prints:
// database is going to be queried
// executed: SELECT * FROM foo


class MyLogger2 extends Doctrine_Overloadable {
    public function __call($m, $a) {
        print $m." called!";
    }
}

$dbh->setListener(new MyLogger2());

$dbh->exec("DELETE FROM foo");
// prints:
// onPreExec called!
// onExec called!
</code>


+++ Chaining listeners

{{Doctrine_Db}} supports event listener chaining. It means multiple listeners can be attached for 
listening the events of a single instance of {{Doctrine_Db}}. 

For example you might want to add different aspects to your {{Doctrine_Db}} instance on-demand. These aspects may include caching, query profiling etc.

<code type="php">

// using PDO dsn for connecting sqlite memory table

$dbh = Doctrine_Db::getConnection('sqlite::memory:');

class Counter extends Doctrine_Db_EventListener {
    private $queries = 0;

    public function onQuery(Doctrine_Db_Event $event) {
        $this->queries++;
    }
    public function count() {
        return count($this->queries);
    }
}
class OutputLogger extends Doctrine_Overloadable {
    public function __call($m, $a) {
        print $m." called!";
    }
}
$counter = new Counter();

$dbh->addListener($counter);
$dbh->addListener(new OutputLogger());

$dbh->query("SELECT * FROM foo"); 
// prints:
// onPreQuery called!
// onQuery called!

print $counter->count(); // 1

</code>