Commit ab65ad5b authored by romanb's avatar romanb

Refactorings. Started with new hydrator for 2.0.

parent ff112209
......@@ -52,7 +52,7 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*
* @var string
*/
protected $_customMapperClassName;
protected $_customRepositoryClassName;
/**
*
......@@ -132,7 +132,6 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
* additional keys:
* -- notnull whether or not the column is marked as notnull
* -- values enum values
* -- notblank notblank validator + notnull constraint
* ... many more
*
* @var array $columns
......@@ -322,7 +321,10 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*/
public function isIdentifier($fieldName)
{
return in_array($fieldName, $this->getIdentifier());
if ($this->_identifierType != Doctrine::IDENTIFIER_COMPOSITE) {
return $fieldName === $this->_identifier[0];
}
return in_array($fieldName, $this->_identifier);
}
/**
......@@ -524,6 +526,7 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*/
public function mapColumn($name, $type, $length = null, $options = array(), $prepend = false)
{
// converts 0 => 'primary' to 'primary' => true etc.
foreach ($options as $k => $option) {
if (is_numeric($k)) {
if ( ! empty($option) && $option !== false) {
......@@ -554,7 +557,42 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
$this->_fieldNames[$name] = $fieldName;
}
// Inspect & fill $options
if ($length == null) {
$length = $this->_getDefaultLength($type);
}
$options['type'] = $type;
$options['length'] = $length;
if ( ! $this->_hasDefaultValues && isset($options['default'])) {
$this->_hasDefaultValues = true;
}
if ( ! empty($options['primary'])) {
if ( ! in_array($fieldName, $this->_identifier)) {
$this->_identifier[] = $fieldName;
}
/*if (isset($options['autoincrement']) && $options['autoincrement'] === true) {
}*/
}
/*
if ( ! isset($options['immutable'])) {
$options['immutable'] = false;
}*/
if ($prepend) {
$this->_mappedColumns = array_merge(array($name => $options), $this->_mappedColumns);
} else {
$this->_mappedColumns[$name] = $options;
}
$this->_columnCount++;
}
private function _getDefaultLength($type)
{
switch ($type) {
case 'string':
case 'clob':
......@@ -565,44 +603,21 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
case 'blob':
case 'gzip':
// use php int max
$length = 2147483647;
break;
return 2147483647;
case 'boolean':
$length = 1;
return 1;
case 'date':
// YYYY-MM-DD ISO 8601
$length = 10;
return 10;
case 'time':
// HH:NN:SS+00:00 ISO 8601
$length = 14;
return 14;
case 'timestamp':
// YYYY-MM-DDTHH:MM:SS+00:00 ISO 8601
$length = 25;
break;
return 25;
}
}
$options['type'] = $type;
$options['length'] = $length;
if ($prepend) {
$this->_mappedColumns = array_merge(array($name => $options), $this->_mappedColumns);
} else {
$this->_mappedColumns[$name] = $options;
}
if ( ! empty($options['primary'])) {
if ( ! in_array($fieldName, $this->_identifier)) {
$this->_identifier[] = $fieldName;
}
}
if (isset($options['default'])) {
$this->_hasDefaultValues = true;
}
$this->_columnCount++;
}
/**
* setColumn
*
......@@ -1733,6 +1748,7 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
* Registers a custom mapper for the entity class.
*
* @param string $mapperClassName The class name of the custom mapper.
* @deprecated
*/
public function setCustomMapperClass($mapperClassName)
{
......@@ -1740,7 +1756,22 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
throw new Doctrine_ClassMetadata_Exception("The custom mapper must be a subclass"
. " of Doctrine_Mapper.");
}
$this->_customMapperClassName = $mapperClassName;
$this->_customRepositoryClassName = $mapperClassName;
}
/**
* Registers a custom mapper for the entity class.
*
* @param string $mapperClassName The class name of the custom mapper.
* @deprecated
*/
public function setCustomRepositoryClass($repositoryClassName)
{
if ( ! is_subclass_of($repositoryClassName, 'Doctrine_EntityRepository')) {
throw new Doctrine_ClassMetadata_Exception("The custom repository must be a subclass"
. " of Doctrine_EntityRepository.");
}
$this->_customRepositoryClassName = $repositoryClassName;
}
/**
......@@ -1748,16 +1779,22 @@ class Doctrine_ClassMetadata extends Doctrine_Configurable implements Serializab
*
* @return string|null The name of the custom mapper class or NULL if the entity
* class does not have a custom mapper class.
* @deprecated
*/
public function getCustomMapperClass()
{
return $this->_customMapperClassName;
return $this->_customRepositoryClassName;
}
public function getCustomRepositoryClass()
{
return $this->_customRepositoryClassName;
}
/**
* @todo Thoughts & Implementation.
*/
public function setType($type)
public function setEntityType($type)
{
//Doctrine::CLASSTYPE_ENTITY
//Doctrine::CLASSTYPE_MAPPED_SUPERCLASS
......
......@@ -449,7 +449,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
} else {
// @todo does not take composite keys into account
$list[] = $record->getIncremented();
$ids = $record->identifier();
$list[] = count($ids) > 0 ? array_pop($ids) : null;
}
}
......@@ -564,7 +565,9 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
if ( ! isset($name)) {
foreach ($this->data as $record) {
$value = $record->getIncremented();
// FIXME: composite key support
$ids = $record->identifier();
$value = count($ids) > 0 ? array_pop($ids) : null;
if ($value !== null) {
$list[] = $value;
}
......@@ -583,7 +586,8 @@ class Doctrine_Collection extends Doctrine_Access implements Countable, Iterator
}
} else {
foreach ($this->data as $record) {
$value = $record->getIncremented();
$ids = $record->identifier();
$value = count($ids) > 0 ? array_pop($ids) : null;
if ($value !== null) {
$list[] = $value;
}
......
......@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Configurable');
/**
* Doctrine_Connection
*
......@@ -56,9 +56,13 @@ Doctrine::autoload('Doctrine_Configurable');
* @todo Split up into Doctrine::DBAL::Connection & Doctrine::ORM::EntityManager.
* Doctrine::DBAL::Connection must have no dependencies on ORM components since
* it sits one layer below.
* Right now, this is the unification of these two classes.
*/
abstract class Doctrine_Connection extends Doctrine_Configurable implements Countable, IteratorAggregate
{
/*
* ----------- Connection attributes ---------------
*/
/**
* The PDO database handle.
*
......@@ -66,22 +70,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
protected $dbh;
/**
* The metadata factory is used to retrieve the metadata of entity classes.
*
* @var Doctrine_ClassMetadata_Factory
* @todo package:orm
*/
protected $_metadataFactory;
/**
* An array of mapper objects currently maintained by this connection.
*
* @var array
* @todo package:orm
*/
protected $_mappers = array();
/**
* $_name
*
......@@ -113,6 +101,76 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
protected $supported = array();
/**
* @var array $properties an array of connection properties
*/
protected $properties = array(
'sql_comments' => array(array('start' => '--', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false)),
'identifier_quoting' => array('start' => '"', 'end' => '"','escape' => '"'),
'string_quoting' => array('start' => "'", 'end' => "'", 'escape' => false,
'escape_pattern' => false),
'wildcards' => array('%', '_'),
'varchar_max_length' => 255,
);
/**
* @var array $serverInfo
*/
protected $serverInfo = array();
/**
*
*/
protected $options = array();
/**
* List of all available drivers.
*
* @var array $availableDrivers
*/
private static $availableDrivers = array(
'Mysql', 'Pgsql', 'Oracle', 'Informix', 'Mssql', 'Sqlite', 'Firebird'
);
/**
* The query count. Represents the number of executed database queries by the connection.
*
* @var integer
*/
protected $_count = 0;
/*
* ----------- EntityManager attributes ---------------
*/
/**
* The metadata factory is used to retrieve the metadata of entity classes.
*
* @var Doctrine_ClassMetadata_Factory
* @todo package:orm
*/
protected $_metadataFactory;
/**
* An array of mapper objects currently maintained by this connection.
*
* @var array
* @todo package:orm
*/
protected $_mappers = array();
/**
* The EntityRepository instances.
*
* @var array
*/
private $_repositories = array();
/*
* ----------- Mixed attributes (need to split up) ---------------
*/
/**
* @var array $pendingAttributes An array of pending attributes. When setting attributes
* no connection is needed. When connected all the pending
......@@ -159,49 +217,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
'util' => false,
);
/**
* @var array $properties an array of connection properties
*/
protected $properties = array('sql_comments' => array(array('start' => '--', 'end' => "\n", 'escape' => false),
array('start' => '/*', 'end' => '*/', 'escape' => false)),
'identifier_quoting' => array('start' => '"', 'end' => '"','escape' => '"'),
'string_quoting' => array('start' => "'",
'end' => "'",
'escape' => false,
'escape_pattern' => false),
'wildcards' => array('%', '_'),
'varchar_max_length' => 255,
);
/**
* @var array $serverInfo
*/
protected $serverInfo = array();
/**
*
*/
protected $options = array();
/**
* @var array $availableDrivers an array containing all available drivers
*/
private static $availableDrivers = array(
'Mysql',
'Pgsql',
'Oracle',
'Informix',
'Mssql',
'Sqlite',
'Firebird'
);
/**
* The query count. Represents the number of executed database queries by the connection.
*
* @var integer
*/
protected $_count = 0;
/**
* the constructor
......@@ -240,6 +255,10 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->getAttribute(Doctrine::ATTR_LISTENER)->onOpen($this);
}
/*
* ----------- Connection methods ---------------
*/
/**
* getOption
*
......@@ -268,38 +287,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return $this->options[$option] = $value;
}
/**
* getAttribute
* retrieves a database connection attribute
*
* @param integer $attribute
* @return mixed
*/
public function getAttribute($attribute)
{
if ($attribute >= 100) {
if ( ! isset($this->_attributes[$attribute])) {
return parent::getAttribute($attribute);
}
return $this->_attributes[$attribute];
}
if ($this->isConnected) {
try {
return $this->dbh->getAttribute($attribute);
} catch (Exception $e) {
throw new Doctrine_Connection_Exception('Attribute ' . $attribute . ' not found.');
}
} else {
if ( ! isset($this->pendingAttributes[$attribute])) {
$this->connect();
$this->getAttribute($attribute);
}
return $this->pendingAttributes[$attribute];
}
}
/**
* returns an array of available PDO drivers
*/
......@@ -308,31 +295,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return PDO::getAvailableDrivers();
}
/**
* setAttribute
* sets an attribute
*
* @todo why check for >= 100? has this any special meaning when creating
* attributes?
*
* @param integer $attribute
* @param mixed $value
* @return boolean
*/
public function setAttribute($attribute, $value)
{
if ($attribute >= 100) {
parent::setAttribute($attribute, $value);
} else {
if ($this->isConnected) {
$this->dbh->setAttribute($attribute, $value);
} else {
$this->pendingAttributes[$attribute] = $value;
}
}
return $this;
}
/**
* getName
* returns the name of this driver
......@@ -369,55 +331,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return $this->driverName;
}
/**
* __get
* lazy loads given module and returns it
*
* @see Doctrine_DataDict
* @see Doctrine_Expression
* @see Doctrine_Export
* @see Doctrine_Transaction
* @see Doctrine_Connection::$modules all availible modules
* @param string $name the name of the module to get
* @throws Doctrine_Connection_Exception if trying to get an unknown module
* @return Doctrine_Connection_Module connection module
*/
public function __get($name)
{
if (isset($this->properties[$name])) {
return $this->properties[$name];
}
if ( ! isset($this->modules[$name])) {
throw new Doctrine_Connection_Exception('Unknown module / property ' . $name);
}
if ($this->modules[$name] === false) {
switch ($name) {
case 'unitOfWork':
$this->modules[$name] = new Doctrine_Connection_UnitOfWork($this);
break;
case 'formatter':
$this->modules[$name] = new Doctrine_Formatter($this);
break;
default:
$class = 'Doctrine_' . ucwords($name) . '_' . $this->getDriverName();
$this->modules[$name] = new $class($this);
}
}
return $this->modules[$name];
}
/**
* returns the manager that created this connection
*
* @return Doctrine_Manager
*/
public function getManager()
{
return $this->getParent();
}
/**
* returns the database handler which this connection uses
*
......@@ -850,31 +763,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return $this->execute($statement, $params)->fetchAll(Doctrine::FETCH_BOTH);
}
/**
* query
* queries the database using Doctrine Query Language
* returns a collection of Doctrine_Record objects
*
* <code>
* $users = $conn->query('SELECT u.* FROM User u');
*
* $users = $conn->query('SELECT u.* FROM User u WHERE u.name LIKE ?', array('someone'));
* </code>
*
* @param string $query DQL query
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @see Doctrine_Query
* @return Doctrine_Collection Collection of Doctrine_Record objects
* @todo package:orm
*/
public function query($query, array $params = array(), $hydrationMode = null)
{
$parser = new Doctrine_Query($this);
return $parser->query($query, $params, $hydrationMode);
}
/**
* prepare
*
......@@ -905,38 +793,8 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
}
/**
* query
* queries the database using Doctrine Query Language and returns
* the first record found
*
* <code>
* $user = $conn->queryOne('SELECT u.* FROM User u WHERE u.id = ?', array(1));
*
* $user = $conn->queryOne('SELECT u.* FROM User u WHERE u.name LIKE ? AND u.password = ?',
* array('someone', 'password')
* );
* </code>
*
* @param string $query DQL query
* @param array $params query parameters
* @see Doctrine_Query
* @return Doctrine_Record|false Doctrine_Record object on success,
* boolean false on failure
*/
public function queryOne($query, array $params = array())
{
$parser = new Doctrine_Query($this);
$coll = $parser->query($query, $params);
if ( ! $coll->contains(0)) {
return false;
}
return $coll[0];
}
/**
* queries the database with limit and offset
* added to the query and returns a Doctrine_Connection_Statement object
* queries the database with limit and offset
* added to the query and returns a Doctrine_Connection_Statement object
*
* @param string $query
* @param integer $limit
......@@ -977,7 +835,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
try {
if ( ! empty($params)) {
//echo $query . "<br />";
$stmt = $this->prepare($query);
$stmt->execute($params);
return $stmt;
......@@ -987,14 +844,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->getAttribute(Doctrine::ATTR_LISTENER)->preQuery($event);
if ( ! $event->skipOperation) {
//try {
$stmt = $this->dbh->query($query);
/*} catch (Exception $e) {
if (strstr($e->getMessage(), 'no such column')) {
echo $query . "<br /><br />";
}
}*/
$this->_count++;
}
$this->getAttribute(Doctrine::ATTR_LISTENER)->postQuery($event);
......@@ -1021,6 +871,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
if ( ! empty($params)) {
$stmt = $this->prepare($query);
$stmt->execute($params);
return $stmt->rowCount();
} else {
$event = new Doctrine_Event($this, Doctrine_Event::CONN_EXEC, $query, $params);
......@@ -1067,206 +918,429 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
}
/**
* hasTable
* whether or not this connection has table $name initialized
* Returns the number of queries executed by the connection.
*
* @param mixed $name
* @return boolean
* @deprecated
* @todo package:orm
* @return integer
* @todo Better name: getQueryCount()
*/
public function hasTable($name)
public function count()
{
return isset($this->tables[$name]);
return $this->_count;
}
/**
* Returns the metadata for a class.
* Closes the connection.
*
* @return Doctrine_Metadata
* @deprecated Use getClassMetadata()
* @todo package:orm
* @return void
*/
public function getMetadata($className)
public function close()
{
return $this->getClassMetadata($className);
}
$event = new Doctrine_Event($this, Doctrine_Event::CONN_CLOSE);
$this->getAttribute(Doctrine::ATTR_LISTENER)->preClose($event);
/**
* Returns the metadata for a class.
*
* @return Doctrine_Metadata
* @todo package:orm
*/
public function getClassMetadata($className)
{
if ( ! $this->_metadataFactory) {
$this->_metadataFactory = new Doctrine_ClassMetadata_Factory($this,
new Doctrine_ClassMetadata_CodeDriver());
}
$this->clear();
return $this->_metadataFactory->getMetadataFor($className);
unset($this->dbh);
$this->isConnected = false;
$this->getAttribute(Doctrine::ATTR_LISTENER)->postClose($event);
}
/**
* Sets the driver that is used to obtain metadata informations about entity
* classes.
* Returns the current total transaction nesting level.
*
* @param $driver The driver to use.
* @todo package:orm
* @return integer The nesting level. A value of 0 means theres no active transaction.
*/
public function setClassMetadataDriver($driver)
public function getTransactionLevel()
{
$this->_metadataFactory->setDriver($driver);
return $this->transaction->getTransactionLevel();
}
/**
* Gets a mapper for the specified domain class that is used to map instances of
* the class between the relational database and their object representation.
* errorCode
* Fetch the SQLSTATE associated with the last operation on the database handle
*
* @param string $entityClassName The name of the entity class.
* @return Doctrine_Mapper The mapper object.
* @todo package:orm
* @return integer
*/
/*public function getMapper($entityName)
public function errorCode()
{
if (isset($this->_mappers[$entityName])) {
return $this->_mappers[$entityName];
}
$this->connect();
$metadata = $this->getClassMetadata($entityName);
$customMapperClassName = $metadata->getCustomMapperClass();
if ($customMapperClassName !== null) {
$mapper = new $customMapperClassName($entityName, $metadata);
} else {
// instantiate correct mapper type
$inheritanceType = $metadata->getInheritanceType();
if ($inheritanceType == Doctrine::INHERITANCE_TYPE_JOINED) {
$mapper = new Doctrine_Mapper_Joined($entityName, $metadata);
} else if ($inheritanceType == Doctrine::INHERITANCE_TYPE_SINGLE_TABLE) {
$mapper = new Doctrine_Mapper_SingleTable($entityName, $metadata);
} else if ($inheritanceType == Doctrine::INHERITANCE_TYPE_TABLE_PER_CLASS) {
$mapper = new Doctrine_Mapper_TablePerClass($entityName, $metadata);
} else {
throw new Doctrine_Connection_Exception("Unknown inheritance type '$inheritanceType'. Can't create mapper.");
}
return $this->dbh->errorCode();
}
$this->_mappers[$entityName] = $mapper;
return $mapper;
}*/
/**
* Gets a mapper for the specified domain class that is used to map instances of
* the class between the relational database and their object representation.
* errorInfo
* Fetch extended error information associated with the last operation on the database handle
*
* @param string $entityClassName The name of the entity class.
* @return Doctrine_Mapper The mapper object.
* @todo package:orm
* @return array
*/
public function getMapper($entityName)
public function errorInfo()
{
if (isset($this->_mappers[$entityName])) {
return $this->_mappers[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customMapperClassName = $metadata->getCustomMapperClass();
if ($customMapperClassName !== null) {
$mapper = new $customMapperClassName($entityName, $metadata);
} else {
$mapper = new Doctrine_Mapper($entityName, $metadata);
}
$this->_mappers[$entityName] = $mapper;
$this->connect();
return $mapper;
return $this->dbh->errorInfo();
}
/**
* Gets all mappers that are currently maintained by the connection.
* lastInsertId
*
* @todo package:orm
* Returns the ID of the last inserted row, or the last value from a sequence object,
* depending on the underlying driver.
*
* Note: This method may not return a meaningful or consistent result across different drivers,
* because the underlying database may not even support the notion of auto-increment fields or sequences.
*
* @param string $table Name of the table into which a new row was inserted.
* @param string $field Name of the field into which a new row was inserted.
*/
public function getMappers()
public function lastInsertId($table = null, $field = null)
{
return $this->_mappers;
return $this->sequence->lastInsertId($table, $field);
}
/**
* returns an iterator that iterates through all
* initialized table objects
* beginTransaction
* Start a transaction or set a savepoint.
*
* <code>
* foreach ($conn as $index => $table) {
* print $table; // get a string representation of each table object
* }
* </code>
* if trying to set a savepoint and there is no active transaction
* a new transaction is being started
*
* @return ArrayIterator SPL ArrayIterator object
* Listeners: onPreTransactionBegin, onTransactionBegin
*
* @param string $savepoint name of a savepoint to set
* @throws Doctrine_Transaction_Exception if the transaction fails at database level
* @return integer current transaction nesting level
*/
public function getIterator()
public function beginTransaction($savepoint = null)
{
return new ArrayIterator($this->_mappers);
return $this->transaction->beginTransaction($savepoint);
}
/**
* Returns the number of queries executed by the connection.
* commit
* Commit the database changes done during a transaction that is in
* progress or release a savepoint. This function may only be called when
* auto-committing is disabled, otherwise it will fail.
*
* @return integer
* @todo Better name: getQueryCount()
* Listeners: onPreTransactionCommit, onTransactionCommit
*
* @param string $savepoint name of a savepoint to release
* @throws Doctrine_Transaction_Exception if the transaction fails at PDO level
* @throws Doctrine_Validator_Exception if the transaction fails due to record validations
* @return boolean false if commit couldn't be performed, true otherwise
*/
public function count()
public function commit($savepoint = null)
{
return $this->_count;
return $this->transaction->commit($savepoint);
}
/**
* create
* creates a record
* rollback
* Cancel any database changes done during a transaction or since a specific
* savepoint that is in progress. This function may only be called when
* auto-committing is disabled, otherwise it will fail. Therefore, a new
* transaction is implicitly started after canceling the pending changes.
*
* create creates a record
* @param string $name component name
* @return Doctrine_Record Doctrine_Record object
* @todo Any strong reasons why this should not be removed?
* @todo package:orm
* this method can be listened with onPreTransactionRollback and onTransactionRollback
* eventlistener methods
*
* @param string $savepoint name of a savepoint to rollback to
* @throws Doctrine_Transaction_Exception if the rollback operation fails at database level
* @return boolean false if rollback couldn't be performed, true otherwise
*/
public function create($name)
public function rollback($savepoint = null)
{
return $this->getMapper($name)->create();
$this->transaction->rollback($savepoint);
}
/**
* Creates a new Doctrine_Query object that operates on this connection.
* createDatabase
*
* @return Doctrine_Query
* @todo package:orm
* Method for creating the database for the connection instance
*
* @return mixed Will return an instance of the exception thrown if the create database fails, otherwise it returns a string detailing the success
*/
public function createQuery($dql = "")
public function createDatabase()
{
$query = new Doctrine_Query($this);
if ( ! empty($dql)) {
$query->parseQuery($dql);
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');
}
return $query;
$manager = $this->getManager();
$info = $manager->parsePdoDsn($dsn);
$username = $this->getOption('username');
$password = $this->getOption('password');
// Make connection without database specified so we can create it
$connect = $manager->openConnection(new PDO($info['scheme'] . ':host=' . $info['host'], $username, $password), 'tmp_connection', false);
// Create database
$connect->export->createDatabase($info['dbname']);
// Close the tmp connection with no database
$manager->closeConnection($connect);
// Close original connection
$manager->closeConnection($this);
// Reopen original connection with newly created database
$manager->openConnection(new PDO($info['dsn'], $username, $password), $this->getName(), true);
return 'Successfully created database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
} catch (Exception $e) {
return $e;
}
}
/**
* flush
* saves all the records from all tables
* this operation is isolated using a transaction
* dropDatabase
*
* @throws PDOException if something went wrong at database level
* @return void
* @todo package:orm
* Method for dropping the database for the connection instance
*
* @return mixed Will return an instance of the exception thrown if the drop database fails, otherwise it returns a string detailing the success
*/
public function flush()
public function dropDatabase()
{
$this->beginInternalTransaction();
$this->unitOfWork->flush();
$this->commit();
}
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()->parsePdoDsn($dsn);
$this->export->dropDatabase($info['dbname']);
return 'Successfully dropped database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
} catch (Exception $e) {
return $e;
}
}
/**
* returns a string representation of this object
* @return string
*/
public function __toString()
{
return Doctrine_Lib::getConnectionAsString($this);
}
/*
* ----------- EntityManager methods ---------------
*/
/**
* query
* queries the database using Doctrine Query Language
* returns a collection of Doctrine_Record objects
*
* <code>
* $users = $conn->query('SELECT u.* FROM User u');
*
* $users = $conn->query('SELECT u.* FROM User u WHERE u.name LIKE ?', array('someone'));
* </code>
*
* @param string $query DQL query
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @see Doctrine_Query
* @return Doctrine_Collection Collection of Doctrine_Record objects
* @todo package:orm
*/
public function query($query, array $params = array(), $hydrationMode = null)
{
$parser = new Doctrine_Query($this);
return $parser->query($query, $params, $hydrationMode);
}
/**
* query
* queries the database using Doctrine Query Language and returns
* the first record found
*
* <code>
* $user = $conn->queryOne('SELECT u.* FROM User u WHERE u.id = ?', array(1));
*
* $user = $conn->queryOne('SELECT u.* FROM User u WHERE u.name LIKE ? AND u.password = ?',
* array('someone', 'password')
* );
* </code>
*
* @param string $query DQL query
* @param array $params query parameters
* @see Doctrine_Query
* @return Doctrine_Record|false Doctrine_Record object on success,
* boolean false on failure
*/
public function queryOne($query, array $params = array())
{
$parser = new Doctrine_Query($this);
$coll = $parser->query($query, $params);
if ( ! $coll->contains(0)) {
return false;
}
return $coll[0];
}
/**
* hasTable
* whether or not this connection has table $name initialized
*
* @param mixed $name
* @return boolean
* @deprecated
* @todo package:orm
*/
public function hasTable($name)
{
return isset($this->tables[$name]);
}
/**
* Returns the metadata for a class.
*
* @return Doctrine_Metadata
* @deprecated Use getClassMetadata()
* @todo package:orm
*/
public function getMetadata($className)
{
return $this->getClassMetadata($className);
}
/**
* Returns the metadata for a class.
*
* @return Doctrine_Metadata
* @todo package:orm
*/
public function getClassMetadata($className)
{
if ( ! $this->_metadataFactory) {
$this->_metadataFactory = new Doctrine_ClassMetadata_Factory($this,
new Doctrine_ClassMetadata_CodeDriver());
}
return $this->_metadataFactory->getMetadataFor($className);
}
/**
* Sets the driver that is used to obtain metadata informations about entity
* classes.
*
* @param $driver The driver to use.
* @todo package:orm
*/
public function setClassMetadataDriver($driver)
{
$this->_metadataFactory->setDriver($driver);
}
/**
* Gets a mapper for the specified domain class that is used to map instances of
* the class between the relational database and their object representation.
*
* @param string $entityClassName The name of the entity class.
* @return Doctrine_Mapper The mapper object.
* @todo package:orm
*/
public function getMapper($entityName)
{
if (isset($this->_mappers[$entityName])) {
return $this->_mappers[$entityName];
}
$metadata = $this->getClassMetadata($entityName);
$customMapperClassName = $metadata->getCustomMapperClass();
if ($customMapperClassName !== null) {
$mapper = new $customMapperClassName($entityName, $metadata);
} else {
$mapper = new Doctrine_Mapper($entityName, $metadata);
}
$this->_mappers[$entityName] = $mapper;
return $mapper;
}
/**
* Gets all mappers that are currently maintained by the connection.
*
* @todo package:orm
*/
public function getMappers()
{
return $this->_mappers;
}
/**
* returns an iterator that iterates through all
* initialized table objects
*
* <code>
* foreach ($conn as $index => $table) {
* print $table; // get a string representation of each table object
* }
* </code>
*
* @return ArrayIterator SPL ArrayIterator object
*/
public function getIterator()
{
return new ArrayIterator($this->_mappers);
}
/**
* create
* creates a record
*
* create creates a record
* @param string $name component name
* @return Doctrine_Record Doctrine_Record object
* @todo Any strong reasons why this should not be removed?
* @todo package:orm
*/
public function create($name)
{
return $this->getMapper($name)->create();
}
/**
* Creates a new Doctrine_Query object that operates on this connection.
*
* @return Doctrine_Query
* @todo package:orm
*/
public function createQuery($dql = "")
{
$query = new Doctrine_Query($this);
if ( ! empty($dql)) {
$query->parseQuery($dql);
}
return $query;
}
/**
* flush
* saves all the records from all tables
* this operation is isolated using a transaction
*
* @throws PDOException if something went wrong at database level
* @return void
* @todo package:orm
*/
public function flush()
{
$this->beginInternalTransaction();
$this->unitOfWork->flush();
$this->commit();
}
/**
* clear
......@@ -1275,12 +1349,16 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
* @return void
* @todo package:orm
*/
public function clear()
public function clear($entityName = null)
{
if ($entityName === null) {
$this->unitOfWork->detachAll();
foreach ($this->_mappers as $mapper) {
$mapper->clear(); // clear identity map of each mapper
}
} else {
$this->getMapper($entityName)->clear();
}
}
/**
......@@ -1299,69 +1377,54 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->exported = array();
}
/**
* Closes the connection.
*
* @return void
*/
public function close()
public function save(Doctrine_Record $entity, $conn = null)
{
$event = new Doctrine_Event($this, Doctrine_Event::CONN_CLOSE);
$this->getAttribute(Doctrine::ATTR_LISTENER)->preClose($event);
$this->clear();
$this->getMapper($entity->getClassName())->save($entity, $conn);
}
unset($this->dbh);
$this->isConnected = false;
public function remove(Doctrine_Record $entity, $conn = null)
{
$this->getMapper($entity->getClassName())->delete($entity, $conn);
}
$this->getAttribute(Doctrine::ATTR_LISTENER)->postClose($event);
public function createEntity($entityName, array $data = array())
{
return $this->getMapper($entityName)->create($data);
}
/**
* Returns the current total transaction nesting level.
*
* @return integer The nesting level. A value of 0 means theres no active transaction.
*/
public function getTransactionLevel()
public function detach(Doctrine_Record $entity)
{
return $this->transaction->getTransactionLevel();
$this->getMapper($entity->getClassName())->detach($entity);
}
/**
* Returns the current internal transaction nesting level.
*
* @return integer The nesting level. A value of 0 means theres no active transaction.
* @todo package:orm???
*/
public function getInternalTransactionLevel()
public function removeRecord(Doctrine_Record $entity)
{
return $this->transaction->getInternalTransactionLevel();
$this->getMapper($entity->getClassName())->removeRecord($entity);
}
/**
* errorCode
* Fetch the SQLSTATE associated with the last operation on the database handle
*
* @return integer
*/
public function errorCode()
public function manage(Doctrine_Record $entity)
{
$this->connect();
$this->getMapper($entity->getClassName())->manage($entity);
}
return $this->dbh->errorCode();
public function executeNamedQuery($name, $params = array(), $hydrationMode = Doctrine::HYDRATE_RECORD)
{
return Doctrine_Manager::getInstance()
->createNamedQuery($name)
->execute($params, $hydrationMode);
}
/**
* errorInfo
* Fetch extended error information associated with the last operation on the database handle
* Returns the current internal transaction nesting level.
*
* @return array
* @return integer The nesting level. A value of 0 means theres no active transaction.
* @todo package:orm???
*/
public function errorInfo()
public function getInternalTransactionLevel()
{
$this->connect();
return $this->dbh->errorInfo();
return $this->transaction->getInternalTransactionLevel();
}
/**
......@@ -1405,41 +1468,6 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return $this->getAttribute(Doctrine::ATTR_QUERY_CACHE);
}
/**
* lastInsertId
*
* Returns the ID of the last inserted row, or the last value from a sequence object,
* depending on the underlying driver.
*
* Note: This method may not return a meaningful or consistent result across different drivers,
* because the underlying database may not even support the notion of auto-increment fields or sequences.
*
* @param string $table Name of the table into which a new row was inserted.
* @param string $field Name of the field into which a new row was inserted.
*/
public function lastInsertId($table = null, $field = null)
{
return $this->sequence->lastInsertId($table, $field);
}
/**
* beginTransaction
* Start a transaction or set a savepoint.
*
* if trying to set a savepoint and there is no active transaction
* a new transaction is being started
*
* Listeners: onPreTransactionBegin, onTransactionBegin
*
* @param string $savepoint name of a savepoint to set
* @throws Doctrine_Transaction_Exception if the transaction fails at database level
* @return integer current transaction nesting level
*/
public function beginTransaction($savepoint = null)
{
return $this->transaction->beginTransaction($savepoint);
}
/**
* Initiates a transaction.
*
......@@ -1454,157 +1482,137 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
}
/**
* commit
* Commit the database changes done during a transaction that is in
* progress or release a savepoint. This function may only be called when
* auto-committing is disabled, otherwise it will fail.
* Enter description here...
*
* Listeners: onPreTransactionCommit, onTransactionCommit
*
* @param string $savepoint name of a savepoint to release
* @throws Doctrine_Transaction_Exception if the transaction fails at PDO level
* @throws Doctrine_Validator_Exception if the transaction fails due to record validations
* @return boolean false if commit couldn't be performed, true otherwise
* @todo To EntityManager
*/
public function commit($savepoint = null)
public function getRepository($entityName)
{
return $this->transaction->commit($savepoint);
if (isset($this->_repositories[$entityName])) {
return $this->_repositories[$entityName];
}
/**
* rollback
* Cancel any database changes done during a transaction or since a specific
* savepoint that is in progress. This function may only be called when
* auto-committing is disabled, otherwise it will fail. Therefore, a new
* transaction is implicitly started after canceling the pending changes.
*
* this method can be listened with onPreTransactionRollback and onTransactionRollback
* eventlistener methods
*
* @param string $savepoint name of a savepoint to rollback to
* @throws Doctrine_Transaction_Exception if the rollback operation fails at database level
* @return boolean false if rollback couldn't be performed, true otherwise
*/
public function rollback($savepoint = null)
{
$this->transaction->rollback($savepoint);
$metadata = $this->getClassMetadata($entityName);
$customRepositoryClassName = $metadata->getCustomRepositoryClass();
if ($customRepositoryClassName !== null) {
$repository = new $customRepositoryClassName($entityName, $metadata);
} else {
$repository = new Doctrine_EntityRepository($entityName, $metadata);
}
$this->_repositories[$entityName] = $repository;
return $repository;
}
/*
* ----------- Mixed methods (need to figure out where they go) ---------------
*/
/**
* createDatabase
*
* Method for creating the database for the connection instance
* getAttribute
* retrieves a database connection attribute
*
* @return mixed Will return an instance of the exception thrown if the create database fails, otherwise it returns a string detailing the success
* @param integer $attribute
* @return mixed
*/
public function createDatabase()
public function getAttribute($attribute)
{
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');
if ($attribute >= 100) {
if ( ! isset($this->_attributes[$attribute])) {
return parent::getAttribute($attribute);
}
return $this->_attributes[$attribute];
}
$manager = $this->getManager();
$info = $manager->parsePdoDsn($dsn);
$username = $this->getOption('username');
$password = $this->getOption('password');
// Make connection without database specified so we can create it
$connect = $manager->openConnection(new PDO($info['scheme'] . ':host=' . $info['host'], $username, $password), 'tmp_connection', false);
// Create database
$connect->export->createDatabase($info['dbname']);
// Close the tmp connection with no database
$manager->closeConnection($connect);
// Close original connection
$manager->closeConnection($this);
// Reopen original connection with newly created database
$manager->openConnection(new PDO($info['dsn'], $username, $password), $this->getName(), true);
return 'Successfully created database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
if ($this->isConnected) {
try {
return $this->dbh->getAttribute($attribute);
} catch (Exception $e) {
return $e;
throw new Doctrine_Connection_Exception('Attribute ' . $attribute . ' not found.');
}
} else {
if ( ! isset($this->pendingAttributes[$attribute])) {
$this->connect();
$this->getAttribute($attribute);
}
return $this->pendingAttributes[$attribute];
}
}
/**
* dropDatabase
* setAttribute
* sets an attribute
*
* Method for dropping the database for the connection instance
* @todo why check for >= 100? has this any special meaning when creating
* attributes?
*
* @return mixed Will return an instance of the exception thrown if the drop database fails, otherwise it returns a string detailing the success
* @param integer $attribute
* @param mixed $value
* @return boolean
*/
public function dropDatabase()
public function setAttribute($attribute, $value)
{
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');
if ($attribute >= 100) {
parent::setAttribute($attribute, $value);
} else {
if ($this->isConnected) {
$this->dbh->setAttribute($attribute, $value);
} else {
$this->pendingAttributes[$attribute] = $value;
}
$info = $this->getManager()->parsePdoDsn($dsn);
$this->export->dropDatabase($info['dbname']);
return 'Successfully dropped database for connection "' . $this->getName() . '" named "' . $info['dbname'] . '"';
} catch (Exception $e) {
return $e;
}
return $this;
}
/**
* returns a string representation of this object
* @return string
* __get
* lazy loads given module and returns it
*
* @see Doctrine_DataDict
* @see Doctrine_Expression
* @see Doctrine_Export
* @see Doctrine_Transaction
* @see Doctrine_Connection::$modules all availible modules
* @param string $name the name of the module to get
* @throws Doctrine_Connection_Exception if trying to get an unknown module
* @return Doctrine_Connection_Module connection module
*/
public function __toString()
public function __get($name)
{
return Doctrine_Lib::getConnectionAsString($this);
if (isset($this->properties[$name])) {
return $this->properties[$name];
}
public function hasAttribute($key)
{
switch ($key) {
case Doctrine::ATTR_COLL_KEY:
case Doctrine::ATTR_LISTENER:
case Doctrine::ATTR_RECORD_LISTENER:
case Doctrine::ATTR_QUOTE_IDENTIFIER:
case Doctrine::ATTR_SEQCOL_NAME:
case Doctrine::ATTR_FIELD_CASE:
case Doctrine::ATTR_IDXNAME_FORMAT:
case Doctrine::ATTR_SEQNAME_FORMAT:
case Doctrine::ATTR_DBNAME_FORMAT:
case Doctrine::ATTR_TBLCLASS_FORMAT:
case Doctrine::ATTR_TBLNAME_FORMAT:
case Doctrine::ATTR_EXPORT:
case Doctrine::ATTR_DECIMAL_PLACES:
case Doctrine::ATTR_PORTABILITY:
case Doctrine::ATTR_VALIDATE:
case Doctrine::ATTR_QUERY_LIMIT:
case Doctrine::ATTR_DEFAULT_TABLE_TYPE:
case Doctrine::ATTR_DEF_TEXT_LENGTH:
case Doctrine::ATTR_DEF_VARCHAR_LENGTH:
case Doctrine::ATTR_DEF_TABLESPACE:
case Doctrine::ATTR_EMULATE_DATABASE:
case Doctrine::ATTR_USE_NATIVE_ENUM:
case Doctrine::ATTR_CREATE_TABLES:
case Doctrine::ATTR_COLL_LIMIT:
case Doctrine::ATTR_CACHE: // deprecated
case Doctrine::ATTR_RESULT_CACHE:
case Doctrine::ATTR_CACHE_LIFESPAN: // deprecated
case Doctrine::ATTR_RESULT_CACHE_LIFESPAN:
case Doctrine::ATTR_LOAD_REFERENCES:
case Doctrine::ATTR_THROW_EXCEPTIONS:
case Doctrine::ATTR_QUERY_CACHE:
case Doctrine::ATTR_QUERY_CACHE_LIFESPAN:
case Doctrine::ATTR_MODEL_LOADING:
case Doctrine::ATTR_METADATA_CACHE:
case Doctrine::ATTR_METADATA_CACHE_LIFESPAN:
return true;
if ( ! isset($this->modules[$name])) {
throw new Doctrine_Connection_Exception('Unknown module / property ' . $name);
}
if ($this->modules[$name] === false) {
switch ($name) {
case 'unitOfWork':
$this->modules[$name] = new Doctrine_Connection_UnitOfWork($this);
break;
case 'formatter':
$this->modules[$name] = new Doctrine_Formatter($this);
break;
default:
return false;
$class = 'Doctrine_' . ucwords($name) . '_' . $this->getDriverName();
$this->modules[$name] = new $class($this);
}
}
return $this->modules[$name];
}
/**
* returns the manager that created this connection
*
* @return Doctrine_Manager
*/
public function getManager()
{
return $this->getParent();
}
}
......@@ -20,7 +20,23 @@
*/
/**
* Doctrine_Connection_UnitOfWork
* The UnitOfWork is responsible for writing out changes to the database at
* the correct time and in the correct order.
*
* Some terminology:
*
* <b>New entity</b>: From the point of view of the unitOfWork 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 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.
*
* <b>Dirty entity</b>: ...
*
* <b>Removed entity</b>: ...
*
* <b>Clean entity</b>: ...
*
* @package Doctrine
* @subpackage Connection
......@@ -105,12 +121,19 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
*/
public function registerNew(Doctrine_Record $entity)
{
if (isset($this->_dirtyEntities[$entity->getOid()])) {
if ( ! $entity->identifier()) {
throw new Doctrine_Connection_Exception("Entity without identity "
. "can't be registered as new.");
}
$oid = $entity->getOid();
if (isset($this->_dirtyEntities[$oid])) {
throw new Doctrine_Connection_Exception("Dirty object can't be registered as new.");
} else if (isset($this->_removedEntities[$entity->getOid()])) {
} else if (isset($this->_removedEntities[$oid])) {
throw new Doctrine_Connection_Exception("Removed object can't be registered as new.");
} else if (isset($this->_newEntities[$oid])) {
throw new Doctrine_Connection_Exception("Object already registered as new. Can't register twice.");
}
$this->_newEntities[$entity->getOid()] = $entity;
$this->_newEntities[$oid] = $entity;
}
public function isRegisteredNew(Doctrine_Record $entity)
......@@ -131,13 +154,18 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
*/
public function registerDirty(Doctrine_Record $entity)
{
if ( ! $entity->identifier()) {
throw new Doctrine_Connection_Exception("Entity without identity "
. "can't be registered as dirty.");
}
$oid = $entity->getOid();
if (isset($this->_removedEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("Removed object can't be registered as dirty.");
} else if (isset($this->_newEntities[$entity->getOid()])) {
throw new Doctrine_Connection_Exception("");
}
if ( ! isset($this->_dirtyEntities[$oid], $this->_newEntities[$oid])) {
$this->_dirtyEntities[$entity->getOid()] = $entity;
}
}
public function isRegisteredDirty(Doctrine_Record $entity)
{
......@@ -149,8 +177,21 @@ class Doctrine_Connection_UnitOfWork extends Doctrine_Connection_Module
*/
public function registerRemoved(Doctrine_Record $entity)
{
if ($entity->isTransient()) {
return;
}
$this->unregisterIdentity($entity);
$this->_removedEntities[$entity->getOid()] = $entity;
$oid = $entity->getOid();
if (isset($this->_newEntities[$oid])) {
unset($this->_newEntities[$oid]);
return;
}
if (isset($this->_dirtyEntities[$oid])) {
unset($this->_dirtyEntities[$oid]);
}
if ( ! isset($this->_removedEntities[$oid])) {
$this->_removedEntities[$oid] = $entity;
}
}
public function isRegisteredRemoved(Doctrine_Record $entity)
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* Base class for all custom user-defined repositories.
* Provides basic finder methods, common to all repositories.
*
* @package Doctrine
* @subpackage EntityRepository
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision$
* @author Roman Borschel <roman@code-factory.org>
* @todo package:orm
*/
class Doctrine_EntityRepository
{
protected $_entityName;
protected $_conn;
protected $_classMetadata;
public function __construct($entityName, Doctrine_ClassMetadata $classMetadata)
{
$this->_entityName = $entityName;
$this->_conn = $classMetadata->getConnection();
$this->_classMetadata = $classMetadata;
}
/**
* createQuery
* creates a new Doctrine_Query object and adds the component name
* of this table as the query 'from' part
*
* @param string Optional alias name for component aliasing.
*
* @return Doctrine_Query
*/
protected function _createQuery($alias = '')
{
if ( ! empty($alias)) {
$alias = ' ' . trim($alias);
}
return Doctrine_Query::create($this->_conn)->from($this->_entityName . $alias);
}
/**
* clear
* clears the first level cache (identityMap)
*
* @return void
* @todo what about a more descriptive name? clearIdentityMap?
*/
public function clear()
{
$this->_conn->unitOfWork->clearIdentitiesForEntity($this->_classMetadata->getRootClassName());
}
/**
* Finds an entity by its primary key.
*
* @param $id database row id
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return mixed Array or Doctrine_Record or false if no result
* @todo Remove. Move to EntityRepository.
*/
public function find($id, $hydrationMode = null)
{
if (is_null($id)) {
return false;
}
if (is_array($id) && count($id) > 1) {
// it's a composite key. keys = field names, values = values.
$values = array_values($id);
$keys = array_keys($id);
} else {
$values = is_array($id) ? array_values($id) : array($id);
$keys = $this->_classMetadata->getIdentifier();
}
return $this->_createQuery()
->where(implode(' = ? AND ', $keys) . ' = ?')
->fetchOne($values, $hydrationMode);
}
/**
* Finds all entities of the mapper's class.
* Use with care.
*
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return Doctrine_Collection
*/
public function findAll($hydrationMode = null)
{
return $this->_createQuery()->execute(array(), $hydrationMode);
}
/**
* findBy
*
* @param string $column
* @param string $value
* @param string $hydrationMode
* @return void
*/
protected function findBy($fieldName, $value, $hydrationMode = null)
{
return $this->_createQuery()->where($fieldName . ' = ?')->execute(array($value), $hydrationMode);
}
/**
* findOneBy
*
* @param string $column
* @param string $value
* @param string $hydrationMode
* @return void
*/
protected function findOneBy($fieldName, $value, $hydrationMode = null)
{
$results = $this->_createQuery()->where($fieldName . ' = ?')->limit(1)->execute(
array($value), $hydrationMode);
return $hydrationMode === Doctrine::HYDRATE_ARRAY ? array_shift($results) : $results->getFirst();
}
/**
* findBySql
* finds records with given SQL where clause
* returns a collection of records
*
* @param string $dql DQL after WHERE clause
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @return Doctrine_Collection
*
* @todo This actually takes DQL, not SQL, but it requires column names
* instead of field names. This should be fixed to use raw SQL instead.
*/
public function findBySql($dql, array $params = array(), $hydrationMode = null)
{
return $this->_createQuery()->where($dql)->execute($params, $hydrationMode);
}
/**
* findByDql
* finds records with given DQL where clause
* returns a collection of records
*
* @param string $dql DQL after WHERE clause
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @return Doctrine_Collection
*/
public function findByDql($dql, array $params = array(), $hydrationMode = null)
{
$query = new Doctrine_Query($this->_conn);
$component = $this->getComponentName();
$dql = 'FROM ' . $component . ' WHERE ' . $dql;
return $query->query($dql, $params, $hydrationMode);
}
/**
* Adds support for magic finders.
* findByColumnName, findByRelationAlias
* findById, findByContactId, etc.
*
* @return void
* @throws Doctrine_Mapper_Exception If the method called is an invalid find* method
* or no find* method at all and therefore an invalid
* method call.
*/
public function __call($method, $arguments)
{
if (substr($method, 0, 6) == 'findBy') {
$by = substr($method, 6, strlen($method));
$method = 'findBy';
} else if (substr($method, 0, 9) == 'findOneBy') {
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
} else {
throw new Doctrine_Mapper_Exception("Undefined method '$method'.");
}
if (isset($by)) {
if ( ! isset($arguments[0])) {
throw new Doctrine_Mapper_Exception('You must specify the value to findBy.');
}
$fieldName = Doctrine::tableize($by);
$hydrationMode = isset($arguments[1]) ? $arguments[1]:null;
if ($this->_classMetadata->hasField($fieldName)) {
return $this->$method($fieldName, $arguments[0], $hydrationMode);
} else if ($this->_classMetadata->hasRelation($by)) {
$relation = $this->_classMetadata->getRelation($by);
if ($relation['type'] === Doctrine_Relation::MANY) {
throw new Doctrine_Mapper_Exception('Cannot findBy many relationship.');
}
return $this->$method($relation['local'], $arguments[0], $hydrationMode);
} else {
throw new Doctrine_Mapper_Exception('Cannot find by: ' . $by . '. Invalid field or relationship alias.');
}
}
}
}
\ No newline at end of file
......@@ -52,7 +52,8 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
* 'table' => Table object,
* 'parent' => Parent DQL alias (if any),
* 'relation' => Relation object (if any),
* 'map' => Custom index to use as the key in the result (if any)
* 'map' => Custom index to use as the key in the result (if any),
* 'agg' => List of aggregate values (sql alias => dql alias)
* )
* )
* @return mixed The created object/array graph.
......@@ -82,7 +83,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// Used variables during hydration
reset($this->_queryComponents);
$rootAlias = key($this->_queryComponents);
$rootComponentName = $this->_queryComponents[$rootAlias]['mapper']->getComponentName();
$rootComponentName = $this->_queryComponents[$rootAlias]['table']->getComponentName();
// if only one component is involved we can make our lives easier
$isSimpleQuery = count($this->_queryComponents) <= 1;
// Holds hydration listeners that get called during hydration
......@@ -110,7 +111,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
foreach ($this->_queryComponents as $dqlAlias => $component) {
// disable lazy-loading of related elements during hydration
$component['table']->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, false);
$componentName = $component['mapper']->getComponentName();
$componentName = $component['table']->getClassName();
$listeners[$componentName] = $component['table']->getRecordListener();
$identifierMap[$dqlAlias] = array();
$prev[$dqlAlias] = array();
......@@ -127,9 +128,8 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
//
// hydrate the data of the root entity from the current row
//
$table = $this->_queryComponents[$rootAlias]['table'];
$mapper = $this->_queryComponents[$rootAlias]['mapper'];
$componentName = $mapper->getComponentName();
$class = $this->_queryComponents[$rootAlias]['table'];
$componentName = $class->getComponentName();
// just event stuff
$event->set('data', $rowData[$rootAlias]);
......@@ -175,9 +175,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$map = $this->_queryComponents[$dqlAlias];
$table = $map['table'];
$mapper = $map['mapper'];
$componentName = $mapper->getComponentName();
$componentName = $map['table']->getComponentName();
// just event stuff
$event->set('data', $data);
......@@ -186,7 +184,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$parent = $map['parent'];
$relation = $map['relation'];
$relationAlias = $map['relation']->getAlias();
$relationAlias = $relation->getAlias();
$path = $parent . '.' . $dqlAlias;
......@@ -195,16 +193,19 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
}
// check the type of the relation
if ( ! $relation->isOneToOne() && $driver->initRelated($prev[$parent], $relationAlias)) {
if ( ! $relation->isOneToOne()) {
$oneToOne = false;
// append element
if (isset($nonemptyComponents[$dqlAlias])) {
$driver->initRelated($prev[$parent], $relationAlias);
if ( ! isset($identifierMap[$path][$id[$parent]][$id[$dqlAlias]])) {
$element = $driver->getElement($data, $componentName);
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
if ($field = $this->_getCustomIndexField($dqlAlias)) {
// TODO: we should check this earlier. Fields used in INDEXBY
// must be unique. Then this can be removed here.
......@@ -223,7 +224,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$index = $identifierMap[$path][$id[$parent]][$id[$dqlAlias]];
}
// register collection for later snapshots
$driver->registerCollection($prev[$parent][$relationAlias]);
//$driver->registerCollection($prev[$parent][$relationAlias]);
}
} else {
// 1-1 relation
......@@ -319,7 +320,13 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$cache[$key]['dqlAlias'] = $this->_tableAliases[strtolower(implode('__', $e))];
$mapper = $this->_queryComponents[$cache[$key]['dqlAlias']]['mapper'];
$classMetadata = $mapper->getClassMetadata();
// check whether it's an aggregate value or a regular field
if (isset($this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$columnName])) {
$fieldName = $this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$columnName];
} else {
$fieldName = $mapper->getFieldName($columnName);
}
$cache[$key]['fieldName'] = $fieldName;
// cache identifier information
......@@ -343,10 +350,6 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$dqlAlias = $cache[$key]['dqlAlias'];
$fieldName = $cache[$key]['fieldName'];
if (isset($this->_queryComponents[$dqlAlias]['agg'][$fieldName])) {
$fieldName = $this->_queryComponents[$dqlAlias]['agg'][$fieldName];
}
if ($cache[$key]['isIdentifier']) {
$id[$dqlAlias] .= '|' . $value;
}
......
......@@ -71,8 +71,6 @@ class Doctrine_Hydrator_ArrayDriver
if ( ! isset($data[$name])) {
$data[$name] = array();
}
return true;
}
/**
......
......@@ -20,7 +20,7 @@
*/
/**
* Doctrine_Hydrate_RecordDriver
* Doctrine_Hydrator_RecordDriver
* Hydration strategy used for creating graphs of entity objects.
*
* @package Doctrine
......@@ -34,8 +34,13 @@
*/
class Doctrine_Hydrator_RecordDriver
{
/** Collections initialized by the driver */
protected $_collections = array();
/** Mappers */
protected $_mappers = array();
/** Memory for initialized relations */
private $_initializedRelations = array();
/** Null object */
private $_nullObject;
public function __construct()
......@@ -53,21 +58,26 @@ class Doctrine_Hydrator_RecordDriver
public function getLastKey($coll)
{
// check needed because of mixed results
if (is_array($coll)) {
end($coll);
return key($coll);
} else {
$coll->end();
return $coll->key();
}
}
public function initRelated($record, $name)
public function initRelated(Doctrine_Record $record, $name)
{
return true;
/*
if ( ! is_array($record)) {
$record[$name];
return true;
if ( ! isset($this->_initializedRelations[$record->getOid()][$name])) {
$relation = $record->getClassMetadata()->getRelation($name);
$relatedClass = $relation->getTable();
$coll = $this->getElementCollection($relatedClass->getClassName());
$coll->setReference($record, $relation);
$record[$name] = $coll;
$this->_initializedRelations[$record->getOid()][$name] = true;
}
return false;
*/
}
public function registerCollection(Doctrine_Collection $coll)
......@@ -75,33 +85,6 @@ class Doctrine_Hydrator_RecordDriver
$this->_collections[] = $coll;
}
/**
* isIdentifiable
* returns whether or not a given data row is identifiable (it contains
* all primary key fields specified in the second argument)
*
* @param array $row
* @param Doctrine_Table $table
* @return boolean
*/
/*public function isIdentifiable(array $row, Doctrine_Table $table)
{
$primaryKeys = $table->getIdentifierColumnNames();
if (is_array($primaryKeys)) {
foreach ($primaryKeys as $id) {
if ( ! isset($row[$id])) {
return false;
}
}
} else {
if ( ! isset($row[$primaryKeys])) {
return false;
}
}
return true;
}*/
public function getNullPointer()
{
return $this->_nullObject;
......@@ -127,6 +110,7 @@ class Doctrine_Hydrator_RecordDriver
}
$this->_collections = array();
$this->_mappers = array();
$this->_initializedRelations = array();
}
/**
......
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
/**
* The hydrator has the tedious task to construct object or array graphs out of
* a database result set.
*
* @package Doctrine
* @subpackage Hydrator
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 3192 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_HydratorNew extends Doctrine_Hydrator_Abstract
{
/**
* hydrateResultSet
* parses the data returned by statement object
*
* This is method defines the core of Doctrine's object population algorithm.
*
* The key idea is the loop over the rowset only once doing all the needed operations
* within this massive loop.
*
* @todo: Detailed documentation. Refactor (too long & nesting level).
*
* @param mixed $stmt
* @param array $tableAliases Array that maps table aliases (SQL alias => DQL alias)
* @param array $aliasMap Array that maps DQL aliases to their components
* (DQL alias => array(
* 'table' => Table object,
* 'parent' => Parent DQL alias (if any),
* 'relation' => Relation object (if any),
* 'map' => Custom index to use as the key in the result (if any),
* 'agg' => List of aggregate value names (sql alias => dql alias)
* )
* )
* @return mixed The created object/array graph.
*/
public function hydrateResultSet($stmt, $tableAliases, $hydrationMode = null)
{
if ($hydrationMode === null) {
$hydrationMode = $this->_hydrationMode;
}
if ($hydrationMode == Doctrine::HYDRATE_NONE) {
return $stmt->fetchAll(PDO::FETCH_NUM);
}
$this->_tableAliases = $tableAliases;
if ($hydrationMode == Doctrine::HYDRATE_ARRAY) {
$driver = new Doctrine_Hydrator_ArrayDriver();
} else {
$driver = new Doctrine_Hydrator_RecordDriver();
}
$event = new Doctrine_Event(null, Doctrine_Event::HYDRATE, null);
//$s = microtime(true);
// Used variables during hydration
reset($this->_queryComponents);
$rootAlias = key($this->_queryComponents);
$rootComponentName = $this->_queryComponents[$rootAlias]['table']->getClassName();
// if only one class is involved we can make our lives easier
$isSimpleQuery = count($this->_queryComponents) <= 1;
// Holds hydration listeners that get called during hydration
$listeners = array();
// Lookup map to quickly discover/lookup existing records in the result
// It's the identifier "memory"
$identifierMap = array();
// Holds for each class a pointer to the last previously seen element in the result set
$resultPointers = array();
// holds the values of the identifier/primary key fields of components,
// separated by a pipe '|' and grouped by component alias (r, u, i, ... whatever)
// the $idTemplate is a prepared template. $id is set to a fresh template when
// starting to process a row.
$id = array();
$idTemplate = array();
// Holds the resulting hydrated data structure
if ($this->_isResultMixed) {
$result = array();
} else {
$result = $driver->getElementCollection($rootComponentName);
}
if ($stmt === false || $stmt === 0) {
return $result;
}
// Initialize
foreach ($this->_queryComponents as $dqlAlias => $component) {
// disable lazy-loading of related elements during hydration
$component['table']->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, false);
$componentName = $component['table']->getClassName();
$listeners[$componentName] = $component['table']->getRecordListener();
$identifierMap[$dqlAlias] = array();
$resultPointers[$dqlAlias] = array();
$idTemplate[$dqlAlias] = '';
}
// Process result set
$cache = array();
while ($data = $stmt->fetch(Doctrine::FETCH_ASSOC)) {
$id = $idTemplate; // initialize the id-memory
$nonemptyComponents = array();
$rowData = $this->_gatherRowData($data, $cache, $id, $nonemptyComponents);
//
// hydrate the data of the root entity from the current row
//
$class = $this->_queryComponents[$rootAlias]['table'];
$componentName = $class->getComponentName();
// just event stuff
$event->set('data', $rowData[$rootAlias]);
$listeners[$componentName]->preHydrate($event);
//--
// Check for an existing element
$index = false;
if ($isSimpleQuery || ! isset($identifierMap[$rootAlias][$id[$rootAlias]])) {
$element = $driver->getElement($rowData[$rootAlias], $componentName);
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
// do we need to index by a custom field?
if ($field = $this->_getCustomIndexField($rootAlias)) {
if (isset($result[$field])) {
throw new Doctrine_Hydrator_Exception("Couldn't hydrate. Found non-unique key mapping.");
} else if ( ! isset($element[$field])) {
throw new Doctrine_Hydrator_Exception("Couldn't hydrate. Found a non-existent key.");
}
if ($this->_isResultMixed) {
$result[] = array($element[$field] => $element);
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_isResultMixed) {
$result[] = array($element);
} else {
$result[] = $element;
}
}
$identifierMap[$rootAlias][$id[$rootAlias]] = $driver->getLastKey($result);
} else {
$index = $identifierMap[$rootAlias][$id[$rootAlias]];
}
$this->_setLastElement($resultPointers, $result, $index, $rootAlias, false);
unset($rowData[$rootAlias]);
// end hydrate data of the root component for the current row
// Check for scalar values
if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars'];
unset($rowData['scalars']);
}
// $prev[$rootAlias] now points to the last element in $result.
// now hydrate the rest of the data found in the current row, that belongs to other
// (related) components.
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$map = $this->_queryComponents[$dqlAlias];
$componentName = $map['table']->getComponentName();
// just event stuff
$event->set('data', $data);
$listeners[$componentName]->preHydrate($event);
//--
$parent = $map['parent'];
$relation = $map['relation'];
$relationAlias = $relation->getAlias();
$path = $parent . '.' . $dqlAlias;
$key = key(reset($resultPointers));
if ($this->_isResultMixed && $parent == $rootAlias && isset($resultPointers[$parent][$key])) {
$baseElement =& $resultPointers[$parent][$key];
} else if (isset($resultPointers[$parent])) {
$baseElement =& $resultPointers[$parent];
} else {
continue;
}
// check the type of the relation (many or single-valued)
if ( ! $relation->isOneToOne()) {
// x-many relation
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
$driver->initRelated($baseElement, $relationAlias);
if ( ! isset($identifierMap[$path][$id[$parent]][$id[$dqlAlias]])) {
$element = $driver->getElement($data, $componentName);
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
if ($field = $this->_getCustomIndexField($dqlAlias)) {
// TODO: we should check this earlier. Fields used in INDEXBY
// must be unique. Then this can be removed here.
if (isset($baseElement[$relationAlias][$field])) {
throw Doctrine_Hydrator_Exception::nonUniqueKeyMapping();
} else if ( ! isset($element[$field])) {
throw Doctrine_Hydrator_Exception::nonExistantFieldUsedAsIndex($field);
}
$baseElement[$relationAlias][$element[$field]] = $element;
} else {
$baseElement[$relationAlias][] = $element;
}
$identifierMap[$path][$id[$parent]][$id[$dqlAlias]] = $driver->getLastKey($baseElement[$relationAlias]);
} else {
$index = $identifierMap[$path][$id[$parent]][$id[$dqlAlias]];
}
}
} else {
// x-1 relation
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias])) {
$baseElement[$relationAlias] = $driver->getNullPointer();
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = $driver->getElement($data, $componentName);
}
}
$coll =& $baseElement[$relationAlias];
$this->_setLastElement($resultPointers, $coll, $index, $dqlAlias, $oneToOne);
}
// append scalar values
if (isset($scalars)) {
$rowNumber = count($result) - 1;
foreach ($scalars as $name => $value) {
$result[$rowNumber][$name] = $value;
}
}
}
$stmt->closeCursor();
$driver->flush();
// re-enable lazy loading
foreach ($this->_queryComponents as $dqlAlias => $data) {
$data['table']->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, true);
}
//$e = microtime(true);
//echo 'Hydration took: ' . ($e - $s) . ' for '.count($result).' records<br />';
return $result;
}
/**
* _setLastElement
*
* sets the last element of given data array / collection
* as previous element
*
* @param array $prev The array that contains the pointers to the latest element of each class.
* @param array|Collection The object collection.
* @param boolean|integer $index Index of the element in the collection.
* @param string $dqlAlias
* @param boolean $oneToOne Whether it is a single-valued association or not.
* @return void
* @todo Detailed documentation
*/
protected function _setLastElement(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne)
{
if ($coll === $this->_nullObject) {
return false;
}
if ($index !== false) {
// Link element at $index to previous element for the component
// identified by the DQL alias $alias
$resultPointers[$dqlAlias] =& $coll[$index];
return;
}
if (is_array($coll) && $coll) {
if ($oneToOne) {
$resultPointers[$dqlAlias] =& $coll;
} else {
end($coll);
$resultPointers[$dqlAlias] =& $coll[key($coll)];
}
} else if ($coll instanceof Doctrine_Record) {
$resultPointers[$dqlAlias] = $coll;
} else if (count($coll) > 0) {
$resultPointers[$dqlAlias] = $coll->getLast();
} else if (isset($resultPointers[$dqlAlias])) {
unset($resultPointers[$dqlAlias]);
}
}
/**
* Puts the fields of a data row into a new array, grouped by the component
* they belong to. The column names in the result set are mapped to their
* field names during this procedure.
*
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component (alias).
*/
protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents)
{
$rowData = array();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
// cache general information like the column name <-> field name mapping
$e = explode('__', $key);
$columnName = strtolower(array_pop($e));
$cache[$key]['dqlAlias'] = $this->_tableAliases[strtolower(implode('__', $e))];
$mapper = $this->_queryComponents[$cache[$key]['dqlAlias']]['mapper'];
$classMetadata = $mapper->getClassMetadata();
// check whether it's an aggregate value or a regular field
if (isset($this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$columnName])) {
$fieldName = $this->_queryComponents[$cache[$key]['dqlAlias']]['agg'][$columnName];
$cache[$key]['isScalar'] = true;
} else {
$fieldName = $mapper->getFieldName($columnName);
$cache[$key]['isScalar'] = false;
}
$cache[$key]['fieldName'] = $fieldName;
// cache identifier information
if ($classMetadata->isIdentifier($fieldName)) {
$cache[$key]['isIdentifier'] = true;
} else {
$cache[$key]['isIdentifier'] = false;
}
// cache type information
$type = $classMetadata->getTypeOfColumn($columnName);
if ($type == 'integer' || $type == 'string') {
$cache[$key]['isSimpleType'] = true;
} else {
$cache[$key]['type'] = $type;
$cache[$key]['isSimpleType'] = false;
}
}
$mapper = $this->_queryComponents[$cache[$key]['dqlAlias']]['mapper'];
$dqlAlias = $cache[$key]['dqlAlias'];
$fieldName = $cache[$key]['fieldName'];
if ($cache[$key]['isScalar']) {
$rowData['scalars'][$fieldName] = $value;
continue;
}
if ($cache[$key]['isIdentifier']) {
$id[$dqlAlias] .= '|' . $value;
}
if ($cache[$key]['isSimpleType']) {
$rowData[$dqlAlias][$fieldName] = $value;
} else {
$rowData[$dqlAlias][$fieldName] = $mapper->prepareValue(
$fieldName, $value, $cache[$key]['type']);
}
if ( ! isset($nonemptyComponents[$dqlAlias]) && $value !== null) {
$nonemptyComponents[$dqlAlias] = true;
}
}
return $rowData;
}
/**
* Gets the custom field used for indexing for the specified component alias.
*
* @return string The field name of the field used for indexing or NULL
* if the component does not use any custom field indices.
*/
protected function _getCustomIndexField($alias)
{
return isset($this->_queryComponents[$alias]['map']) ? $this->_queryComponents[$alias]['map'] : null;
}
private $_isResultMixed = false;
public function setResultMixed($bool)
{
$this->_isResultMixed = $bool;
}
}
......@@ -90,23 +90,6 @@ class Doctrine_Mapper
}
}
/**
* createQuery
* creates a new Doctrine_Query object and adds the component name
* of this table as the query 'from' part
*
* @param string Optional alias name for component aliasing.
*
* @return Doctrine_Query
*/
public function createQuery($alias = '')
{
if ( ! empty($alias)) {
$alias = ' ' . trim($alias);
}
return Doctrine_Query::create($this->_conn)->from($this->getComponentName() . $alias);
}
/**
* sets the connection for this class
*
......@@ -139,7 +122,7 @@ class Doctrine_Mapper
*/
public function create(array $array = array())
{
$record = new $this->_domainClassName($this, true);
$record = new $this->_domainClassName();
$record->fromArray($array);
return $record;
......@@ -178,79 +161,6 @@ class Doctrine_Mapper
return $this->_conn->unitOfWork->detach($entity);
}
/**
* Finds an entity by its primary key.
*
* @param $id database row id
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return mixed Array or Doctrine_Record or false if no result
* @todo Remove. Move to EntityRepository.
*/
public function find($id, $hydrationMode = null)
{
if (is_null($id)) {
return false;
}
$id = is_array($id) ? array_values($id) : array($id);
return $this->createQuery()
->where(implode(' = ? AND ', (array) $this->_classMetadata->getIdentifier()) . ' = ?')
->fetchOne($id, $hydrationMode);
}
/**
* Finds all entities of the mapper's class.
* Use with care.
*
* @param int $hydrationMode Doctrine::HYDRATE_ARRAY or Doctrine::HYDRATE_RECORD
* @return Doctrine_Collection
* @todo Remove. Move to EntityRepository.
*/
public function findAll($hydrationMode = null)
{
return $this->createQuery()->execute(array(), $hydrationMode);
}
/**
* findBySql
* finds records with given SQL where clause
* returns a collection of records
*
* @param string $dql DQL after WHERE clause
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @return Doctrine_Collection
*
* @todo This actually takes DQL, not SQL, but it requires column names
* instead of field names. This should be fixed to use raw SQL instead.
* @todo Remove. Move to EntityRepository.
*/
public function findBySql($dql, array $params = array(), $hydrationMode = null)
{
return $this->createQuery()->where($dql)->execute($params, $hydrationMode);
}
/**
* findByDql
* finds records with given DQL where clause
* returns a collection of records
*
* @param string $dql DQL after WHERE clause
* @param array $params query parameters
* @param int $hydrationMode Doctrine::FETCH_ARRAY or Doctrine::FETCH_RECORD
* @return Doctrine_Collection
* @todo Remove. Move to EntityRepository.
*/
public function findByDql($dql, array $params = array(), $hydrationMode = null)
{
$query = new Doctrine_Query($this->_conn);
$component = $this->getComponentName();
$dql = 'FROM ' . $component . ' WHERE ' . $dql;
return $query->query($dql, $params, $hydrationMode);
}
/**
* Executes a named query.
*
......@@ -349,9 +259,7 @@ class Doctrine_Mapper
}
if ($found) {
$record = new $this->_domainClassName($this, true, $data);
$data = array();
return $record;
return new $this->_domainClassName(true, $data);
}
$idHash = $this->_conn->unitOfWork->getIdentifierHash($id);
......@@ -360,12 +268,12 @@ class Doctrine_Mapper
$this->_classMetadata->getRootClassName())) {
$record->hydrate($data);
} else {
$record = new $this->_domainClassName($this, false, $data);
$record = new $this->_domainClassName(false, $data);
$this->_conn->unitOfWork->registerIdentity($record);
}
$data = array();
} else {
$record = new $this->_domainClassName($this, true, $data);
$record = new $this->_domainClassName(true, $data);
}
return $record;
......@@ -545,83 +453,6 @@ class Doctrine_Mapper
return $this->_domainClassName;
}
/**
* findBy
*
* @param string $column
* @param string $value
* @param string $hydrationMode
* @return void
* @todo Remove. Move to EntityRepository.
*/
protected function findBy($fieldName, $value, $hydrationMode = null)
{
return $this->createQuery()->where($fieldName . ' = ?')->execute(array($value), $hydrationMode);
}
/**
* findOneBy
*
* @param string $column
* @param string $value
* @param string $hydrationMode
* @return void
* @todo Remove. Move to EntityRepository.
*/
protected function findOneBy($fieldName, $value, $hydrationMode = null)
{
$results = $this->createQuery()->where($fieldName . ' = ?')->limit(1)->execute(
array($value), $hydrationMode);
return $hydrationMode === Doctrine::HYDRATE_ARRAY ? array_shift($results) : $results->getFirst();
}
/**
* __call
*
* Adds support for magic finders.
* findByColumnName, findByRelationAlias
* findById, findByContactId, etc.
*
* @return void
* @throws Doctrine_Mapper_Exception If the method called is an invalid find* method
* or no find* method at all and therefore an invalid
* method call.
* @todo Remove. Move to EntityRepository.
*/
public function __call($method, $arguments)
{
if (substr($method, 0, 6) == 'findBy') {
$by = substr($method, 6, strlen($method));
$method = 'findBy';
} else if (substr($method, 0, 9) == 'findOneBy') {
$by = substr($method, 9, strlen($method));
$method = 'findOneBy';
} else {
throw new Doctrine_Mapper_Exception("Undefined method '$method'.");
}
if (isset($by)) {
if ( ! isset($arguments[0])) {
throw new Doctrine_Mapper_Exception('You must specify the value to findBy.');
}
$fieldName = Doctrine::tableize($by);
$hydrationMode = isset($arguments[1]) ? $arguments[1]:null;
if ($this->_classMetadata->hasField($fieldName)) {
return $this->$method($fieldName, $arguments[0], $hydrationMode);
} else if ($this->_classMetadata->hasRelation($by)) {
$relation = $this->_classMetadata->getRelation($by);
if ($relation['type'] === Doctrine_Relation::MANY) {
throw new Doctrine_Mapper_Exception('Cannot findBy many relationship.');
}
return $this->$method($relation['local'], $arguments[0], $hydrationMode);
} else {
throw new Doctrine_Mapper_Exception('Cannot find by: ' . $by . '. Invalid field or relationship alias.');
}
}
}
/**
* Saves an entity and all it's related entities.
*
......@@ -795,7 +626,12 @@ class Doctrine_Mapper
$query = 'DELETE FROM ' . $assocTable->getTableName()
. ' WHERE ' . $rel->getForeign() . ' = ?'
. ' AND ' . $rel->getLocal() . ' = ?';
$this->_conn->execute($query, array($r->getIncremented(), $record->getIncremented()));
// FIXME: composite key support
$ids1 = $r->identifier();
$id1 = count($ids1) > 0 ? array_pop($ids1) : null;
$ids2 = $record->identifier();
$id2 = count($ids2) > 0 ? array_pop($ids2) : null;
$this->_conn->execute($query, array($id1, $id2));
}
$assocMapper = $this->_conn->getMapper($assocTable->getComponentName());
......@@ -804,7 +640,6 @@ class Doctrine_Mapper
$assocRecord->set($assocTable->getFieldName($rel->getForeign()), $r);
$assocRecord->set($assocTable->getFieldName($rel->getLocal()), $record);
$assocMapper->save($assocRecord);
//$this->saveSingleRecord($assocRecord);
}
}
}
......@@ -890,19 +725,6 @@ class Doctrine_Mapper
return true;
}
public function hasAttribute($key)
{
switch ($key) {
case Doctrine::ATTR_LOAD_REFERENCES:
case Doctrine::ATTR_QUERY_LIMIT:
case Doctrine::ATTR_COLL_KEY:
case Doctrine::ATTR_VALIDATE:
return true;
default:
return false;
}
}
public function executeQuery(Doctrine_Query $query)
{
......
......@@ -111,7 +111,8 @@ class Doctrine_Mapper_JoinedStrategy extends Doctrine_Mapper_Strategy
if ( ! $value->exists()) {
$value->save();
}
$record->set($field, $value->getIncremented());
$idValues = $value->identifier();
$record->set($field, $idValues[0]);
}
}
......
......@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Query_Abstract');
/**
* Doctrine_Query
* A Doctrine_Query object represents a DQL query. It is used to query databases for
......
......@@ -118,12 +118,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
protected $_class;
/**
*
* @var Doctrine_Mapper
*/
protected $_mapper;
/**
*
*/
......@@ -187,6 +181,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
*/
protected $_references = array();
/**
* The EntityManager that is responsible for the persistence of the entity.
*
* @var Doctrine_EntityManager
*/
protected $_em;
/**
* The object identifier of the object. Each object has a unique identifier during runtime.
*
......@@ -206,23 +207,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* open connections
* @throws Doctrine_Record_Exception if the cleanData operation fails somehow
*/
public function __construct($mapper = null, $isNewEntry = false, array $data = array())
public function __construct($isNewEntry = true, array $data = array())
{
if (isset($mapper) && $mapper instanceof Doctrine_Mapper) {
$class = get_class($this);
$this->_mapper = $mapper;
$this->_class = $this->_mapper->getClassMetadata();
$exists = ! $isNewEntry;
} else {
$this->_mapper = Doctrine_Manager::getInstance()->getMapper(get_class($this));
$this->_class = $this->_mapper->getClassMetadata();
$exists = false;
}
$this->_entityName = $this->_mapper->getMappedClassName();
$this->_oid = self::$_index;
$this->_entityName = get_class($this);
$this->_em = Doctrine_Manager::getInstance()->getCurrentConnection();
$this->_class = $this->_em->getClassMetadata($this->_entityName);
self::$_index++;
$this->_oid = self::$_index++;
// get the data array
$this->_data = $data;
......@@ -232,9 +223,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->_values = $this->cleanData($this->_data);
$this->_extractIdentifier($exists);
$this->_extractIdentifier( ! $isNewEntry);
if ( ! $exists) {
if ($isNewEntry) {
if ($count > count($this->_values)) {
$this->_state = Doctrine_Record::STATE_TDIRTY;
} else {
......@@ -252,7 +243,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
self::$_useAutoAccessorOverride = false; // @todo read from attribute the first time
$this->_mapper->manage($this);
$this->_em->manage($this);
$this->construct();
}
......@@ -510,13 +501,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$tmp = $data;
$data = array();
$fieldNames = $this->_mapper->getFieldNames();
$fieldNames = $this->_em->getMapper($this->_entityName)->getFieldNames();
foreach ($fieldNames as $fieldName) {
if (isset($tmp[$fieldName])) {
$data[$fieldName] = $tmp[$fieldName];
} else if (array_key_exists($fieldName, $tmp)) {
$data[$fieldName] = Doctrine_Null::$INSTANCE;
} else if (!isset($this->_data[$fieldName])) {
} else if ( ! isset($this->_data[$fieldName])) {
$data[$fieldName] = Doctrine_Null::$INSTANCE;
}
unset($tmp[$fieldName]);
......@@ -554,7 +545,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
case Doctrine::IDENTIFIER_AUTOINC:
case Doctrine::IDENTIFIER_SEQUENCE:
case Doctrine::IDENTIFIER_NATURAL:
$name = (array)$this->_class->getIdentifier();
$name = $this->_class->getIdentifier();
$name = $name[0];
if ($exists) {
if (isset($this->_data[$name]) && $this->_data[$name] !== Doctrine_Null::$INSTANCE) {
......@@ -563,7 +554,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
break;
case Doctrine::IDENTIFIER_COMPOSITE:
$names = (array)$this->_class->getIdentifier();
$names = $this->_class->getIdentifier();
foreach ($names as $name) {
if ($this->_data[$name] === Doctrine_Null::$INSTANCE) {
......@@ -576,6 +567,14 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
}
/**
* INTERNAL:
*/
final public function setIdentifier(array $identifier)
{
$this->_id = $identifier;
}
/**
* Serializes the entity.
* This method is automatically called when the entity is serialized.
......@@ -596,6 +595,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
unset($vars['_errorStack']);
unset($vars['_filter']);
unset($vars['_node']);
unset($vars['_em']);
//$name = (array)$this->_table->getIdentifier();
$this->_data = array_merge($this->_data, $this->_id);
......@@ -648,7 +648,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->_oid = self::$_index;
self::$_index++;
$this->_mapper = $connection->getMapper(get_class($this));
$this->_em = $connection;
$array = unserialize($serialized);
......@@ -656,7 +656,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->$k = $v;
}
$this->_class = $this->_mapper->getTable();
$this->_entityName = get_class($this);
$this->_class = $this->_em->getClassMetadata($this->_entityName);
foreach ($this->_data as $k => $v) {
switch ($this->_class->getTypeOf($k)) {
......@@ -674,7 +675,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
}
$this->_mapper->manage($this);
$this->_em->manage($this);
$this->cleanData($this->_data);
$this->_extractIdentifier($this->exists());
......@@ -749,7 +750,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$id = array_values($id);
if ($deep) {
$query = $this->_mapper->createQuery();
$query = $this->_class->getConnection()->createQuery()->from($this->_entityName);
foreach (array_keys($this->_references) as $name) {
$query->leftJoin(get_class($this) . '.' . $name);
}
......@@ -758,7 +759,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$record = $query->fetchOne($id);
} else {
// Use FETCH_ARRAY to avoid clearing object relations
$record = $this->_mapper->find($id, Doctrine::HYDRATE_ARRAY);
$record = $this->getRepository()->find($this->identifier(), Doctrine::HYDRATE_ARRAY);
if ($record) {
$this->hydrate($record);
}
......@@ -929,8 +930,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
}
return $this->_references[$fieldName];
} catch (Doctrine_Relation_Exception $e) {
echo $e->getTraceAsString();
echo "<br/><br/>";
//echo $e->getTraceAsString();
//echo "<br/><br/>";
foreach ($this->_class->getFilters() as $filter) {
if (($value = $filter->filterGet($this, $fieldName, $value)) !== null) {
return $value;
......@@ -979,7 +980,9 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
if (isset($this->_data[$fieldName])) {
if ($value instanceof Doctrine_Record) {
$type = $this->_class->getTypeOf($fieldName);
$id = $value->getIncremented();
// FIXME: composite key support
$ids = $value->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
if ($id !== null && $type !== 'object') {
$value = $id;
}
......@@ -998,6 +1001,13 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->_data[$fieldName] = $value;
$this->_modified[] = $fieldName;
/* We can't do this currently because there are tests that change
* the primary key of already persisted entities (ugh). */
if ($this->isTransient() && $this->_class->isIdentifier($fieldName)) {
$this->_id[$fieldName] = $value;
}
switch ($this->_state) {
case Doctrine_Record::STATE_CLEAN:
$this->_state = Doctrine_Record::STATE_DIRTY;
......@@ -1011,8 +1021,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
try {
$this->_coreSetRelated($fieldName, $value);
} catch (Doctrine_Relation_Exception $e) {
echo $e->getTraceAsString();
echo "<br/><br/>";
//echo $e->getTraceAsString();
//echo "<br/><br/>";
foreach ($this->_class->getFilters() as $filter) {
if (($value = $filter->filterSet($this, $fieldName, $value)) !== null) {
return $value;
......@@ -1131,7 +1141,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
public function save(Doctrine_Connection $conn = null)
{
// TODO: Forward to EntityManager. There: registerNew() OR registerDirty() on UnitOfWork.
$this->_mapper->save($this, $conn);
$this->_em->save($this, $conn);
}
/**
......@@ -1175,7 +1185,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
public function replace(Doctrine_Connection $conn = null)
{
if ($conn === null) {
$conn = $this->_mapper->getConnection();
$conn = $this->_em;
}
return $conn->replace($this->_class, $this->getPrepared(), $this->_id);
......@@ -1249,7 +1259,10 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
break;
default:
if ($this->_data[$field] instanceof Doctrine_Record) {
$this->_data[$field] = $this->_data[$field]->getIncremented();
// FIXME: composite key support
$ids = $this->_data[$field]->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
$this->_data[$field] = $id;
}
/** TODO:
if ($this->_data[$v] === null) {
......@@ -1313,8 +1326,12 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
if ($this->_class->getIdentifierType() == Doctrine::IDENTIFIER_AUTOINC) {
$idFieldNames = (array)$this->_class->getIdentifier();
$id = $idFieldNames[0];
$a[$id] = $this->getIncremented();
$idFieldName = $idFieldNames[0];
$ids = $this->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
$a[$idFieldName] = $id;
}
if ($deep) {
......@@ -1460,17 +1477,41 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
* Checks whether the entity already has a persistent state.
*
* @return boolean TRUE if the object is new, FALSE otherwise.
* @deprecated Use isTransient()
*/
public function isNew()
{
return $this->_state == self::STATE_TCLEAN || $this->_state == self::STATE_TDIRTY;
}
/**
* Checks whether the entity already has a persistent state.
*
* @return boolean TRUE if the object is new, FALSE otherwise.
*/
public function isTransient()
{
return $this->_state == self::STATE_TCLEAN || $this->_state == self::STATE_TDIRTY;
}
/**
* Checks whether the entity has been modified since it was last synchronized
* with the database.
*
* @return boolean TRUE if the object has been modified, FALSE otherwise.
*/
public function isDirty()
{
return ($this->_state === Doctrine_Record::STATE_DIRTY ||
$this->_state === Doctrine_Record::STATE_TDIRTY);
}
/**
* Checks whether the entity has been modified since it was last synchronized
* with the database.
*
* @return boolean TRUE if the object has been modified, FALSE otherwise.
* @deprecated Use isDirty()
*/
public function isModified()
{
......@@ -1496,6 +1537,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
/**
* getIterator
* @return Doctrine_Record_Iterator a Doctrine_Record_Iterator that iterates through the data
* @todo Really needed/useful?
*/
public function getIterator()
{
......@@ -1513,7 +1555,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
public function delete(Doctrine_Connection $conn = null)
{
// TODO: Forward to EntityManager. There: registerRemoved() on UnitOfWork
return $this->_mapper->delete($this, $conn);
return $this->_em->remove($this, $conn);
}
/**
......@@ -1532,7 +1574,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
unset($data[$id]);
}
$ret = $this->_mapper->create($data);
$ret = $this->_em->createEntity($this->_entityName, $data);
$modified = array();
foreach ($data as $key => $val) {
......@@ -1581,7 +1623,7 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
$this->_data[$fieldName] = $value;
}
} else {
$idFieldNames = (array)$this->_class->getIdentifier();
$idFieldNames = $this->_class->getIdentifier();
$name = $idFieldNames[0];
$this->_id[$name] = $id;
$this->_data[$name] = $id;
......@@ -1601,23 +1643,6 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
return $this->_id;
}
/**
* returns the value of autoincremented primary key of this object (if any)
*
* @return integer
* @todo Better name? Not sure this is the right place here.
* @todo Plays against full composite key support..
*/
final public function getIncremented()
{
$id = current($this->_id);
if ($id === false) {
return null;
}
return $id;
}
/**
* hasRefence
* @param string $name
......@@ -1965,14 +1990,14 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
return $this->_class;
}
/**
* Returns the mapper of the entity.
*
* @return Doctrine_Mapper
*/
public function getMapper()
public function getEntityManager()
{
return $this->_em;
}
public function getRepository()
{
return $this->_mapper;
return $this->_class->getConnection()->getRepository($this->_entityName);
}
/**
......@@ -2002,8 +2027,8 @@ abstract class Doctrine_Record extends Doctrine_Access implements Countable, Ite
public function free($deep = false)
{
if ($this->_state != self::STATE_LOCKED) {
$this->_mapper->detach($this);
$this->_mapper->removeRecord($this);
$this->_em->detach($this);
$this->_em->removeRecord($this);
$this->_data = array();
$this->_id = array();
......
......@@ -94,17 +94,14 @@ class Doctrine_Relation_Association extends Doctrine_Relation
*/
public function fetchRelatedFor(Doctrine_Record $record)
{
$id = $record->getIncremented();
//var_dump($id);
//echo "<br /><br />";
// FIXME: composite key support
$ids = $record->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
if (empty($id) || ! $this->_foreignMapper->getClassMetadata()->getAttribute(Doctrine::ATTR_LOAD_REFERENCES)) {
//echo "here" . $this->_foreignMapper->getAttribute(Doctrine::ATTR_LOAD_REFERENCES);
$coll = new Doctrine_Collection($this->getForeignComponentName());
} else {
$query = Doctrine_Query::create()->parseQuery($this->getRelationDql(1));
//echo $query->getDql() . "<br />";
//echo $query->getSql() . "<br />";
//echo "<br /><br />";
$coll = Doctrine_Query::create()->query($this->getRelationDql(1), array($id));
}
$coll->setReference($record, $this);
......
......@@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Relation_Association');
/**
* Doctrine_Relation_Association_Self
*
......@@ -76,7 +76,9 @@ class Doctrine_Relation_Association_Self extends Doctrine_Relation_Association
public function fetchRelatedFor(Doctrine_Record $record)
{
$id = $record->getIncremented();
// FIXME: composite key support
$ids = $record->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
$q = new Doctrine_RawSql();
......
......@@ -74,35 +74,11 @@ class Doctrine_Relation_Nest extends Doctrine_Relation_Association
return $dql;
}
/**
public function fetchRelatedFor(Doctrine_Record $record)
{
$id = $record->getIncremented();
if (empty($id) || ! $this->definition['table']->getAttribute(Doctrine::ATTR_LOAD_REFERENCES)) {
return new Doctrine_Collection($this->getTable());
} else {
$q = new Doctrine_Query();
$c = $this->getTable()->getComponentName();
$a = substr($c, 0, 1);
$c2 = $this->getAssociationTable()->getComponentName();
$a2 = substr($c2, 0, 1);
$q->from($c)
->innerJoin($c . '.' . $c2)
$sub = 'SELECT ' . $this->getForeign()
. ' FROM ' . $c2
. ' WHERE ' . $this->getLocal()
. ' = ?';
}
}
*/
public function fetchRelatedFor(Doctrine_Record $record)
{
$id = $record->getIncremented();
// FIXME: composite key support
$ids = $record->identifier();
$id = count($ids) > 0 ? array_pop($ids) : null;
if (empty($id) || ! $this->_foreignMapper->getClassMetadata()->getAttribute(Doctrine::ATTR_LOAD_REFERENCES)) {
......
......@@ -147,12 +147,6 @@ class Doctrine_Relation_Parser
$this->getRelations();
return $this->getRelation($alias, false);
} else {
/*try {
throw new Exception();
} catch (Exception $e) {
//echo "" . "<br />";
///echo $e->getTraceAsString() . "<br /><br /><br />";
}*/
throw new Doctrine_Relation_Exception("Unknown relation '$alias'.");
}
}
......
......@@ -84,7 +84,8 @@ class Doctrine_Validator
if ($value === Doctrine_Null::$INSTANCE) {
$value = null;
} else if ($value instanceof Doctrine_Record) {
$value = $value->getIncremented();
$ids = $value->identifier();
$value = count($ids) > 0 ? array_pop($ids) : null;
}
$dataType = $classMetadata->getTypeOf($fieldName);
......
......@@ -9,11 +9,22 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase
parent::setUp();
}
/** The data of the hydration mode dataProvider */
protected static $hydrationModeProviderData = array(
array('hydrationMode' => Doctrine::HYDRATE_RECORD),
array('hydrationMode' => Doctrine::HYDRATE_ARRAY)
);
/** Getter for the hydration mode dataProvider */
public static function hydrationModeProvider()
{
return self::$hydrationModeProviderData;
}
/**
* Fakes the DQL query: select u.id, u.name from CmsUser u
* Select u.id, u.name from CmsUser u
*
*/
public function testBasic()
public function testBasicHydration()
{
// Faked query components
$queryComponents = array(
......@@ -72,4 +83,285 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase
$this->assertEquals('jwage', $objectResult[1]->name);
}
/**
* select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u
* join u.phonenumbers p
* =
* select u.id, u.status, p.phonenumber, upper(u.name) as u__0 from USERS u
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id
*
* @dataProvider hydrationModeProvider
*/
public function testNewHydrationMixedQueryFetchJoin($hydrationMode)
{
// Faked query components
$queryComponents = array(
'u' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsUser'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsUser'),
'parent' => null,
'relation' => null,
'map' => null,
'agg' => array('0' => 'nameUpper')
),
'p' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsPhonenumber'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsPhonenumber'),
'parent' => 'u',
'relation' => $this->sharedFixture['connection']->getClassMetadata('CmsUser')->getRelation('phonenumbers'),
'map' => null
)
);
// Faked table alias map
$tableAliasMap = array(
'u' => 'u',
'p' => 'p'
);
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__0' => 'ROMANB',
'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__0' => 'ROMANB',
'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__0' => 'JWAGE',
'p__phonenumber' => '91'
)
);
$stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_HydratorNew();
$hydrator->setQueryComponents($queryComponents);
$hydrator->setResultMixed(true);
$result = $hydrator->hydrateResultSet($stmt, $tableAliasMap, $hydrationMode);
//var_dump($result);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1]));
$this->assertEquals(3, count($result[0][0]));
// first user => 2 phonenumbers
$this->assertEquals(2, count($result[0][0]['phonenumbers']));
$this->assertEquals('ROMANB', $result[0]['nameUpper']);
// second user => 1 phonenumber
$this->assertEquals(1, count($result[1][0]['phonenumbers']));
$this->assertEquals('JWAGE', $result[1]['nameUpper']);
$this->assertEquals(42, $result[0][0]['phonenumbers'][0]['phonenumber']);
$this->assertEquals(43, $result[0][0]['phonenumbers'][1]['phonenumber']);
$this->assertEquals(91, $result[1][0]['phonenumbers'][0]['phonenumber']);
if ($hydrationMode == Doctrine::HYDRATE_RECORD) {
$this->assertTrue($result[0][0] instanceof Doctrine_Record);
$this->assertTrue($result[0][0]['phonenumbers'] instanceof Doctrine_Collection);
$this->assertTrue($result[0][0]['phonenumbers'][0] instanceof Doctrine_Record);
$this->assertTrue($result[0][0]['phonenumbers'][1] instanceof Doctrine_Record);
$this->assertTrue($result[1][0] instanceof Doctrine_Record);
$this->assertTrue($result[1][0]['phonenumbers'] instanceof Doctrine_Collection);
}
}
/**
* select u.id, u.status, count(p.phonenumber) numPhones from User u
* join u.phonenumbers p group by u.status, u.id
* =
* select u.id, u.status, count(p.phonenumber) as p__0 from USERS u
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id group by u.id, u.status
*
* @dataProvider hydrationModeProvider
*/
public function testNewHydrationBasicsMixedQueryNormalJoin($hydrationMode)
{
// Faked query components
$queryComponents = array(
'u' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsUser'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsUser'),
'parent' => null,
'relation' => null,
'map' => null
),
'p' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsPhonenumber'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsPhonenumber'),
'parent' => 'u',
'relation' => $this->sharedFixture['connection']->getClassMetadata('CmsUser')->getRelation('phonenumbers'),
'map' => null,
'agg' => array('0' => 'numPhones')
)
);
// Faked table alias map
$tableAliasMap = array(
'u' => 'u',
'p' => 'p'
);
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'p__0' => '2',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'p__0' => '1',
)
);
$stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_HydratorNew();
$hydrator->setQueryComponents($queryComponents);
$hydrator->setResultMixed(true);
$result = $hydrator->hydrateResultSet($stmt, $tableAliasMap, $hydrationMode);
//var_dump($result);
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1]));
// first user => 2 phonenumbers
$this->assertEquals(2, $result[0]['numPhones']);
// second user => 1 phonenumber
$this->assertEquals(1, $result[1]['numPhones']);
if ($hydrationMode == Doctrine::HYDRATE_RECORD) {
$this->assertTrue($result[0][0] instanceof Doctrine_Record);
$this->assertTrue($result[1][0] instanceof Doctrine_Record);
}
}
/**
* select u.id, u.status, upper(u.name) nameUpper from User u index by u.id
* join u.phonenumbers p indexby p.phonenumber
* =
* select u.id, u.status, upper(u.name) as p__0 from USERS u
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id
*
* @dataProvider hydrationModeProvider
*/
public function testNewHydrationMixedQueryFetchJoinCustomIndex($hydrationMode)
{
// Faked query components
$queryComponents = array(
'u' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsUser'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsUser'),
'parent' => null,
'relation' => null,
'agg' => array('0' => 'nameUpper'),
'map' => 'id'
),
'p' => array(
'table' => $this->sharedFixture['connection']->getClassMetadata('CmsPhonenumber'),
'mapper' => $this->sharedFixture['connection']->getMapper('CmsPhonenumber'),
'parent' => 'u',
'relation' => $this->sharedFixture['connection']->getClassMetadata('CmsUser')->getRelation('phonenumbers'),
'map' => 'phonenumber'
)
);
// Faked table alias map
$tableAliasMap = array(
'u' => 'u',
'p' => 'p'
);
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__0' => 'ROMANB',
'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__0' => 'ROMANB',
'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__0' => 'JWAGE',
'p__phonenumber' => '91'
)
);
$stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_HydratorNew();
$hydrator->setQueryComponents($queryComponents);
// give the hydrator an artificial hint
$hydrator->setResultMixed(true);
$result = $hydrator->hydrateResultSet($stmt, $tableAliasMap, $hydrationMode);
if ($hydrationMode == Doctrine::HYDRATE_ARRAY) {
//var_dump($result);
}
$this->assertEquals(2, count($result));
$this->assertTrue(is_array($result));
$this->assertTrue(is_array($result[0]));
$this->assertTrue(is_array($result[1]));
// first user => 2 phonenumbers. notice the custom indexing by user id
$this->assertEquals(2, count($result[0]['1']['phonenumbers']));
// second user => 1 phonenumber. notice the custom indexing by user id
$this->assertEquals(1, count($result[1]['2']['phonenumbers']));
// test the custom indexing of the phonenumbers
$this->assertTrue(isset($result[0]['1']['phonenumbers']['42']));
$this->assertTrue(isset($result[0]['1']['phonenumbers']['43']));
$this->assertTrue(isset($result[1]['2']['phonenumbers']['91']));
// test the scalar values
$this->assertEquals('ROMANB', $result[0]['nameUpper']);
$this->assertEquals('JWAGE', $result[1]['nameUpper']);
if ($hydrationMode == Doctrine::HYDRATE_RECORD) {
$this->assertTrue($result[0]['1'] instanceof Doctrine_Record);
$this->assertTrue($result[1]['2'] instanceof Doctrine_Record);
$this->assertTrue($result[0]['1']['phonenumbers'] instanceof Doctrine_Collection);
$this->assertEquals(2, count($result[0]['1']['phonenumbers']));
}
}
}
\ No newline at end of file
......@@ -18,6 +18,8 @@ class Orm_UnitOfWorkTestCase extends Doctrine_OrmTestCase
public function testRegisterNew()
{
$this->_user->username = 'romanb';
$this->_user->id = 1;
$this->_unitOfWork->registerNew($this->_user);
$this->assertFalse($this->_unitOfWork->contains($this->_user));
$this->assertTrue($this->_unitOfWork->isRegisteredNew($this->_user));
......@@ -35,7 +37,15 @@ class Orm_UnitOfWorkTestCase extends Doctrine_OrmTestCase
$this->assertTrue($this->_unitOfWork->isRegisteredDirty($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredNew($this->_user));
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
}
public function testRegisterRemovedOnTransientEntityIsIgnored()
{
$this->_user->username = 'romanb';
$this->_user->id = 1;
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
$this->_unitOfWork->registerRemoved($this->_user);
$this->assertFalse($this->_unitOfWork->isRegisteredRemoved($this->_user));
}
/*public function testSavedEntityHasIdentityAndIsManaged()
......
<?php
class CmsPhonenumber extends Doctrine_Record
{
public static function initMetadata($class)
{
$class->mapColumn('user_id', 'integer', 4);
$class->mapColumn('phonenumber', 'string', 50, array('primary' => true));
}
}
......@@ -6,5 +6,8 @@ class CmsUser extends Doctrine_Record
$class->mapColumn('id', 'integer', 4, array('primary' => true, 'autoincrement' => true));
$class->mapColumn('username', 'string', 255);
$class->mapColumn('name', 'string', 255);
$class->hasMany('CmsPhonenumber as phonenumbers', array(
'local' => 'id', 'foreign' => 'user_id'));
}
}
......@@ -77,7 +77,7 @@ class Doctrine_Access_TestCase extends Doctrine_UnitTestCase
$user->save();
$user = $this->connection->getMapper('User')->find($user->identifier());
$user = $this->connection->getRepository('User')->find($user->identifier());
$this->assertEqual($user->name, 'Jack');
$user['name'] = 'Jack';
......@@ -97,7 +97,7 @@ class Doctrine_Access_TestCase extends Doctrine_UnitTestCase
$user->save();
$user = $this->connection->getMapper('User')->find($user->identifier());
$user = $this->connection->getRepository('User')->find($user->identifier());
$this->assertEqual($user->name, 'Jack');
$user->name = 'Jack';
......@@ -115,7 +115,7 @@ class Doctrine_Access_TestCase extends Doctrine_UnitTestCase
$user->save();
$user = $this->connection->getMapper('User')->find($user->identifier());
$user = $this->connection->getRepository('User')->find($user->identifier());
$this->assertEqual($user->get('name'), 'Jack');
......
......@@ -168,7 +168,7 @@ class Doctrine_ClassTableInheritance_TestCase extends Doctrine_UnitTestCase
$profiler = new Doctrine_Connection_Profiler();
$this->conn->addListener($profiler);
$record = $this->conn->getMapper('CTITest')->find(1);
$record = $this->conn->getRepository('CTITest')->find(1);
$record->age = 11;
$record->name = 'Jack';
......@@ -193,7 +193,7 @@ class Doctrine_ClassTableInheritance_TestCase extends Doctrine_UnitTestCase
{
$this->conn->clear();
$record = $this->conn->getMapper('CTITest')->find(1);
$record = $this->conn->getRepository('CTITest')->find(1);
$this->assertEqual($record->id, 1);
$this->assertEqual($record->name, 'Jack');
......@@ -209,7 +209,7 @@ class Doctrine_ClassTableInheritance_TestCase extends Doctrine_UnitTestCase
$profiler = new Doctrine_Connection_Profiler();
$this->conn->addListener($profiler);
$record = $this->conn->getMapper('CTITest')->find(1);
$record = $this->conn->getRepository('CTITest')->find(1);
$record->delete();
......
......@@ -53,7 +53,7 @@ class Doctrine_CustomPrimaryKey_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($c->identifier(), array('uid' => 1));
$this->connection->clear();
$c = $this->connection->getMapper('CustomPK')->find(1);
$c = $this->connection->getRepository('CustomPK')->find(1);
$this->assertEqual($c->identifier(), array('uid' => 1));
}
......
......@@ -60,7 +60,7 @@ class Doctrine_DataType_Boolean_TestCase extends Doctrine_UnitTestCase {
$this->connection->clear();
$test = $test->getMapper()->find($test->id);
$test = $test->getRepository()->find($test->id);
$this->assertIdentical($test->is_working, true);
}
public function testNormalQuerying() {
......
......@@ -172,7 +172,7 @@ class Doctrine_DataType_Enum_TestCase extends Doctrine_UnitTestCase
public function testFailingRefresh()
{
$enum = $this->connection->getMapper('EnumTest')->find(1);
$enum = $this->connection->getRepository('EnumTest')->find(1);
$this->conn->exec('DELETE FROM enum_test WHERE id = 1');
......
......@@ -197,7 +197,7 @@ class Doctrine_UnitTestCase extends UnitTestCase
//echo "exporting : " . var_dump($this->tables);
//echo "<br /><br />";
$this->conn->export->exportClasses($this->tables);
$this->objTable = $this->connection->getMapper('User');
$this->objTable = $this->connection->getRepository('User');
}
public function prepareData()
......
......@@ -152,7 +152,7 @@ class Doctrine_Inheritance_Joined_TestCase extends Doctrine_UnitTestCase
public function testDqlQueryJoinsTransparentlyAcrossParents()
{
$this->_createManager();
$this->conn->getMapper('CTI_Manager')->clear();
$this->conn->clear('CTI_Manager');
$query = $this->conn->createQuery();
$query->parseQuery("SELECT m.* FROM CTI_Manager m");
......@@ -167,8 +167,8 @@ class Doctrine_Inheritance_Joined_TestCase extends Doctrine_UnitTestCase
public function testQueryingBaseClassOuterJoinsSubClassesAndReturnsSubclassInstances()
{
$this->_createManager();
$this->conn->getMapper('CTI_Manager')->clear();
$this->conn->getMapper('CTI_User')->clear();
$this->conn->clear('CTI_Manager');
$this->conn->clear('CTI_User');
$query = $this->conn->createQuery();
$query->parseQuery("SELECT u.* FROM CTI_User u");
......
......@@ -41,9 +41,9 @@ class Doctrine_Query_JoinCondition2_TestCase extends Doctrine_UnitTestCase
public function prepareData()
{
$this->conn->getMapper('User')->clear();
$this->conn->getMapper('Group')->clear();
$this->conn->getMapper('Groupuser')->clear();
$this->conn->clear('User');
$this->conn->clear('Group');
$this->conn->clear('Groupuser');
$zYne = new User();
$zYne->name = 'zYne';
......
......@@ -43,7 +43,7 @@ class Doctrine_Query_MultiJoin_TestCase extends Doctrine_UnitTestCase
$query = new Doctrine_Query($this->connection);
$user = $this->connection->getMapper('User')->find(4);
$user = $this->connection->getRepository('User')->find(4);
$album = $this->connection->create('Album');
......@@ -73,7 +73,7 @@ class Doctrine_Query_MultiJoin_TestCase extends Doctrine_UnitTestCase
$this->assertEqual(count($user->Album[1]->Song), 4);
$user = $this->connection->getMapper('User')->find(5);
$user = $this->connection->getRepository('User')->find(5);
$user->Album[0]->name = 'Clayman';
$user->Album[1]->name = 'Colony';
......@@ -122,7 +122,7 @@ class Doctrine_Query_MultiJoin_TestCase extends Doctrine_UnitTestCase
public function testInitializeMoreData()
{
$user = $this->connection->getMapper('User')->find(4);
$user = $this->connection->getRepository('User')->find(4);
$user->Book[0]->name = 'The Prince';
$user->Book[0]->Author[0]->name = 'Niccolo Machiavelli';
$user->Book[0]->Author[1]->name = 'Someone';
......@@ -133,7 +133,7 @@ class Doctrine_Query_MultiJoin_TestCase extends Doctrine_UnitTestCase
$user->save();
$user = $this->connection->getMapper('User')->find(5);
$user = $this->connection->getRepository('User')->find(5);
$user->Book[0]->name = 'Zadig';
$user->Book[0]->Author[0]->name = 'Voltaire';
$user->Book[0]->Author[1]->name = 'Someone';
......
......@@ -60,7 +60,7 @@ class Doctrine_Query_ReferenceModel_TestCase extends Doctrine_UnitTestCase {
$this->connection->unitOfWork->saveAll();
$this->connection->clear();
$category = $category->getMapper()->find($category->id);
$category = $category->getRepository()->find($category->id);
$this->assertEqual($category->name, 'Root');
$this->assertEqual($category->Subcategory[0]->name, 'Sub 1');
......
......@@ -62,6 +62,6 @@ class Doctrine_Query_Registry_TestCase extends Doctrine_UnitTestCase
$user = new User();
$user->getMapper()->executeNamedQuery('User.all');
$user->getEntityManager()->executeNamedQuery('User.all');
}
}
......@@ -89,7 +89,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($account->amount, 2000);
$user = $user->getMapper()->find($user->id);
$user = $user->getRepository()->find($user->id);
$this->assertEqual($user->state(), Doctrine_Record::STATE_CLEAN);
......@@ -148,7 +148,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($gzip->gzip, "compressed");
$this->connection->clear();
$gzip = $gzip->getMapper()->find($gzip->id);
$gzip = $gzip->getRepository()->find($gzip->id);
$this->assertEqual($gzip->gzip, "compressed");
$gzip->gzip = "compressed 2";
......@@ -209,7 +209,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertTrue(array_key_exists('id', $a));
$this->assertTrue(is_numeric($a['id']));
$this->connection->clear();
$user = $user->getMapper()->find($user->id);
$user = $user->getRepository()->find($user->id);
$a = $user->toArray();
......@@ -231,7 +231,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testUpdatingWithNullValue()
{
$user = $this->connection->getMapper('User')->find(5);
$user = $this->connection->getRepository('User')->find(5);
$user->name = null;
$this->assertEqual($user->name, null);
......@@ -241,7 +241,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->connection->clear();
$user = $this->connection->getMapper('User')->find(5);
$user = $this->connection->getRepository('User')->find(5);
$this->assertEqual($user->name, null);
......@@ -249,7 +249,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testSerialize()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$str = serialize($user);
$user2 = unserialize($str);
......@@ -279,7 +279,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($record->entity2, 4);
$this->assertEqual($record->entity1, 3);
$this->assertEqual($record->state(), Doctrine_Record::STATE_TDIRTY);
$this->assertEqual($record->identifier(), array("entity1" => null, "entity2" => null));
$this->assertEqual($record->identifier(), array("entity1" => 3, "entity2" => 4));
$record->save();
$this->assertEqual($record->state(), Doctrine_Record::STATE_CLEAN);
......@@ -287,7 +287,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($record->entity1, 3);
$this->assertEqual($record->identifier(), array("entity1" => 3, "entity2" => 4));
$record = $record->getMapper()->find($record->identifier());
$record = $record->getRepository()->find($record->identifier());
$this->assertEqual($record->state(), Doctrine_Record::STATE_CLEAN);
$this->assertEqual($record->entity2, 4);
$this->assertEqual($record->entity1, 3);
......@@ -306,7 +306,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($record->entity2, 5);
$this->assertEqual($record->entity1, 2);
$this->assertEqual($record->identifier(), array("entity1" => 2, "entity2" => 5));
$record = $record->getMapper()->find($record->identifier());
$record = $record->getRepository()->find($record->identifier());
$this->assertEqual($record->state(), Doctrine_Record::STATE_CLEAN);
$this->assertEqual($record->entity2, 5);
......@@ -314,6 +314,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($record->identifier(), array("entity1" => 2, "entity2" => 5));
$record->refresh();
$this->assertEqual($record->state(), Doctrine_Record::STATE_CLEAN);
$this->assertEqual($record->entity2, 5);
$this->assertEqual($record->entity1, 2);
......@@ -368,7 +369,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->connection->unitOfWork->saveAll();
$task = $task->getMapper()->find($task->identifier());
$task = $task->getRepository()->find($task->identifier());
$this->assertEqual($task->name, "Task 1");
$this->assertEqual($task->ResourceAlias[0]->name, "Resource 1");
......@@ -386,7 +387,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($user->updated, null);
$user->save();
$id = $user->identifier();
$user = $user->getMapper()->find($id);
$user = $user->getRepository()->find($id);
$this->assertEqual($user->name, "Jack Daniels");
$this->assertEqual($user->created, null);
$this->assertEqual($user->updated, null);
......@@ -439,12 +440,12 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$elements = $this->connection->query("FROM Element");
$this->assertEqual($elements->count(), 5);
$e = $e->getMapper()->find(1);
$e = $e->getRepository()->find(1);
$this->assertEqual($e->name,"parent");
$this->assertEqual($e->Child[0]->name,"child 1");
$c = $e->getMapper()->find(2);
$c = $e->getRepository()->find(2);
$this->assertEqual($c->name, "child 1");
$this->assertEqual($e->Child[0]->parent_id, 1);
......@@ -553,7 +554,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testUpdate()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$user->set("name","Jack Daniels",true);
......@@ -566,7 +567,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testCopy()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$new = $user->copy();
$this->assertTrue($new instanceof Doctrine_Record);
......@@ -583,7 +584,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testCopyAndModify()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$new = $user->copy();
$this->assertTrue($new instanceof Doctrine_Record);
......@@ -604,7 +605,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testReferences()
{
$user = $this->connection->getMapper('User')->find(5);
$user = $this->connection->getRepository('User')->find(5);
$this->assertTrue($user->Phonenumber instanceof Doctrine_Collection);
$this->assertEqual($user->Phonenumber->count(), 3);
......@@ -615,7 +616,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
$this->assertEqual($user->Phonenumber->count(), 0);
$user->save();
$user->getMapper()->clear();
$user->getEntityManager()->clear('User');
$user = $this->objTable->find(5);
......@@ -736,15 +737,11 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testSaveAssociations()
{
$userMapper = $this->connection->getMapper('User');
$userMapper = $this->connection->getRepository('User');
$user = $userMapper->find(5);
$this->assertTrue($userMapper === $user->getMapper());
$this->assertTrue($userMapper->getTable() === $user->getMapper()->getTable());
$this->assertTrue($userMapper->getTable() === $this->conn->getClassMetadata('User'));
$this->assertTrue($this->conn === $userMapper->getConnection());
$userTable = $userMapper->getTable();
$userTable = $this->connection->getClassMetadata('User');
/*echo get_class($rel1) . "<br />";
echo get_class($rel2) . "<br />";
echo get_class($userTable->getRelation('Group'));
......@@ -753,7 +750,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
echo "local:" . $rel2->getLocal() . "---foreign:" . $rel2->getForeign() . "<br />";
echo "........<br />";*/
$gf = $this->connection->getMapper("Group");
$gf = $this->connection->getRepository("Group");
//echo "start";
$this->assertTrue($user->Group instanceof Doctrine_Collection);
//echo "end";
......@@ -865,14 +862,14 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testCount()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$this->assertTrue(is_integer($user->count()));
}
public function testGetReference()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$this->assertTrue($user->Email instanceof Doctrine_Record);
$this->assertTrue($user->Phonenumber instanceof Doctrine_Collection);
......@@ -882,13 +879,13 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
}
public function testGetIterator()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$this->assertTrue($user->getIterator() instanceof ArrayIterator);
}
public function testRefreshRelated()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$user->Address[0]->address = "Address #1";
$user->Address[1]->address = "Address #2";
$user->save();
......@@ -904,7 +901,7 @@ class Doctrine_Record_TestCase extends Doctrine_UnitTestCase
public function testRefreshDeep()
{
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
$user->Address[0]->address = "Address #1";
$user->Address[1]->address = "Address #2";
$user->save();
......
......@@ -117,7 +117,7 @@ class Doctrine_Relation_Nest_TestCase extends Doctrine_UnitTestCase
$this->connection->clear();
$e = $e->getMapper()->find($e->id);
$e = $e->getRepository()->find($e->id);
$count = count($this->conn);
......
......@@ -83,7 +83,7 @@ class Doctrine_Table_TestCase extends Doctrine_UnitTestCase
$this->connection->clear();
$t = $this->connection->getMapper('FieldNameTest')->find(1);
$t = $this->connection->getRepository('FieldNameTest')->find(1);
$this->assertEqual($t->someColumn, 'abc');
$this->assertEqual($t->someEnum, 'php');
......
......@@ -37,7 +37,7 @@ class Doctrine_Ticket_626D_TestCase extends Doctrine_UnitTestCase
$student1 = $this->newStudent('T626D_Student1', '07090002', 'First Student');
try {
$student = $this->conn->getMapper('T626D_Student1')->find('07090002');
$student = $this->conn->getRepository('T626D_Student1')->find('07090002');
$this->pass();
} catch (Exception $e) {
$this->fail($e->__toString());
......
......@@ -140,7 +140,7 @@ class Doctrine_Validator_TestCase extends Doctrine_UnitTestCase
public function testValidate()
{
$this->manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);
$user = $this->connection->getMapper('User')->find(4);
$user = $this->connection->getRepository('User')->find(4);
$set = array('password' => 'this is an example of too long password',
'loginname' => 'this is an example of too long loginname',
......@@ -200,7 +200,7 @@ class Doctrine_Validator_TestCase extends Doctrine_UnitTestCase
public function testSave()
{
$this->manager->setAttribute(Doctrine::ATTR_VALIDATE, Doctrine::VALIDATE_ALL);
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
try {
$user->name = "this is an example of too long name not very good example but an example nevertheless";
$user->save();
......@@ -260,7 +260,7 @@ class Doctrine_Validator_TestCase extends Doctrine_UnitTestCase
}
// Tests validateOnUpdate()
$user = $this->connection->getMapper("User")->find(4);
$user = $this->connection->getRepository("User")->find(4);
try {
$user->name = "The Saint"; // Set correct name
$user->password = "Top Secret"; // Set correct password
......@@ -337,7 +337,7 @@ class Doctrine_Validator_TestCase extends Doctrine_UnitTestCase
$r->identifier = '1234';
$r->save();
$r = $this->connection->getMapper('ValidatorTest_Person')->findAll()->getFirst();
$r = $this->connection->getRepository('ValidatorTest_Person')->findAll()->getFirst();
$r->identifier = 1234;
try {
$r->save();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment