Author: romanb
Date: 2008-07-04 17:32:19 +0100 (Fri, 04 Jul 2008)
New Revision: 4628
Modified:
trunk/lib/Doctrine/ClassMetadata.php
trunk/lib/Doctrine/Collection.php
trunk/lib/Doctrine/Configuration.php
trunk/lib/Doctrine/Connection.php
trunk/lib/Doctrine/Connection/Mock.php
trunk/lib/Doctrine/Connection/Mysql.php
trunk/lib/Doctrine/Connection/Sqlite.php
trunk/lib/Doctrine/Connection/UnitOfWork.php
trunk/lib/Doctrine/ConnectionFactory.php
trunk/lib/Doctrine/EntityManager.php
trunk/lib/Doctrine/EntityManagerFactory.php
trunk/lib/Doctrine/EntityPersister/Standard.php
trunk/lib/Doctrine/EventListener.php
trunk/lib/Doctrine/EventManager.php
trunk/lib/Doctrine/Exception.php
trunk/lib/Doctrine/HydratorNew.php
trunk/lib/Doctrine/Manager.php
trunk/lib/Doctrine/Query.php
trunk/lib/Doctrine/Query/Abstract.php
trunk/lib/Doctrine/Query/Exception.php
trunk/lib/Doctrine/Sequence.php
trunk/lib/Doctrine/Transaction.php
trunk/tests/Orm/Query/DqlGenerationTest.php
trunk/tests/Orm/UnitOfWorkTest.php
trunk/tests/lib/Doctrine_TestUtil.php
Log:
The usual 2.0 refactoring/implementation commit.
Modified: trunk/lib/Doctrine/ClassMetadata.php
===================================================================
--- trunk/lib/Doctrine/ClassMetadata.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/ClassMetadata.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -141,6 +141,13 @@
protected $_mappedEmbeddedValues = array();
/**
+ * Enter description here...
+ *
+ * @var array
+ */
+ protected $_attributes = array('loadReferences' => true);
+
+ /**
* An array of field names. used to look up field names from column names.
* Keys are column names and values are field names.
* This is the reverse lookup map of $_columnNames.
@@ -148,13 +155,6 @@
* @var array
*/
protected $_fieldNames = array();
-
- /**
- * Enter description here...
- *
- * @var unknown_type
- */
- protected $_attributes = array('loadReferences' => true);
/**
* An array of column names. Keys are field names and values column names.
@@ -166,11 +166,20 @@
protected $_columnNames = array();
/**
+ * Map that maps lowercased column names to field names.
+ * Mainly used during hydration because Doctrine enforces PDO_CASE_LOWER
+ * for portability.
+ *
+ * @var array
+ */
+ protected $_lcColumnToFieldNames = array();
+
+ /**
* Enter description here...
*
* @var unknown_type
*/
- protected $_subclassFieldNames = array();
+ //protected $_subclassFieldNames = array();
/**
* Caches enum value mappings. Keys are field names and values arrays with the
@@ -192,7 +201,7 @@
*
* @var integer
*/
- protected $_columnCount;
+ //protected $_columnCount;
/**
* Whether or not this class has default values.
@@ -540,11 +549,9 @@
}
/**
- * getFieldName
+ * Gets the field name for a column name.
+ * If no field name can be found the column name is returned.
*
- * returns the field name for a column name
- * if no field name can be found the column name is returned.
- *
* @param string $columnName column name
* @return string column alias
*/
@@ -555,28 +562,57 @@
}
/**
+ * Gets the field name for a completely lowercased column name.
+ * Mainly used during hydration.
+ *
+ * @param string $lcColumnName
+ * @return string
+ */
+ public function getFieldNameForLowerColumnName($lcColumnName)
+ {
+ return isset($this->_lcColumnToFieldNames[$lcColumnName]) ?
+ $this->_lcColumnToFieldNames[$lcColumnName] : $lcColumnName;
+ }
+
+ public function hasLowerColumn($lcColumnName)
+ {
+ return isset($this->_lcColumnToFieldNames[$lcColumnName]);
+ }
+
+ /**
+ * Looks up the field name for a (lowercased) column name.
*
+ * This is mostly used during hydration, because we want to make the
+ * conversion to field names while iterating over the result set for best
+ * performance. By doing this at that point, we can avoid re-iterating over
+ * the data just to convert the column names to field names.
+ *
+ * However, when this is happening, we don't know the real
+ * class name to instantiate yet (the row data may target a sub-type), hence
+ * this method looks up the field name in the subclass mappings if it's not
+ * found on this class mapping.
+ * This lookup on subclasses is costly but happens only *once* for a column
+ * during hydration because the hydrator caches effectively.
*/
- public function lookupFieldName($columnName)
+ public function lookupFieldName($lcColumnName)
{
- if (isset($this->_fieldNames[$columnName])) {
- return $this->_fieldNames[$columnName];
- } else if (isset($this->_subclassFieldNames[$columnName])) {
- return $this->_subclassFieldNames[$columnName];
- }
+ if (isset($this->_lcColumnToFieldNames[$lcColumnName])) {
+ return $this->_lcColumnToFieldNames[$lcColumnName];
+ }/* else if (isset($this->_subclassFieldNames[$lcColumnName])) {
+ return $this->_subclassFieldNames[$lcColumnName];
+ }*/
- $classMetadata = $this;
- $conn = $this->_em;
-
- foreach ($classMetadata->getSubclasses() as $subClass) {
- $subClassMetadata = $conn->getClassMetadata($subClass);
- if ($subClassMetadata->hasColumn($columnName)) {
- $this->_subclassFieldNames[$columnName] = $subClassMetadata->getFieldName($columnName);
- return $this->_subclassFieldNames[$columnName];
+ foreach ($this->getSubclasses() as $subClass) {
+ $subClassMetadata = $this->_em->getClassMetadata($subClass);
+ if ($subClassMetadata->hasLowerColumn($lcColumnName)) {
+ /*$this->_subclassFieldNames[$lcColumnName] = $subClassMetadata->
+ getFieldNameForLowerColumnName($lcColumnName);
+ return $this->_subclassFieldNames[$lcColumnName];*/
+ return $subClassMetadata->getFieldNameForLowerColumnName($lcColumnName);
}
}
- throw new Doctrine_ClassMetadata_Exception("No field name found for column name '$columnName' during lookup.");
+ throw new Doctrine_ClassMetadata_Exception("No field name found for column name '$lcColumnName' during lookup.");
}
/**
@@ -615,27 +651,31 @@
}
}
- // extract column name & field name
+ // extract column name & field name & lowercased column name
$parts = explode(' as ', $name);
if (count($parts) > 1) {
$fieldName = $parts[1];
} else {
$fieldName = $parts[0];
}
- $name = strtolower($parts[0]);
+ $columnName = $parts[0];
+ $lcColumnName = strtolower($parts[0]);
- if (isset($this->_columnNames[$fieldName])) {
+ if (isset($this->_mappedColumns[$columnName])) {
return;
}
+ // Fill column name <-> field name lookup maps
if ($prepend) {
- $this->_columnNames = array_merge(array($fieldName => $name), $this->_columnNames);
- $this->_fieldNames = array_merge(array($name => $fieldName), $this->_fieldNames);
+ $this->_columnNames = array_merge(array($fieldName => $columnName), $this->_columnNames);
+ $this->_fieldNames = array_merge(array($columnName => $fieldName), $this->_fieldNames);
} else {
- $this->_columnNames[$fieldName] = $name;
- $this->_fieldNames[$name] = $fieldName;
+ $this->_columnNames[$fieldName] = $columnName;
+ $this->_fieldNames[$columnName] = $fieldName;
}
+ $this->_lcColumnToFieldNames[$lcColumnName] = $fieldName;
+
// Inspect & fill $options
if ($length == null) {
@@ -662,9 +702,9 @@
}*/
if ($prepend) {
- $this->_mappedColumns = array_merge(array($name => $options), $this->_mappedColumns);
+ $this->_mappedColumns = array_merge(array($columnName => $options), $this->_mappedColumns);
} else {
- $this->_mappedColumns[$name] = $options;
+ $this->_mappedColumns[$columnName] = $options;
}
$this->_columnCount++;
Modified: trunk/lib/Doctrine/Collection.php
===================================================================
--- trunk/lib/Doctrine/Collection.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Collection.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -65,7 +65,7 @@
*
* @var Doctrine_Entity
*/
- protected $reference;
+ protected $_owner;
/**
* The reference field of the collection.
@@ -93,7 +93,14 @@
*
* @var Doctrine_Null
*/
- protected static $null;
+ //protected static $null;
+
+ /**
+ * The EntityManager.
+ *
+ * @var EntityManager
+ */
+ protected $_em;
/**
* Constructor.
@@ -104,15 +111,12 @@
*/
public function __construct($entityBaseType, $keyField = null)
{
- if (is_string($entityBaseType)) {
- $this->_entityBaseType = $entityBaseType;
- $mapper = Doctrine_EntityManagerFactory::getManager($entityBaseType)
- ->getEntityPersister($entityBaseType);
- }
- $this->_mapper = $mapper;
+ $this->_entityBaseType = $entityBaseType;
+ $this->_em = Doctrine_EntityManagerFactory::getManager($entityBaseType);
+ $this->_mapper = $this->_em->getEntityPersister($entityBaseType);
if ($keyField === null) {
- $keyField = $mapper->getClassMetadata()->getBoundQueryPart('indexBy');
+ $keyField = $this->_mapper->getClassMetadata()->getBoundQueryPart('indexBy');
}
if ($keyField === null) {
@@ -128,39 +132,6 @@
}
/**
- * initNullObject
- * Initializes the null object for this collection.
- *
- * @return void
- */
- public static function initNullObject(Doctrine_Null $null)
- {
- self::$null = $null;
- }
-
- /**
- * getTable
- * Returns the table of the mapper of the collection.
- *
- * @return Doctrine_Table
- */
- public function getTable()
- {
- return $this->_mapper->getTable();
- }
-
- /**
- * getMapper
- * Returns the mapper of this collection.
- *
- * @return Doctrine_Mapper
- */
- public function getMapper()
- {
- return $this->_mapper;
- }
-
- /**
* setData
*
* @param array $data
@@ -306,25 +277,25 @@
}
/**
- * setReference
+ * INTERNAL:
* sets a reference pointer
*
* @return void
*/
- public function setReference(Doctrine_Entity $record, Doctrine_Relation $relation)
+ public function setReference(Doctrine_Entity $entity, Doctrine_Relation $relation)
{
- $this->reference = $record;
+ $this->_owner = $entity;
$this->relation = $relation;
if ($relation instanceof Doctrine_Relation_ForeignKey ||
$relation instanceof Doctrine_Relation_LocalKey) {
$this->referenceField = $relation->getForeignFieldName();
- $value = $record->get($relation->getLocalFieldName());
- foreach ($this->data as $record) {
+ $value = $entity->get($relation->getLocalFieldName());
+ foreach ($this->data as $entity) {
if ($value !== null) {
- $record->set($this->referenceField, $value, false);
+ $entity->set($this->referenceField, $value, false);
} else {
- $record->set($this->referenceField, $this->reference, false);
+ $entity->set($this->referenceField, $this->_owner, false);
}
}
} else if ($relation instanceof Doctrine_Relation_Association) {
@@ -333,18 +304,18 @@
}
/**
+ * INTERNAL:
* getReference
*
* @return mixed
*/
public function getReference()
{
- return $this->reference;
+ return $this->_owner;
}
/**
- * remove
- * removes a specified collection element
+ * Removes an entity from the collection.
*
* @param mixed $key
* @return boolean
@@ -357,8 +328,7 @@
}
/**
- * contains
- * whether or not this collection contains a specified element
+ * Checks whether the collection contains an entity.
*
* @param mixed $key the key of the element
* @return boolean
@@ -378,17 +348,8 @@
}
/**
- * get
* returns a record for given key
*
- * There are two special cases:
- *
- * 1. if null is given as a key a new record is created and attached
- * at the end of the collection
- *
- * 2. if given key does not exist, then a new record is create and attached
- * to the given key
- *
* Collection also maps referential information to newly created records
*
* @param mixed $key the key of the element
@@ -396,33 +357,10 @@
*/
public function get($key)
{
- if ( ! isset($this->data[$key])) {
- $record = $this->_mapper->create();
-
- if (isset($this->referenceField)) {
- $value = $this->reference->get($this->relation->getLocalFieldName());
-
- if ($value !== null) {
- $record->set($this->referenceField, $value, false);
- } else {
- $record->set($this->referenceField, $this->reference, false);
- }
- }
-
- if ($key === null) {
- $this->data[] = $record;
- } else {
- $this->data[$key] = $record;
- }
-
- if (isset($this->_keyField)) {
- $record->set($this->_keyField, $key);
- }
-
- return $record;
+ if (isset($this->data[$key])) {
+ return $this->data[$key];
}
-
- return $this->data[$key];
+ return null;
}
/**
@@ -491,16 +429,16 @@
* @internal Can't type-hint the second parameter to Doctrine_Entity because we need
* to adhere to the Doctrine_Access::set() signature.
*/
- public function set($key, $record)
+ public function set($key, $entity)
{
- if ( ! $record instanceOf Doctrine_Entity) {
+ if ( ! $entity instanceof Doctrine_Entity) {
throw new Doctrine_Collection_Exception('Value variable in set is not an instance of Doctrine_Entity');
}
if (isset($this->referenceField)) {
- $record->set($this->referenceField, $this->reference, false);
+ $entity->set($this->referenceField, $this->_owner, false);
}
- $this->data[$key] = $record;
+ $this->data[$key] = $entity;
}
/**
@@ -517,12 +455,12 @@
}
if (isset($this->referenceField)) {
- $value = $this->reference->get($this->relation->getLocalFieldName());
+ $value = $this->_owner->get($this->relation->getLocalFieldName());
if ($value !== null) {
$record->set($this->referenceField, $value, false);
} else {
- $record->set($this->referenceField, $this->reference, false);
+ $record->set($this->referenceField, $this->_owner, false);
}
}
/*
@@ -559,6 +497,7 @@
}
/**
+ * INTERNAL:
* loadRelated
*
* @param mixed $name
@@ -578,8 +517,10 @@
$list[] = $value;
}
}
- $query->from($this->_mapper->getComponentName() . '(' . implode(", ",$this->_mapper->getTable()->getPrimaryKeys()) . ')');
- $query->where($this->_mapper->getComponentName() . '.id IN (' . substr(str_repeat("?, ", count($list)),0,-2) . ')');
+ $query->from($this->_mapper->getComponentName()
+ . '(' . implode(", ",$this->_mapper->getTable()->getPrimaryKeys()) . ')');
+ $query->where($this->_mapper->getComponentName()
+ . '.id IN (' . substr(str_repeat("?, ", count($list)),0,-2) . ')');
return $query;
}
@@ -607,6 +548,7 @@
}
/**
+ * INTERNAL:
* populateRelated
*
* @param string $name
@@ -929,9 +871,9 @@
$this->data = array();
- if ($this->reference) {
- $this->reference->free($deep);
- $this->reference = null;
+ if ($this->_owner) {
+ $this->_owner->free($deep);
+ $this->_owner = null;
}
}
Modified: trunk/lib/Doctrine/Configuration.php
===================================================================
--- trunk/lib/Doctrine/Configuration.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Configuration.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -27,6 +27,7 @@
* The Configuration is the container for all configuration options of Doctrine.
* It combines all configuration options from DBAL & ORM.
*
+ * @author Roman Borschel <ro...@code-factory.org>
* @since 2.0
*/
class Doctrine_Configuration
Modified: trunk/lib/Doctrine/Connection/Mock.php
===================================================================
--- trunk/lib/Doctrine/Connection/Mock.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Connection/Mock.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -38,7 +38,7 @@
/**
* @var string $driverName the name of this connection driver
*/
- protected $driverName = 'MySql';
+ protected $_driverName = 'Mysql';
/**
* the constructor
Modified: trunk/lib/Doctrine/Connection/Mysql.php
===================================================================
--- trunk/lib/Doctrine/Connection/Mysql.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Connection/Mysql.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -40,7 +40,7 @@
*
* @var string
*/
- protected $driverName = 'Mysql';
+ protected $_driverName = 'Mysql';
/**
* the constructor
@@ -206,5 +206,31 @@
$query = 'REPLACE INTO ' . $tableName . ' (' . $query . ') VALUES (' . $values . ')';
return $this->exec($query);
+ }
+
+ /**
+ * Constructs the MySql PDO DSN.
+ *
+ * Overrides Connection#_constructPdoDsn().
+ *
+ * @return string The DSN.
+ */
+ protected function _constructPdoDsn()
+ {
+ $dsn = 'mysql:';
+ if (isset($this->_params['host'])) {
+ $dsn .= 'host=' . $this->_params['host'] . ';';
+ }
+ if (isset($this->_params['port'])) {
+ $dsn .= 'port=' . $this->_params['port'] . ';';
+ }
+ if (isset($this->_params['dbname'])) {
+ $dsn .= 'dbname=' . $this->_params['dbname'] . ';';
+ }
+ if (isset($this->_params['unix_socket'])) {
+ $dsn .= 'unix_socket=' . $this->_params['unix_socket'] . ';';
+ }
+
+ return $dsn;
}
}
Modified: trunk/lib/Doctrine/Connection/Sqlite.php
===================================================================
--- trunk/lib/Doctrine/Connection/Sqlite.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Connection/Sqlite.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -38,7 +38,7 @@
/**
* @var string $driverName the name of this connection driver
*/
- protected $driverName = 'Sqlite';
+ protected $_driverName = 'Sqlite';
/**
* the constructor
@@ -67,13 +67,14 @@
'prepared_statements' => 'emulated',
'identifier_quoting' => true,
'pattern_escaping' => false,
- );
+ );
+
parent::__construct($params);
- if ($this->isConnected) {
- $this->dbh->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2);
- $this->dbh->sqliteCreateFunction('md5', 'md5', 1);
- $this->dbh->sqliteCreateFunction('now', 'time', 0);
+ if ($this->_isConnected) {
+ $this->_pdo->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2);
+ $this->_pdo->sqliteCreateFunction('md5', 'md5', 1);
+ $this->_pdo->sqliteCreateFunction('now', 'time', 0);
}
}
@@ -85,15 +86,15 @@
*/
public function connect()
{
- if ($this->isConnected) {
+ if ($this->_isConnected) {
return false;
}
parent::connect();
- $this->dbh->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2);
- $this->dbh->sqliteCreateFunction('md5', 'md5', 1);
- $this->dbh->sqliteCreateFunction('now', 'time', 0);
+ $this->_pdo->sqliteCreateFunction('mod', array('Doctrine_Expression_Sqlite', 'modImpl'), 2);
+ $this->_pdo->sqliteCreateFunction('md5', 'md5', 1);
+ $this->_pdo->sqliteCreateFunction('now', 'time', 0);
}
/**
@@ -125,18 +126,37 @@
*/
public function dropDatabase()
{
- try {
- if ( ! $dsn = $this->getOption('dsn')) {
- throw new Doctrine_Connection_Exception('You must create your Doctrine_Connection by using a valid Doctrine style dsn in order to use the create/drop database functionality');
- }
-
- $info = $this->getManager()->parseDsn($dsn);
+ try {
+ if ( ! $dsn = $this->getOption('dsn')) {
+ throw new Doctrine_Connection_Exception('You must create your Doctrine_Connection by using a valid Doctrine style dsn in order to use the create/drop database functionality');
+ }
- $this->export->dropDatabase($info['database']);
+ $info = $this->getManager()->parseDsn($dsn);
- return 'Successfully dropped database for connection "' . $this->getName() . '" at path "' . $info['database'] . '"';
- } catch (Exception $e) {
- return $e;
- }
+ $this->export->dropDatabase($info['database']);
+
+ return 'Successfully dropped database for connection "' . $this->getName() . '" at path "' . $info['database'] . '"';
+ } catch (Exception $e) {
+ return $e;
+ }
+ }
+
+ /**
+ * Constructs the Sqlite PDO DSN.
+ *
+ * Overrides Connection#_constructPdoDsn().
+ *
+ * @return string The DSN.
+ */
+ protected function _constructPdoDsn()
+ {
+ $dsn = 'sqlite:';
+ if (isset($this->_params['path'])) {
+ $dsn .= $this->_params['path'];
+ } else if (isset($this->_params['memory'])) {
+ $dsn .= ':memory:';
+ }
+
+ return $dsn;
}
}
\ No newline at end of file
Modified: trunk/lib/Doctrine/Connection/UnitOfWork.php
===================================================================
--- trunk/lib/Doctrine/Connection/UnitOfWork.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Connection/UnitOfWork.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -22,17 +22,19 @@
#namespace Doctrine::ORM::Internal;
/**
- * The UnitOfWork is responsible for writing out changes to the database at
- * the correct time and in the correct order.
+ * The UnitOfWork is responsible for tracking changes to objects during an
+ * "object-level" transaction and for writing out changes to the database at
+ * in the correct order.
*
* Some terminology:
*
* <b>New entity</b>: A new entity is an entity that already has an identity but
* is not yet persisted into the database. This is usually the case for all
- * newly saved entities that use a SEQUENCE id generator. Entities with an
+ * newly saved/persisted entities that use a SEQUENCE id generator. Entities with an
* IDENTITY id generator get persisted as soon as they're saved in order to
* obtain the identifier. Therefore entities that use an IDENTITY id generator
* never appear in the list of new entities of the UoW.
+ * New entities are inserted into the database when the is UnitOfWork committed.
*
* <b>Dirty entity</b>: A dirty entity is a managed entity whose values have
* been altered.
@@ -53,7 +55,7 @@
* @author Roman Borschel <ro...@code-factory.org>
* @todo package:orm. Figure out a useful implementation.
*/
-class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
+class Doctrine_Connection_UnitOfWork
{
/**
* The identity map that holds references to all managed entities that have
@@ -95,6 +97,17 @@
protected $_commitOrderCalculator;
/**
+ * Constructor.
+ * Created a new UnitOfWork.
+ *
+ * @param Doctrine_EntityManager $em
+ */
+ public function __construct(Doctrine_EntityManager $em)
+ {
+ $this->_em = $em;
+ }
+
+ /**
* Commits the unit of work, executing all operations that have been postponed
* up to this point.
*
@@ -201,7 +214,6 @@
}
/**
- * buildFlushTree
* builds a flush tree that is used in transactions
*
* The returned array has all the initialized components in
@@ -301,14 +313,13 @@
}
/**
- * saveAll
* persists all the pending records from all tables
*
* @throws PDOException if something went wrong at database level
* @return void
* @deprecated
*/
- public function saveAll()
+ /*public function saveAll()
{
$this->conn->beginInternalTransaction();
// get the flush tree
@@ -337,7 +348,7 @@
}
}
$this->conn->commit();
- }
+ }*/
/**
* Adds an entity to the pool of managed entities.
Modified: trunk/lib/Doctrine/Connection.php
===================================================================
--- trunk/lib/Doctrine/Connection.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Connection.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -78,10 +78,9 @@
/**
* The PDO database handle.
*
- * @var PDO
- * @todo Rename to $pdo.
+ * @var PDO
*/
- protected $dbh;
+ protected $_pdo;
/**
* The Configuration.
@@ -116,14 +115,14 @@
*
* @var string $driverName
*/
- protected $driverName;
+ protected $_driverName;
/**
* Whether or not a connection has been established.
*
* @var boolean $isConnected
*/
- protected $isConnected = false;
+ protected $_isConnected = false;
/**
* An array containing all features this driver supports, keys representing feature
@@ -163,7 +162,7 @@
*
* @var array $availableDrivers
*/
- private static $availableDrivers = array(
+ private static $_availableDrivers = array(
'Mysql', 'Pgsql', 'Oracle', 'Informix', 'Mssql', 'Sqlite', 'Firebird'
);
@@ -172,7 +171,7 @@
*
* @var integer
*/
- protected $_count = 0;
+ protected $_queryCount = 0;
/*
@@ -220,14 +219,13 @@
/**
* Constructor.
*
- * @param Doctrine_Manager $manager the manager object
- * @param PDO|Doctrine_Adapter_Interface $adapter database driver
+ * @param array $params The connection parameters.
*/
public function __construct(array $params)
{
if (isset($params['pdo'])) {
- $this->dbh = $params['pdo'];
- $this->isConnected = true;
+ $this->_pdo = $params['pdo'];
+ $this->_isConnected = true;
}
$this->_params = $params;
}
@@ -319,66 +317,82 @@
}
/**
- * getDriverName
- *
* Gets the name of the instance driver
*
* @return void
*/
public function getDriverName()
{
- return $this->driverName;
+ return $this->_driverName;
}
/**
* returns the database handler which this connection uses
*
* @return PDO the database handler
+ * @deprecated
*/
public function getDbh()
{
- //$this->connect();
-
- return $this->dbh;
+ $this->connect();
+ return $this->_pdo;
}
/**
+ * Gets the PDO handle used by the connection.
+ *
+ * @return PDO
+ */
+ public function getPdo()
+ {
+ $this->connect();
+ return $this->_pdo;
+ }
+
+ /**
* Establishes the connection with the database.
*
* @return boolean
*/
public function connect()
{
- if ($this->isConnected) {
+ if ($this->_isConnected) {
return false;
}
//$event = new Doctrine_Event($this, Doctrine_Event::CONN_CONNECT);
//$this->getListener()->preConnect($event);
- $e = explode(':', $this->options['dsn']);
+ // TODO: the extension_loaded check can happen earlier, maybe in the factory
if (extension_loaded('pdo')) {
- if (in_array($e[0], PDO::getAvailableDrivers())) {
- $this->dbh = new PDO(
- $this->options['dsn'], $this->options['username'],
- $this->options['password'], $this->options['other']);
- $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
- $this->dbh->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
- }
+ $driverOptions = isset($this->_params['driverOptions']) ?
+ $this->_params['driverOptions'] : array();
+ $user = isset($this->_params['user']) ?
+ $this->_params['user'] : null;
+ $password = isset($this->_params['password']) ?
+ $this->_params['password'] : null;
+ $this->_pdo = new PDO(
+ $this->_constructPdoDsn(),
+ $user,
+ $password,
+ $driverOptions
+ );
+ $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $this->_pdo->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
} else {
throw new Doctrine_Connection_Exception("Couldn't locate driver named " . $e[0]);
}
// attach the pending attributes to adapter
- foreach($this->pendingAttributes as $attr => $value) {
+ /*foreach($this->pendingAttributes as $attr => $value) {
// some drivers don't support setting this so we just skip it
if ($attr == Doctrine::ATTR_DRIVER_NAME) {
continue;
}
- $this->dbh->setAttribute($attr, $value);
- }
+ $this->_pdo->setAttribute($attr, $value);
+ }*/
- $this->isConnected = true;
+ $this->_isConnected = true;
//$this->getListener()->postConnect($event);
return true;
@@ -394,7 +408,7 @@
*/
protected function _constructPdoDsn()
{
-
+ throw Doctrine_Exception::notImplemented('_constructPdoDsn', get_class($this));
}
/**
@@ -402,20 +416,12 @@
*/
public function incrementQueryCount()
{
- $this->_count++;
+ $this->_queryCount++;
}
/**
- * converts given driver name
+ * Checks whether a certain feature is supported.
*
- * @param
- */
- public function driverName($name)
- {}
-
- /**
- * supports
- *
* @param string $feature the name of the feature
* @return boolean whether or not this drivers supports given feature
*/
@@ -665,7 +671,7 @@
*/
public function quote($input, $type = null)
{
- return $this->dbh->quote($input, $type);
+ return $this->_pdo->quote($input, $type);
}
/**
@@ -782,7 +788,7 @@
$stmt = false;
if ( ! $event->skipOperation) {
- $stmt = $this->dbh->prepare($statement);
+ $stmt = $this->_pdo->prepare($statement);
}
$this->getAttribute(Doctrine::ATTR_LISTENER)->postPrepare($event);
@@ -846,8 +852,8 @@
$this->getAttribute(Doctrine::ATTR_LISTENER)->preQuery($event);
if ( ! $event->skipOperation) {
- $stmt = $this->dbh->query($query);
- $this->_count++;
+ $stmt = $this->_pdo->query($query);
+ $this->_queryCount++;
}
$this->getAttribute(Doctrine::ATTR_LISTENER)->postQuery($event);
@@ -881,8 +887,8 @@
$this->getAttribute(Doctrine::ATTR_LISTENER)->preExec($event);
if ( ! $event->skipOperation) {
- $count = $this->dbh->exec($query);
- $this->_count++;
+ $count = $this->_pdo->exec($query);
+ $this->_queryCount++;
}
$this->getAttribute(Doctrine::ATTR_LISTENER)->postExec($event);
@@ -926,7 +932,7 @@
//$event = new Doctrine_Event($this, Doctrine_Event::CONN_ERROR);
//$this->getListener()->preError($event);
- $name = 'Doctrine_Connection_' . $this->driverName . '_Exception';
+ $name = 'Doctrine_Connection_' . $this->_driverName . '_Exception';
$exc = new $name($e->getMessage(), (int) $e->getCode());
if ( ! is_array($e->errorInfo)) {
@@ -949,7 +955,7 @@
*/
public function count()
{
- return $this->_count;
+ return $this->_queryCount;
}
/**
@@ -964,8 +970,8 @@
$this->clear();
- unset($this->dbh);
- $this->isConnected = false;
+ unset($this->_pdo);
+ $this->_isConnected = false;
//$this->getAttribute(Doctrine::ATTR_LISTENER)->postClose($event);
}
@@ -990,7 +996,7 @@
{
$this->connect();
- return $this->dbh->errorCode();
+ return $this->_pdo->errorCode();
}
/**
@@ -1003,7 +1009,7 @@
{
$this->connect();
- return $this->dbh->errorInfo();
+ return $this->_pdo->errorInfo();
}
/**
Modified: trunk/lib/Doctrine/ConnectionFactory.php
===================================================================
--- trunk/lib/Doctrine/ConnectionFactory.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/ConnectionFactory.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -52,6 +52,12 @@
}
+ /**
+ * Creates a connection object with the specified parameters.
+ *
+ * @param array $params
+ * @return Connection
+ */
public function createConnection(array $params)
{
// check for existing pdo object
@@ -80,14 +86,6 @@
if ( ! isset($params['driver'])) {
throw Doctrine_ConnectionFactory_Exception::driverRequired();
}
- // user
- if ( ! isset($params['user'])) {
- throw Doctrine_ConnectionFactory_Exception::userRequired();
- }
- // password
- if ( ! isset($params['password'])) {
- throw Doctrine_ConnectionFactory_Exception::passwordRequired();
- }
// check validity of parameters
Modified: trunk/lib/Doctrine/EntityManager.php
===================================================================
--- trunk/lib/Doctrine/EntityManager.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/EntityManager.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -148,7 +148,7 @@
$this->_name = $name;
$this->_metadataFactory = new Doctrine_ClassMetadata_Factory(
$this, new Doctrine_ClassMetadata_CodeDriver());
- $this->_unitOfWork = new Doctrine_Connection_UnitOfWork($conn);
+ $this->_unitOfWork = new Doctrine_Connection_UnitOfWork($this);
$this->_nullObject = Doctrine_Null::$INSTANCE;
}
@@ -463,8 +463,8 @@
/**
* Creates an entity. Used for reconstitution as well as initial creation.
*
- * @param
- * @param
+ * @param string $className The name of the entity class.
+ * @param array $data The data for the entity.
* @return Doctrine_Entity
*/
public function createEntity($className, array $data)
@@ -485,22 +485,19 @@
}
if ($isNew) {
- $entity = new $className(true);
- //$entity->_setData($data);
+ $entity = new $className;
} else {
$idHash = $this->_unitOfWork->getIdentifierHash($id);
if ($entity = $this->_unitOfWork->tryGetByIdHash($idHash,
$classMetadata->getRootClassName())) {
return $entity;
} else {
- $entity = new $className(false);
- //$entity->_setData($data);
+ $entity = new $className;
$this->_unitOfWork->registerIdentity($entity);
}
}
} else {
- $entity = new $className(true);
- //$entity->_setData($data);
+ $entity = new $className;
}
/*if (count($data) < $classMetadata->getMappedColumnCount()) {
@@ -508,7 +505,6 @@
} else {
$entity->_state(Doctrine_Entity::STATE_CLEAN);
}*/
- $this->_tmpEntityData = array();
return $entity;
}
@@ -519,7 +515,9 @@
*/
public function _getTmpEntityData()
{
- return $this->_tmpEntityData;
+ $data = $this->_tmpEntityData;
+ $this->_tmpEntityData = array();
+ return $data;
}
/**
@@ -528,7 +526,6 @@
* classname will be returned.
*
* @return string The name of the class to instantiate.
- * @todo Can be optimized performance-wise.
*/
private function _inferCorrectClassName(array $data, $className)
{
@@ -553,10 +550,10 @@
*
* @return UnitOfWork
*/
- public function getUnitOfWork()
+ /*public function getUnitOfWork()
{
return $this->_unitOfWork;
- }
+ }*/
/**
* Gets the EventManager used by the EntityManager.
Modified: trunk/lib/Doctrine/EntityManagerFactory.php
===================================================================
--- trunk/lib/Doctrine/EntityManagerFactory.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/EntityManagerFactory.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -11,6 +11,7 @@
* instances as well as keeping track of all created EntityManagers and
* hard bindings to Entities.
*
+ * @author Roman Borschel <ro...@code-factory.org>
* @since 2.0
*/
class Doctrine_EntityManagerFactory
@@ -52,21 +53,44 @@
*/
private $_config;
+ /**
+ * Constructor.
+ * Creates a new EntityManagerFactory.
+ */
public function __construct()
{
$this->_connFactory = new Doctrine_ConnectionFactory();
}
+ /**
+ * Sets the Configuration that is injected into all EntityManagers
+ * (and their Connections) that are created by this factory.
+ *
+ * @param Doctrine_Configuration $eventManager
+ */
public function setConfiguration(Doctrine_Configuration $config)
{
$this->_config = $config;
}
+ /**
+ * Sets the EventManager that is injected into all EntityManagers
+ * (and their Connections) that are created by this factory.
+ *
+ * @param Doctrine_EventManager $eventManager
+ */
public function setEventManager(Doctrine_EventManager $eventManager)
{
$this->_eventManager = $eventManager;
}
+ /**
+ * Creates an EntityManager.
+ *
+ * @param unknown_type $connParams
+ * @param unknown_type $name
+ * @return unknown
+ */
public function createEntityManager($connParams, $name = null)
{
if ( ! $this->_config) {
Modified: trunk/lib/Doctrine/EntityPersister/Standard.php
===================================================================
--- trunk/lib/Doctrine/EntityPersister/Standard.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/EntityPersister/Standard.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -20,7 +20,7 @@
*/
/**
- * The default mapping strategy maps a single entity instance to a single database table,
+ * The default persister strategy maps a single entity instance to a single database table,
* as is the case in Single Table Inheritance & Concrete Table Inheritance.
*
* @author Roman Borschel <ro...@code-factory.org>
Modified: trunk/lib/Doctrine/EventListener.php
===================================================================
--- trunk/lib/Doctrine/EventListener.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/EventListener.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -30,7 +30,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
- * @version $Revision$
+ * @version $Revision$
+ * @todo Remove. The 2.0 event system has no listener interfaces.
*/
class Doctrine_EventListener implements Doctrine_EventListener_Interface
{
Modified: trunk/lib/Doctrine/EventManager.php
===================================================================
--- trunk/lib/Doctrine/EventManager.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/EventManager.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -21,12 +21,33 @@
#namespace Doctrine::Common;
+/**
+ * The EventManager is the central point of Doctrine's event listener system.
+ * Listeners are registered on the manager and events are dispatch through the
+ * manager.
+ *
+ * @author Roman Borschel <ro...@code-factory.org>
+ * @author Guilherme Blanco <guilhermebla...@hotmail.com>
+ * @since 2.0
+ */
class Doctrine_EventManager
{
+ /**
+ * Map of registered listeners.
+ * <event> => <listeners>
+ *
+ * @var array
+ */
private $_listeners = array();
-
- public function dispatchEvent($event) {
+ /**
+ * Dispatches an event to all registered listeners.
+ *
+ * @param string|Event $event The name of the event or the event object.
+ * @return boolean
+ */
+ public function dispatchEvent($event)
+ {
$argIsCallback = is_string($event);
$callback = $argIsCallback ? $event : $event->getType();
@@ -40,25 +61,43 @@
return ! $event->getDefaultPrevented();
}
-
- public function getListeners($callback = null) {
- return $callback ? $this->_listeners[$callback] : $this->_listeners;
+ /**
+ * Gets the listeners of a specific event or all listeners.
+ *
+ * @param string $event The name of the event.
+ * @return
+ */
+ public function getListeners($event = null)
+ {
+ return $event ? $this->_listeners[$event] : $this->_listeners;
}
-
- public function hasListeners($callback) {
- return isset($this->_listeners[$callback]);
+ /**
+ * Checks whether an event has any registered listeners.
+ *
+ * @param string $event
+ * @return boolean
+ */
+ public function hasListeners($event)
+ {
+ return isset($this->_listeners[$event]);
}
-
- public function addEventListener($callbacks, $listener) {
+ /**
+ * Adds an event listener that listens on the specified events.
+ *
+ * @param string|array $events The event(s) to listen on.
+ * @param object $listener The listener object.
+ */
+ public function addEventListener($events, $listener)
+ {
// TODO: maybe check for duplicate registrations?
- if ( ! is_array($callbacks)) {
- $callbacks = array($callbacks);
+ if ( ! is_array($events)) {
+ $events = array($events);
}
- foreach ($callbacks as $callback) {
- $this->_listeners[$callback] = $listener;
+ foreach ($events as $event) {
+ $this->_listeners[$event] = $listener;
}
}
}
Modified: trunk/lib/Doctrine/Exception.php
===================================================================
--- trunk/lib/Doctrine/Exception.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Exception.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -46,6 +46,11 @@
public function getInnerException()
{
return $this->_innerException;
+ }
+
+ public static function notImplemented($method, $class)
+ {
+ return new self("The method '$method' is not implemented in the class '$class'.");
}
}
Modified: trunk/lib/Doctrine/HydratorNew.php
===================================================================
--- trunk/lib/Doctrine/HydratorNew.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/HydratorNew.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -355,8 +355,6 @@
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
- // check ignored names. fastest solution for now. if we get more we'll start
- // to introduce a list.
if ($this->_isIgnoredName($key)) continue;
// cache general information like the column name <-> field name mapping
@@ -439,8 +437,6 @@
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
- // check ignored names. fastest solution for now. if we get more we'll start
- // to introduce a list.
if ($this->_isIgnoredName($key)) continue;
// cache general information like the column name <-> field name mapping
Modified: trunk/lib/Doctrine/Manager.php
===================================================================
--- trunk/lib/Doctrine/Manager.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Manager.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -30,7 +30,8 @@
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
- * @author Konsta Vesterinen <kvest...@cc.hut.fi>
+ * @author Konsta Vesterinen <kvest...@cc.hut.fi>
+ * @todo Remove.
*/
class Doctrine_Manager implements Doctrine_Configurable, Countable, IteratorAggregate
{
Modified: trunk/lib/Doctrine/Query/Abstract.php
===================================================================
--- trunk/lib/Doctrine/Query/Abstract.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Query/Abstract.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -987,5 +987,28 @@
* @return string SQL query
*/
abstract public function getSql();
+
+ /**
+ * Sets a query parameter.
+ *
+ * @param string|integer $key
+ * @param mixed $value
+ */
+ public function setParameter($key, $value)
+ {
+ $this->_params[$key] = $value;
+ }
+
+ /**
+ * Sets a collection of query parameters.
+ *
+ * @param array $params
+ */
+ public function setParameters(array $params)
+ {
+ foreach ($params as $key => $value) {
+ $this->setParameter($key, $value);
+ }
+ }
}
Modified: trunk/lib/Doctrine/Query/Exception.php
===================================================================
--- trunk/lib/Doctrine/Query/Exception.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Query/Exception.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
-Doctrine::autoload('Doctrine_Exception');
+
/**
* Doctrine_Query_Exception
*
@@ -31,4 +31,9 @@
* @author Konsta Vesterinen <kvest...@cc.hut.fi>
*/
class Doctrine_Query_Exception extends Doctrine_Exception
-{ }
\ No newline at end of file
+{
+ public static function nonUniqueResult()
+ {
+ return new self("The query contains more than one result.");
+ }
+}
Modified: trunk/lib/Doctrine/Query.php
===================================================================
--- trunk/lib/Doctrine/Query.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Query.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -540,13 +540,14 @@
return $this;
}
-
/**
* Empty template method to provide Query subclasses with the possibility
* to hook into the query building procedure, doing any custom / specialized
* query building procedures that are neccessary.
*
* @return void
+ * @deprecated Should be removed. Extending Query is no good solution. Should
+ * Things like this should be done through listeners.
*/
public function preQuery()
{
@@ -559,13 +560,44 @@
* post query procedures (for example logging) that are neccessary.
*
* @return void
+ * @deprecated Should be removed. Extending Query is no good solution. Should
+ * Things like this should be done through listeners.
*/
public function postQuery()
{
}
+
+ /**
+ * Gets the list of results for the query.
+ *
+ * @param integer $hydrationMode
+ * @return mixed
+ */
+ public function getResultList($hydrationMode = null)
+ {
+ return $this->execute(array(), $hydrationMode);
+ }
+
+ /**
+ * Gets the single result of the query.
+ * Enforces the uniqueness of the result. If the result is not unique,
+ * a QueryException is thrown.
+ *
+ * @param integer $hydrationMode
+ * @return mixed
+ * @throws QueryException If the query result is not unique.
+ */
+ public function getSingleResult($hydrationMode = null)
+ {
+ $result = $this->execute(array(), $hydrationMode);
+ if (count($result) > 1) {
+ throw Doctrine_Query_Exception::nonUniqueResult();
+ }
+
+ return is_array($result) ? array_shift($result) : $result->getFirst();
+ }
-
/**
* This method is automatically called when this Doctrine_Hydrate is serialized.
*
Modified: trunk/lib/Doctrine/Sequence.php
===================================================================
--- trunk/lib/Doctrine/Sequence.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Sequence.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
-Doctrine::autoload('Doctrine_Connection_Module');
+
/**
* Doctrine_Sequence
* The base class for sequence handling drivers.
Modified: trunk/lib/Doctrine/Transaction.php
===================================================================
--- trunk/lib/Doctrine/Transaction.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/lib/Doctrine/Transaction.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -22,7 +22,6 @@
#namespace Doctrine::DBAL::Transactions;
/**
- * Doctrine_Transaction
* Handles transaction savepoint and isolation abstraction
*
* @author Konsta Vesterinen <kvest...@cc.hut.fi>
Modified: trunk/tests/Orm/Query/DqlGenerationTest.php
===================================================================
--- trunk/tests/Orm/Query/DqlGenerationTest.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/tests/Orm/Query/DqlGenerationTest.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -29,7 +29,7 @@
* @author Konsta Vesterinen <kvest...@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
- * @since 1.0
+ * @since 2.0
* @version $Revision$
*/
class Orm_Query_DqlGenerationTest extends Doctrine_OrmTestCase
Modified: trunk/tests/Orm/UnitOfWorkTest.php
===================================================================
--- trunk/tests/Orm/UnitOfWorkTest.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/tests/Orm/UnitOfWorkTest.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -9,7 +9,7 @@
protected function setUp() {
parent::setUp();
$this->_user = new ForumUser();
- $this->_unitOfWork = $this->_em->getUnitOfWork();
+ $this->_unitOfWork = new Doctrine_Connection_UnitOfWork($this->_em);
}
protected function tearDown() {
Modified: trunk/tests/lib/Doctrine_TestUtil.php
===================================================================
--- trunk/tests/lib/Doctrine_TestUtil.php 2008-07-03 17:10:44 UTC (rev 4627)
+++ trunk/tests/lib/Doctrine_TestUtil.php 2008-07-04 16:32:19 UTC (rev 4628)
@@ -19,7 +19,8 @@
//return Doctrine_Manager::connection($dsn, 'testconn');
} else {
$params = array(
- 'pdo' => new PDO('sqlite::memory:')
+ 'driver' => 'sqlite',
+ 'memory' => true
);
}