Commit 60fb69dd authored by romanb's avatar romanb

First commit of new extensible hydrator structure. Cleanup to follow.

parent 1843539f
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#use \Countable; #use \Countable;
#use \IteratorAggregate; #use \IteratorAggregate;
#use \Serializable;
#use \ArrayAccess; #use \ArrayAccess;
/** /**
...@@ -17,7 +16,8 @@ ...@@ -17,7 +16,8 @@
* *
* @author robo * @author robo
*/ */
class Doctrine_Common_Collections_Collection implements Countable, IteratorAggregate, Serializable, ArrayAccess { class Doctrine_Common_Collections_Collection implements Countable, IteratorAggregate, ArrayAccess
{
/** /**
* An array containing the entries of this collection. * An array containing the entries of this collection.
* This is the wrapped php array. * This is the wrapped php array.
...@@ -89,10 +89,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -89,10 +89,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
} }
/** /**
* __isset() * @see containsKey()
*
* @param string $name
* @return boolean whether or not this object contains $name
*/ */
public function __isset($key) public function __isset($key)
{ {
...@@ -100,10 +97,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -100,10 +97,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
} }
/** /**
* __unset() * @see remove()
*
* @param string $key
* @return mixed
*/ */
public function __unset($key) public function __unset($key)
{ {
...@@ -113,10 +107,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -113,10 +107,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
/* ArrayAccess implementation */ /* ArrayAccess implementation */
/** /**
* Check if an offset exists. * @see containsKey()
*
* @param mixed $offset
* @return boolean Whether or not this object contains $offset
*/ */
public function offsetExists($offset) public function offsetExists($offset)
{ {
...@@ -124,12 +115,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -124,12 +115,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
} }
/** /**
* Gets the element with the given key. * @see get()
*
* Part of the ArrayAccess implementation.
*
* @param mixed $offset
* @return mixed
*/ */
public function offsetGet($offset) public function offsetGet($offset)
{ {
...@@ -137,13 +123,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -137,13 +123,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
} }
/** /**
* Part of the ArrayAccess implementation. * @see add()
* * @see set()
* sets $offset to $value
* @see set, __set
* @param mixed $offset
* @param mixed $value
* @return void
*/ */
public function offsetSet($offset, $value) public function offsetSet($offset, $value)
{ {
...@@ -154,11 +135,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -154,11 +135,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
} }
/** /**
* Part of the ArrayAccess implementation. * @see remove()
*
* unset a given offset
* @see set, offsetSet, __set
* @param mixed $offset
*/ */
public function offsetUnset($offset) public function offsetUnset($offset)
{ {
...@@ -171,7 +148,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -171,7 +148,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* Checks whether the collection contains a specific key/index. * Checks whether the collection contains a specific key/index.
* *
* @param mixed $key The key to check for. * @param mixed $key The key to check for.
* @return boolean * @return boolean TRUE if the given key/index exists, FALSE otherwise.
*/ */
public function containsKey($key) public function containsKey($key)
{ {
...@@ -185,7 +162,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -185,7 +162,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* For objects this means reference equality. * For objects this means reference equality.
* *
* @param mixed $element * @param mixed $element
* @return boolean * @return boolean TRUE if the given element is contained in the collection,
* FALSE otherwise.
*/ */
public function contains($element) public function contains($element)
{ {
...@@ -196,9 +174,9 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -196,9 +174,9 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* Tests for the existance of an element that satisfies the given predicate. * Tests for the existance of an element that satisfies the given predicate.
* *
* @param function $func * @param function $func
* @return boolean * @return boolean TRUE if the predicate is TRUE for at least one element, FALSe otherwise.
*/ */
public function exists($func) { public function exists(Closure $func) {
foreach ($this->_data as $key => $element) foreach ($this->_data as $key => $element)
if ($func($key, $element)) if ($func($key, $element))
return true; return true;
...@@ -213,7 +191,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -213,7 +191,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
*/ */
public function containsAll($otherColl) public function containsAll($otherColl)
{ {
//... throw new Doctrine_Exception("Not yet implemented.");
} }
/** /**
...@@ -343,7 +321,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -343,7 +321,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* *
* @param function $func * @param function $func
*/ */
public function map($func) public function map(Closure $func)
{ {
return new Doctrine_Common_Collections_Collection(array_map($func, $this->_data)); return new Doctrine_Common_Collections_Collection(array_map($func, $this->_data));
} }
...@@ -354,7 +332,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -354,7 +332,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* *
* @param function $func * @param function $func
*/ */
public function filter($func) public function filter(Closure $func)
{ {
return new Doctrine_Common_Collections_Collection(array_filter($this->_data, $func)); return new Doctrine_Common_Collections_Collection(array_filter($this->_data, $func));
} }
...@@ -376,39 +354,5 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre ...@@ -376,39 +354,5 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
{ {
$this->_data = array(); $this->_data = array();
} }
/* Serializable implementation */
/**
* Serializes the collection.
* This method is automatically called when the Collection is serialized.
*
* Part of the implementation of the Serializable interface.
*
* @return array
*/
public function serialize()
{
$vars = get_object_vars($this);
//TODO
return serialize($vars);
}
/**
* Reconstitutes the collection object from it's serialized form.
* This method is automatically called everytime the Collection object is unserialized.
*
* Part of the implementation of the Serializable interface.
*
* @param string $serialized The serialized data
*
* @return void
*/
public function unserialize($serialized)
{
//TODO
}
} }
...@@ -6,14 +6,24 @@ ...@@ -6,14 +6,24 @@
class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver
{ {
/**
* Attempts to establish a connection with the underlying driver.
*
* @param array $params
* @param string $username
* @param string $password
* @param array $driverOptions
* @return Doctrine\DBAL\Driver\Connection
*/
public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) public function connect(array $params, $username = null, $password = null, array $driverOptions = array())
{ {
return new Doctrine_DBAL_Driver_PDOConnection( $conn = new Doctrine_DBAL_Driver_PDOConnection(
$this->_constructPdoDsn($params), $this->_constructPdoDsn($params),
$username, $username,
$password, $password,
$driverOptions); $driverOptions);
$conn->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
return $conn;
} }
/** /**
...@@ -54,4 +64,3 @@ class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver ...@@ -54,4 +64,3 @@ class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver
} }
?>
\ No newline at end of file
...@@ -24,12 +24,8 @@ ...@@ -24,12 +24,8 @@
/** /**
* A persistent collection wrapper. * A persistent collection wrapper.
* *
* A collection object is strongly typed in the sense that it can only contain * A PersistentCollection represents a collection of entities. Collections of
* entities of a specific type or one of it's subtypes. A collection object is * entities represent only the associations (links) to those entities.
* basically a wrapper around an ordinary php array and just like a php array
* it can have List or Map semantics.
*
* A collection of entities represents only the associations (links) to those entities.
* That means, if the collection is part of a many-many mapping and you remove * That means, if the collection is part of a many-many mapping and you remove
* entities from the collection, only the links in the xref table are removed (on flush). * entities from the collection, only the links in the xref table are removed (on flush).
* Similarly, if you remove entities from a collection that is part of a one-many * Similarly, if you remove entities from a collection that is part of a one-many
...@@ -46,14 +42,14 @@ ...@@ -46,14 +42,14 @@
* @author Roman Borschel <roman@code-factory.org> * @author Roman Borschel <roman@code-factory.org>
* @todo Rename to PersistentCollection * @todo Rename to PersistentCollection
*/ */
class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection final class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
{ {
/** /**
* The base type of the collection. * The base type of the collection.
* *
* @var string * @var string
*/ */
protected $_entityBaseType; private $_entityBaseType;
/** /**
* A snapshot of the collection at the moment it was fetched from the database. * A snapshot of the collection at the moment it was fetched from the database.
...@@ -61,14 +57,14 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -61,14 +57,14 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* *
* @var array * @var array
*/ */
protected $_snapshot = array(); private $_snapshot = array();
/** /**
* The entity that owns this collection. * The entity that owns this collection.
* *
* @var Doctrine\ORM\Entity * @var object
*/ */
protected $_owner; private $_owner;
/** /**
* The association mapping the collection belongs to. * The association mapping the collection belongs to.
...@@ -76,21 +72,21 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -76,21 +72,21 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* *
* @var Doctrine\ORM\Mapping\AssociationMapping * @var Doctrine\ORM\Mapping\AssociationMapping
*/ */
protected $_association; private $_association;
/** /**
* The name of the field that is used for collection key mapping. * The name of the field that is used for collection key mapping.
* *
* @var string * @var string
*/ */
protected $_keyField; private $_keyField;
/** /**
* The EntityManager that manages the persistence of the collection. * The EntityManager that manages the persistence of the collection.
* *
* @var Doctrine\ORM\EntityManager * @var Doctrine\ORM\EntityManager
*/ */
protected $_em; private $_em;
/** /**
* The name of the field on the target entities that points to the owner * The name of the field on the target entities that points to the owner
...@@ -98,7 +94,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -98,7 +94,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* *
* @var string * @var string
*/ */
protected $_backRefFieldName; private $_backRefFieldName;
/** /**
* Hydration flag. * Hydration flag.
...@@ -106,7 +102,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -106,7 +102,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* @var boolean * @var boolean
* @see _setHydrationFlag() * @see _setHydrationFlag()
*/ */
protected $_hydrationFlag; private $_hydrationFlag;
/** /**
* Creates a new persistent collection. * Creates a new persistent collection.
...@@ -115,7 +111,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -115,7 +111,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
{ {
$this->_entityBaseType = $entityBaseType; $this->_entityBaseType = $entityBaseType;
$this->_em = $em; $this->_em = $em;
if ($keyField !== null) { if ($keyField !== null) {
if ( ! $this->_em->getClassMetadata($entityBaseType)->hasField($keyField)) { if ( ! $this->_em->getClassMetadata($entityBaseType)->hasField($keyField)) {
throw new Doctrine_Exception("Invalid field '$keyField' can't be uses as key."); throw new Doctrine_Exception("Invalid field '$keyField' can't be uses as key.");
...@@ -124,17 +119,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -124,17 +119,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
} }
} }
/**
* setData
*
* @param array $data
* @todo Remove?
*/
public function setData(array $data)
{
$this->_data = $data;
}
/** /**
* INTERNAL: Sets the key column for this collection * INTERNAL: Sets the key column for this collection
* *
...@@ -161,7 +145,8 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -161,7 +145,8 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* INTERNAL: * INTERNAL:
* Sets the collection owner. Used (only?) during hydration. * Sets the collection owner. Used (only?) during hydration.
* *
* @return void * @param object $entity
* @param AssociationMapping $relation
*/ */
public function _setOwner($entity, Doctrine_ORM_Mapping_AssociationMapping $relation) public function _setOwner($entity, Doctrine_ORM_Mapping_AssociationMapping $relation)
{ {
...@@ -184,7 +169,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -184,7 +169,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* INTERNAL: * INTERNAL:
* Gets the collection owner. * Gets the collection owner.
* *
* @return Doctrine\ORM\Entity * @return object
*/ */
public function _getOwner() public function _getOwner()
{ {
...@@ -196,6 +181,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -196,6 +181,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* *
* @param mixed $key * @param mixed $key
* @return boolean * @return boolean
* @override
*/ */
public function remove($key) public function remove($key)
{ {
...@@ -205,8 +191,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -205,8 +191,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/*if ($this->_association->isOneToMany() && $this->_association->shouldDeleteOrphans()) { /*if ($this->_association->isOneToMany() && $this->_association->shouldDeleteOrphans()) {
$this->_em->delete($removed); $this->_em->delete($removed);
}*/ }*/
$removed = parent::remove($key);
return parent::remove($key); $this->_changed();
return $removed;
} }
/** /**
...@@ -215,13 +202,13 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -215,13 +202,13 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* *
* @param integer $key * @param integer $key
* @param mixed $value * @param mixed $value
* @return void * @override
*/ */
public function set($key, $value) public function set($key, $value)
{ {
parent::set($key, $value); parent::set($key, $value);
//TODO: Register collection as dirty with the UoW if necessary //TODO: Register collection as dirty with the UoW if necessary
$this->_changed(); if ( ! $this->_hydrationFlag) $this->_changed();
} }
/** /**
...@@ -230,10 +217,11 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -230,10 +217,11 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* @param mixed $value * @param mixed $value
* @param string $key * @param string $key
* @return boolean * @return boolean
* @override
*/ */
public function add($value, $key = null) public function add($value)
{ {
$result = parent::add($value, $key); $result = parent::add($value);
if ( ! $result) return $result; // EARLY EXIT if ( ! $result) return $result; // EARLY EXIT
if ($this->_hydrationFlag) { if ($this->_hydrationFlag) {
...@@ -287,10 +275,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -287,10 +275,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* Snapshots are used for diff processing, for example * Snapshots are used for diff processing, for example
* when a fetched collection has three elements, then two of those * when a fetched collection has three elements, then two of those
* are being removed the diff would contain one element. * are being removed the diff would contain one element.
*
* Collection::save() attaches the diff with the help of last snapshot.
*
* @return void
*/ */
public function _takeSnapshot() public function _takeSnapshot()
{ {
...@@ -299,9 +283,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -299,9 +283,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/** /**
* INTERNAL: * INTERNAL:
* Returns the data of the last snapshot. * Returns the last snapshot of the elements in the collection.
* *
* @return array returns the data in last snapshot * @return array The last snapshot of the elements.
*/ */
public function _getSnapshot() public function _getSnapshot()
{ {
...@@ -366,7 +350,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -366,7 +350,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/** /**
* INTERNAL: Gets the association mapping of the collection. * INTERNAL: Gets the association mapping of the collection.
* *
* @return Doctrine::ORM::Mapping::AssociationMapping * @return Doctrine\ORM\Mapping\AssociationMapping
*/ */
public function getMapping() public function getMapping()
{ {
...@@ -375,8 +359,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection ...@@ -375,8 +359,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/** /**
* Clears the collection. * Clears the collection.
*
* @return void
*/ */
public function clear() public function clear()
{ {
......
...@@ -64,13 +64,12 @@ class Doctrine_ORM_EntityManager ...@@ -64,13 +64,12 @@ class Doctrine_ORM_EntityManager
* The currently active EntityManager. Only one EntityManager can be active * The currently active EntityManager. Only one EntityManager can be active
* at any time. * at any time.
* *
* @var Doctrine::ORM::EntityManager * @var Doctrine\ORM\EntityManager
*/ */
private static $_activeEm; private static $_activeEm;
/** /**
* The unique name of the EntityManager. The name is used to bind entity classes * The unique name of the EntityManager.
* to certain EntityManagers.
* *
* @var string * @var string
*/ */
...@@ -79,14 +78,14 @@ class Doctrine_ORM_EntityManager ...@@ -79,14 +78,14 @@ class Doctrine_ORM_EntityManager
/** /**
* The used Configuration. * The used Configuration.
* *
* @var Configuration * @var Doctrine\ORM\Configuration
*/ */
private $_config; private $_config;
/** /**
* The database connection used by the EntityManager. * The database connection used by the EntityManager.
* *
* @var Connection * @var Doctrine\DBAL\Connection
*/ */
private $_conn; private $_conn;
...@@ -98,7 +97,7 @@ class Doctrine_ORM_EntityManager ...@@ -98,7 +97,7 @@ class Doctrine_ORM_EntityManager
private $_metadataFactory; private $_metadataFactory;
/** /**
* The EntityPersister instances. * The EntityPersister instances used to persist entity instances.
* *
* @var array * @var array
*/ */
...@@ -119,16 +118,16 @@ class Doctrine_ORM_EntityManager ...@@ -119,16 +118,16 @@ class Doctrine_ORM_EntityManager
private $_flushMode = 'commit'; private $_flushMode = 'commit';
/** /**
* The unit of work used to coordinate object-level transactions. * The UnitOfWork used to coordinate object-level transactions.
* *
* @var UnitOfWork * @var Doctrine\ORM\UnitOfWork
*/ */
private $_unitOfWork; private $_unitOfWork;
/** /**
* The event manager that is the central point of the event system. * The event manager that is the central point of the event system.
* *
* @var EventManager * @var Doctrine\Common\EventManager
*/ */
private $_eventManager; private $_eventManager;
...@@ -139,6 +138,13 @@ class Doctrine_ORM_EntityManager ...@@ -139,6 +138,13 @@ class Doctrine_ORM_EntityManager
*/ */
private $_idGenerators = array(); private $_idGenerators = array();
/**
* The maintained (cached) hydrators. One instance per type.
*
* @var array
*/
private $_hydrators = array();
/** Whether the EntityManager is closed or not. */ /** Whether the EntityManager is closed or not. */
private $_closed = false; private $_closed = false;
...@@ -224,7 +230,7 @@ class Doctrine_ORM_EntityManager ...@@ -224,7 +230,7 @@ class Doctrine_ORM_EntityManager
/** /**
* Returns the metadata for a class. * Returns the metadata for a class.
* *
* @return Doctrine_Metadata * @return Doctrine\ORM\Mapping\ClassMetadata
* @internal Performance-sensitive method. * @internal Performance-sensitive method.
*/ */
public function getClassMetadata($className) public function getClassMetadata($className)
...@@ -249,7 +255,7 @@ class Doctrine_ORM_EntityManager ...@@ -249,7 +255,7 @@ class Doctrine_ORM_EntityManager
* Used to lazily create the id generator. * Used to lazily create the id generator.
* *
* @param string $generatorType * @param string $generatorType
* @return void * @return object
*/ */
protected function _createIdGenerator($generatorType) protected function _createIdGenerator($generatorType)
{ {
...@@ -349,6 +355,8 @@ class Doctrine_ORM_EntityManager ...@@ -349,6 +355,8 @@ class Doctrine_ORM_EntityManager
/** /**
* Flushes all changes to objects that have been queued up to now to the database. * Flushes all changes to objects that have been queued up to now to the database.
* This effectively synchronizes the in-memory state of managed objects with the
* database.
*/ */
public function flush() public function flush()
{ {
...@@ -362,7 +370,7 @@ class Doctrine_ORM_EntityManager ...@@ -362,7 +370,7 @@ class Doctrine_ORM_EntityManager
* *
* @param string $entityName * @param string $entityName
* @param mixed $identifier * @param mixed $identifier
* @return Doctrine\ORM\Entity * @return object
*/ */
public function find($entityName, $identifier) public function find($entityName, $identifier)
{ {
...@@ -569,6 +577,49 @@ class Doctrine_ORM_EntityManager ...@@ -569,6 +577,49 @@ class Doctrine_ORM_EntityManager
{ {
return self::$_activeEm === $this; return self::$_activeEm === $this;
} }
/**
* Gets a hydrator for the given hydration mode.
*
* @param $hydrationMode
*/
public function getHydrator($hydrationMode)
{
if ( ! isset($this->_hydrators[$hydrationMode])) {
switch ($hydrationMode) {
case Doctrine_ORM_Query::HYDRATE_OBJECT:
$this->_hydrators[$hydrationMode] = new Doctrine_ORM_Internal_Hydration_ObjectHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_ARRAY:
$this->_hydrators[$hydrationMode] = new Doctrine_ORM_Internal_Hydration_ArrayHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_SCALAR:
case Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR:
$this->_hydrators[$hydrationMode] = new Doctrine_ORM_Internal_Hydration_ScalarHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_NONE:
$this->_hydrators[$hydrationMode] = new Doctrine_ORM_Internal_Hydration_NoneHydrator($this);
break;
default:
throw new Doctrine_Exception("No hydrator found for hydration mode '$hydrationMode'.");
}
} else if ($this->_hydrators[$hydrationMode] instanceof Closure) {
$this->_hydrators[$hydrationMode] = $this->_hydrators[$hydrationMode]($this);
}
return $this->_hydrators[$hydrationMode];
}
/**
* Sets a hydrator for a hydration mode.
*
* @param mixed $hydrationMode
* @param object $hydrator Either a hydrator instance or a closure that creates a
* hydrator instance.
*/
public function setHydrator($hydrationMode, $hydrator)
{
$this->_hydrators[$hydrationMode] = $hydrator;
}
/** /**
* Makes this EntityManager the currently active one. * Makes this EntityManager the currently active one.
...@@ -630,4 +681,3 @@ class Doctrine_ORM_EntityManager ...@@ -630,4 +681,3 @@ class Doctrine_ORM_EntityManager
} }
} }
?>
\ No newline at end of file
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of ArrayHydrator
*
* @author robo
*/
class Doctrine_ORM_Internal_Hydration_ArrayHydrator extends Doctrine_ORM_Internal_Hydration_AbstractHydrator
{
private $_rootAlias;
private $_rootEntityName;
private $_isSimpleQuery = false;
private $_identifierMap = array();
private $_resultPointers = array();
private $_idTemplate = array();
private $_resultCounter = 0;
/** @override */
protected function _prepare($parserResult)
{
parent::_prepare($parserResult);
reset($this->_queryComponents);
$this->_rootAlias = key($this->_queryComponents);
$this->_rootEntityName = $this->_queryComponents[$this->_rootAlias]['metadata']->getClassName();
$this->_isSimpleQuery = count($this->_queryComponents) <= 1;
$this->_identifierMap = array();
$this->_resultPointers = array();
$this->_idTemplate = array();
$this->_resultCounter = 0;
foreach ($this->_queryComponents as $dqlAlias => $component) {
$this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
}
}
/** @override */
protected function _hydrateAll($parserResult)
{
$s = microtime(true);
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$this->_hydrateRow($data, $cache, $result);
}
$e = microtime(true);
echo 'Hydration took: ' . ($e - $s) . PHP_EOL;
return $result;
}
/** @override */
protected function _hydrateRow(array &$data, array &$cache, &$result)
{
// 1) Initialize
$id = $this->_idTemplate; // initialize the id-memory
$nonemptyComponents = array();
$rowData = parent::_gatherRowData($data, $cache, $id, $nonemptyComponents);
$rootAlias = $this->_rootAlias;
// 2) Hydrate the data of the root entity from the current row
// Check for an existing element
$index = false;
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$rootAlias][$id[$rootAlias]])) {
$element = $rowData[$rootAlias];
if ($field = $this->_getCustomIndexField($rootAlias)) {
if ($this->_parserResult->isMixedQuery()) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_parserResult->isMixedQuery()) {
$result[] = array($element);
++$this->_resultCounter;
} else {
$result[] = $element;
}
}
end($result);
$this->_identifierMap[$rootAlias][$id[$rootAlias]] = key($result);
} else {
$index = $this->_identifierMap[$rootAlias][$id[$rootAlias]];
}
$this->updateResultPointer($result, $index, $rootAlias, false);
unset($rowData[$rootAlias]);
// end of hydrate data of the root component for the current row
// Extract scalar values. They're appended at the end.
if (isset($rowData['scalars'])) {
$scalars = $rowData['scalars'];
unset($rowData['scalars']);
}
// 3) Now hydrate the rest of the data found in the current row, that
// belongs to other (related) entities.
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$map = $this->_queryComponents[$dqlAlias];
$parent = $map['parent'];
$relationAlias = $map['relation']->getSourceFieldName();
$path = $parent . '.' . $dqlAlias;
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
if ($this->_parserResult->isMixedQuery() && $parent == $rootAlias) {
$key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key];
} else if (isset($this->_resultPointers[$parent])) {
$baseElement =& $this->_resultPointers[$parent];
} else {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
continue;
}
// Check the type of the relation (many or single-valued)
if ( ! $map['relation']->isOneToOne()) {
$oneToOne = false;
if (isset($nonemptyComponents[$dqlAlias])) {
if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array();
}
$indexExists = isset($this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]]);
$index = $indexExists ? $this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] : false;
$indexIsValid = $index !== false ? isset($baseElement[$relationAlias][$index]) : false;
if ( ! $indexExists || ! $indexIsValid) {
$element = $data;
if ($field = $this->_getCustomIndexField($dqlAlias)) {
$baseElement[$relationAlias][$element[$field]] = $element;
} else {
$baseElement[$relationAlias][] = $element;
}
end($baseElement[$relationAlias]);
$this->_identifierMap[$path][$id[$parent]][$id[$dqlAlias]] =
key($baseElement[$relationAlias]);
}
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = array();
}
} else {
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias]) && ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = null;
} else if ( ! isset($baseElement[$relationAlias])) {
$baseElement[$relationAlias] = $data;
}
}
$coll =& $baseElement[$relationAlias];
if ($coll !== null) {
$this->updateResultPointer($coll, $index, $dqlAlias, $oneToOne);
}
}
// Append scalar values to mixed result sets
if (isset($scalars)) {
foreach ($scalars as $name => $value) {
$result[$this->_resultCounter - 1][$name] = $value;
}
}
}
/**
* Updates the result pointer for an Entity. The result pointers point to the
* last seen instance of each Entity type. This is used for graph construction.
*
* @param array $coll The element.
* @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.
*/
private function updateResultPointer(&$coll, $index, $dqlAlias, $oneToOne)
{
if ($coll === null) {
unset($this->_resultPointers[$dqlAlias]); // Ticket #1228
return;
}
if ($index !== false) {
$this->_resultPointers[$dqlAlias] =& $coll[$index];
return;
} else {
if ($coll) {
if ($oneToOne) {
$this->_resultPointers[$dqlAlias] =& $coll;
} else {
end($coll);
$this->_resultPointers[$dqlAlias] =& $coll[key($coll)];
}
}
}
}
/** {@inheritdoc} */
protected function _getRowContainer()
{
return array();
}
}
<?php
/**
* Represents a result structure that can be iterated over, hydrating row-by-row
* during the iteration. An IterableResult is obtained by AbstractHydrator#iterate().
*
* @author robo
* @since 2.0
*/
class Doctrine_ORM_Internal_Hydration_IterableResult
{
private $_hydrator;
public function __construct($hydrator)
{
$this->_hydrator = $hydrator;
}
/**
* Gets the next set of results.
*
* @return array
*/
public function next()
{
return $this->_hydrator->hydrateRow();
}
}
...@@ -159,13 +159,13 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver ...@@ -159,13 +159,13 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
$oid2 = spl_object_hash($entity2); $oid2 = spl_object_hash($entity2);
$sourceProp = $targetClass->getInverseAssociationMapping($fieldName)->getSourceFieldName(); $sourceProp = $targetClass->getInverseAssociationMapping($fieldName)->getSourceFieldName();
$targetClass->getReflectionProperty($sourceProp)->setValue($entity2, $entity1); $targetClass->getReflectionProperty($sourceProp)->setValue($entity2, $entity1);
$this->_entityData[$oid2][$sourceProp] = $entity1; //$this->_entityData[$oid2][$sourceProp] = $entity1;
} }
} else { } else {
// for sure bidirectional, as there is no inverse side in unidirectional // for sure bidirectional, as there is no inverse side in unidirectional
$mappedByProp = $relation->getMappedByFieldName(); $mappedByProp = $relation->getMappedByFieldName();
$targetClass->getReflectionProperty($mappedByProp)->setValue($entity2, $entity1); $targetClass->getReflectionProperty($mappedByProp)->setValue($entity2, $entity1);
$this->_entityData[spl_object_hash($entity2)][$mappedByProp] = $entity1; //$this->_entityData[spl_object_hash($entity2)][$mappedByProp] = $entity1;
} }
} }
} }
...@@ -217,7 +217,6 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver ...@@ -217,7 +217,6 @@ class Doctrine_ORM_Internal_Hydration_ObjectDriver
public function updateResultPointer(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne) public function updateResultPointer(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne)
{ {
if ($coll === null) { if ($coll === null) {
echo "HERE!";
unset($resultPointers[$dqlAlias]); // Ticket #1228 unset($resultPointers[$dqlAlias]); // Ticket #1228
return; return;
} }
......
This diff is collapsed.
<?php
/**
* Hydrator that produces flat, rectangular results of scalar data.
* The created result is almost the same as a regular SQL result set, except
* that column names are mapped to field names and data type conversions.
*
* @author robo
* @since 2.0
*/
class Doctrine_ORM_Internal_Hydration_ScalarHydrator extends Doctrine_ORM_Internal_Hydration_AbstractHydrator
{
/** @override */
protected function _hydrateAll($parserResult)
{
$result = array();
$cache = array();
while ($data = $this->_stmt->fetch(PDO::FETCH_ASSOC)) {
$result[] = $this->_gatherScalarRowData($data, $cache);
}
return $result;
}
/** @override */
protected function _hydrateRow(array &$data, array &$cache, &$result)
{
$result[] = $this->_gatherScalarRowData($data, $cache);
}
/** @override */
protected function _getRowContainer()
{
return array();
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of SingleScalarHydrator
*
* @author robo
*/
class Doctrine_ORM_Internal_Hydration_SingleScalarHydrator extends Doctrine_ORM_Internal_Hydration_AbstractHydrator
{
/** @override */
protected function _hydrateAll($parserResult)
{
$cache = array();
$result = $this->_stmt->fetchAll(PDO::FETCH_ASSOC);
//TODO: Let this exception be raised by Query as QueryException
if (count($result) > 1 || count($result[0]) > 1) {
throw Doctrine_ORM_Exceptions_HydrationException::nonUniqueResult();
}
$result = $this->_gatherScalarRowData($result[0], $cache);
return array_shift($result);
}
/** {@inheritdoc} */
protected function _getRowContainer()
{
return array();
}
}
This diff is collapsed.
...@@ -54,6 +54,11 @@ class Doctrine_ORM_Query_ParserResultDummy ...@@ -54,6 +54,11 @@ class Doctrine_ORM_Query_ParserResultDummy
{ {
return $this->_tableToClassAliasMap; return $this->_tableToClassAliasMap;
} }
public function getTableAliasMap()
{
return $this->_tableToClassAliasMap;
}
public function setTableToClassAliasMap(array $map) public function setTableToClassAliasMap(array $map)
{ {
......
...@@ -68,4 +68,4 @@ class Doctrine_ORM_VirtualProxy ...@@ -68,4 +68,4 @@ class Doctrine_ORM_VirtualProxy
unset($realInstance->$prop); unset($realInstance->$prop);
} }
} }
?>
...@@ -6,7 +6,11 @@ if (!defined('PHPUnit_MAIN_METHOD')) { ...@@ -6,7 +6,11 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
require_once 'lib/DoctrineTestInit.php'; require_once 'lib/DoctrineTestInit.php';
// Tests // Tests
require_once 'Orm/Hydration/BasicHydrationTest.php'; //require_once 'Orm/Hydration/BasicHydrationTest.php';
require_once 'Orm/Hydration/ObjectHydratorTest.php';
require_once 'Orm/Hydration/ArrayHydratorTest.php';
require_once 'Orm/Hydration/ScalarHydratorTest.php';
require_once 'Orm/Hydration/SingleScalarHydratorTest.php';
class Orm_Hydration_AllTests class Orm_Hydration_AllTests
{ {
...@@ -19,7 +23,11 @@ class Orm_Hydration_AllTests ...@@ -19,7 +23,11 @@ class Orm_Hydration_AllTests
{ {
$suite = new Doctrine_TestSuite('Doctrine Orm Hydration'); $suite = new Doctrine_TestSuite('Doctrine Orm Hydration');
$suite->addTestSuite('Orm_Hydration_BasicHydrationTest'); //$suite->addTestSuite('Orm_Hydration_BasicHydrationTest');
$suite->addTestSuite('Orm_Hydration_ObjectHydratorTest');
$suite->addTestSuite('Orm_Hydration_ArrayHydratorTest');
$suite->addTestSuite('Orm_Hydration_ScalarHydratorTest');
$suite->addTestSuite('Orm_Hydration_SingleScalarHydratorTest');
return $suite; return $suite;
} }
......
This diff is collapsed.
...@@ -686,7 +686,7 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase ...@@ -686,7 +686,7 @@ class Orm_Hydration_BasicHydrationTest extends Doctrine_OrmTestCase
$stmt = new Doctrine_HydratorMockStatement($resultSet); $stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_ORM_Internal_Hydration_StandardHydrator($this->_em); $hydrator = new Doctrine_ORM_Internal_Hydration_StandardHydrator($this->_em);
$result = $hydrator->hydrateResultSet($this->_createParserResult( $result = $hydrator->hydrateResultSet($this->_createParserResult(
$stmt, $queryComponents, $tableAliasMap, $hydrationMode, true)); $stmt, $queryComponents, $tableAliasMap, $hydrationMode, true));
if ($hydrationMode == Doctrine_ORM_Query::HYDRATE_ARRAY) { if ($hydrationMode == Doctrine_ORM_Query::HYDRATE_ARRAY) {
......
<?php
require_once 'lib/DoctrineTestInit.php';
require_once 'lib/mocks/Doctrine_HydratorMockStatement.php';
/**
* Description of HydrationTest
*
* @author robo
*/
class Orm_Hydration_HydrationTest extends Doctrine_OrmTestCase
{
protected $_em;
protected function setUp()
{
parent::setUp();
$this->_em = $this->_getTestEntityManager();
}
/** Helper method */
protected function _createParserResult($stmt, $queryComponents, $tableToClassAliasMap,
$hydrationMode, $isMixedQuery = false)
{
$parserResult = new Doctrine_ORM_Query_ParserResultDummy();
$parserResult->setDatabaseStatement($stmt);
$parserResult->setHydrationMode($hydrationMode);
$parserResult->setQueryComponents($queryComponents);
$parserResult->setTableToClassAliasMap($tableToClassAliasMap);
$parserResult->setMixedQuery($isMixedQuery);
return $parserResult;
}
}
This diff is collapsed.
<?php
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'HydrationTest.php';
/**
* Description of ScalarHydratorTest
*
* @author robo
*/
class Orm_Hydration_ScalarHydratorTest extends Orm_Hydration_HydrationTest
{
/**
* Select u.id, u.name from CmsUser u
*/
public function testNewHydrationSimpleEntityQuery()
{
// Faked query components
$queryComponents = array(
'u' => array(
'metadata' => $this->_em->getClassMetadata('CmsUser'),
'parent' => null,
'relation' => null,
'map' => null
)
);
// Faked table alias map
$tableAliasMap = array(
'u' => 'u'
);
// Faked result set
$resultSet = array(
array(
'u__id' => '1',
'u__name' => 'romanb'
),
array(
'u__id' => '2',
'u__name' => 'jwage'
)
);
$stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_ORM_Internal_Hydration_ScalarHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult(
$stmt, $queryComponents, $tableAliasMap, Doctrine_ORM_Query::HYDRATE_SCALAR));
$this->assertTrue(is_array($result));
$this->assertEquals(2, count($result));
$this->assertEquals('romanb', $result[0]['u_name']);
$this->assertEquals(1, $result[0]['u_id']);
$this->assertEquals('jwage', $result[1]['u_name']);
$this->assertEquals(2, $result[1]['u_id']);
}
}
<?php
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'HydrationTest.php';
/**
* Description of SingleScalarHydratorTest
*
* @author robo
*/
class Orm_Hydration_SingleScalarHydratorTest extends Orm_Hydration_HydrationTest
{
/** Result set provider for the HYDRATE_SINGLE_SCALAR tests */
public static function singleScalarResultSetProvider() {
return array(
// valid
array('name' => 'result1',
'resultSet' => array(
array(
'u__name' => 'romanb'
)
)),
// valid
array('name' => 'result2',
'resultSet' => array(
array(
'u__id' => '1'
)
)),
// invalid
array('name' => 'result3',
'resultSet' => array(
array(
'u__id' => '1',
'u__name' => 'romanb'
)
)),
// invalid
array('name' => 'result4',
'resultSet' => array(
array(
'u__id' => '1'
),
array(
'u__id' => '2'
)
)),
);
}
/**
* select u.name from CmsUser u where u.id = 1
*
* @dataProvider singleScalarResultSetProvider
*/
public function testHydrateSingleScalar($name, $resultSet)
{
// Faked query components
$queryComponents = array(
'u' => array(
'metadata' => $this->_em->getClassMetadata('CmsUser'),
'parent' => null,
'relation' => null,
'map' => null
)
);
// Faked table alias map
$tableAliasMap = array(
'u' => 'u'
);
$stmt = new Doctrine_HydratorMockStatement($resultSet);
$hydrator = new Doctrine_ORM_Internal_Hydration_SingleScalarHydrator($this->_em);
if ($name == 'result1') {
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult(
$stmt, $queryComponents, $tableAliasMap, Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR));
$this->assertEquals('romanb', $result);
} else if ($name == 'result2') {
$result = $hydrator->hydrateAll($stmt, $this->_createParserResult(
$stmt, $queryComponents, $tableAliasMap, Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR));
$this->assertEquals(1, $result);
} else if ($name == 'result3' || $name == 'result4') {
try {
$result = $hydrator->hydrateall($stmt, $this->_createParserResult(
$stmt, $queryComponents, $tableAliasMap, Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR));
$this->fail();
} catch (Doctrine_ORM_Exceptions_HydrationException $ex) {}
}
}
}
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