++ Validators ++ View ++ Profiler +++ Introduction {{Doctrine_Connection_Profiler}} is an eventlistener for {{Doctrine_Connection}}. It provides flexible query profiling. Besides the SQL strings the query profiles include elapsed time to run the queries. This allows inspection of the queries that have been performed without the need for adding extra debugging code to model classes. {{Doctrine_Connection_Profiler}} can be enabled by adding it as an eventlistener for {{Doctrine_Connection}}. $conn = Doctrine_Manager::connection($dsn); $profiler = new Doctrine_Connection_Profiler(); $conn->setListener($profiler); +++ Basic usage Perhaps some of your pages is loading slowly. The following shows how to build a complete profiler report from the connection: $totalTime = $profiler->getTotalElapsedSecs(); $queryCount = $profiler->getTotalNumQueries(); $longestTime = 0; $longestQuery = null; foreach ($profiler->getQueryProfiles() as $query) { if ($query->getElapsedSecs() > $longestTime) { $longestTime = $query->getElapsedSecs(); $longestQuery = $query->getQuery(); } } echo 'Executed ' . $queryCount . ' queries in ' . $totalTime . ' seconds' . "\n"; echo 'Average query length: ' . $totalTime / $queryCount . ' seconds' . "\n"; echo 'Queries per second: ' . $queryCount / $totalTime . "\n"; echo 'Longest query length: ' . $longestTime . "\n"; echo 'Longest query: ' . $longestQuery . "\n"; +++ Advanced usage ++ Locking Manager ++ Connection Profiler ++ AuditLog and versioning Doctrine_AuditLog provides a full versioning solution. Lets say we have a NewsItem class that we want to be versioned. This functionality can be applied by simply adding $this->actAs('Versionable') into your record setup. class NewsItem extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('title', 'string', 200); $this->hasColumn('content', 'string'); // the versioning plugin needs version column $this->hasColumn('version', 'integer'); } public function setUp() { $this->actAs('Versionable'); } } Now when we have defined this record to be versionable, Doctrine does internally the following things: * It creates a class called NewsItemVersion on-the-fly, the table this record is pointing at is news_item_version * Everytime a NewsItem object is deleted / updated the previous version is stored into news_item_version * Everytime a NewsItem object is updated its version number is increased. +++ Using versioning $newsItem = new NewsItem(); $newsItem->title = 'No news is good news'; $newsItem->content = 'All quiet on the western front'; $newsItem->save(); $newsItem->version; // 1 $newsItem->title = 'A different title'; $newsItem->save(); $newsItem->version; // 2 +++ Reverting changes Doctrine_Record provides a method called revert() which can be used for reverting to specified version. Internally Doctrine queries the version table and fetches the data for given version. If the given version is not found a Doctrine_Record_Exception is being thrown. $newsItem->revert(1); $newsItem->title; // No news is good news +++ Advanced usage There are many options for the versioning plugin. Sometimes you may want to use other version column than 'version'. This can be achieved by giving the options parameter to actAs() method. class NewsItem extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('title', 'string', 200); $this->hasColumn('content', 'string'); // the versioning plugin needs version column $this->hasColumn('news_version', 'integer'); } public function setUp() { $this->actAs('Versionable', array('versionColumn' => 'news_version')); } } You can also control the name of the versioning record and the name of the version table with option attributes 'className' and 'tableName'. ++ Hook ++ Soft-delete Soft-delete is a very simple plugin for achieving the following behaviour: when a record is deleted its not removed from database. Usually the record contains some special field like 'deleted' which tells the state of the record (deleted or alive). The following code snippet shows what you need in order to achieve this kind of behaviour. Notice how we define two event hooks: preDelete and postDelete. Also notice how the preDelete hook skips the actual delete-operation with skipOperation() call. For more info about the event hooks see the Event listener section. class SoftDeleteTest extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('name', 'string', null, array('primary' => true)); $this->hasColumn('deleted', 'boolean', 1); } public function preDelete($event) { $event->skipOperation(); } public function postDelete($event) { $this->deleted = true; $this->save(); } } Now lets put the plugin in action: // save a new record $record = new SoftDeleteTest(); $record->name = 'new record'; $record->save(); $record->delete(); var_dump($record->deleted); // true