Commit 60fb69dd authored by romanb's avatar romanb

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

parent 1843539f
......@@ -8,7 +8,6 @@
#use \Countable;
#use \IteratorAggregate;
#use \Serializable;
#use \ArrayAccess;
/**
......@@ -17,7 +16,8 @@
*
* @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.
* This is the wrapped php array.
......@@ -89,10 +89,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
}
/**
* __isset()
*
* @param string $name
* @return boolean whether or not this object contains $name
* @see containsKey()
*/
public function __isset($key)
{
......@@ -100,10 +97,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
}
/**
* __unset()
*
* @param string $key
* @return mixed
* @see remove()
*/
public function __unset($key)
{
......@@ -113,10 +107,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
/* ArrayAccess implementation */
/**
* Check if an offset exists.
*
* @param mixed $offset
* @return boolean Whether or not this object contains $offset
* @see containsKey()
*/
public function offsetExists($offset)
{
......@@ -124,12 +115,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
}
/**
* Gets the element with the given key.
*
* Part of the ArrayAccess implementation.
*
* @param mixed $offset
* @return mixed
* @see get()
*/
public function offsetGet($offset)
{
......@@ -137,13 +123,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
}
/**
* Part of the ArrayAccess implementation.
*
* sets $offset to $value
* @see set, __set
* @param mixed $offset
* @param mixed $value
* @return void
* @see add()
* @see set()
*/
public function offsetSet($offset, $value)
{
......@@ -154,11 +135,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
}
/**
* Part of the ArrayAccess implementation.
*
* unset a given offset
* @see set, offsetSet, __set
* @param mixed $offset
* @see remove()
*/
public function offsetUnset($offset)
{
......@@ -171,7 +148,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* Checks whether the collection contains a specific key/index.
*
* @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)
{
......@@ -185,7 +162,8 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* For objects this means reference equality.
*
* @param mixed $element
* @return boolean
* @return boolean TRUE if the given element is contained in the collection,
* FALSE otherwise.
*/
public function contains($element)
{
......@@ -196,9 +174,9 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
* Tests for the existance of an element that satisfies the given predicate.
*
* @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)
if ($func($key, $element))
return true;
......@@ -213,7 +191,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
*/
public function containsAll($otherColl)
{
//...
throw new Doctrine_Exception("Not yet implemented.");
}
/**
......@@ -343,7 +321,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
*
* @param function $func
*/
public function map($func)
public function map(Closure $func)
{
return new Doctrine_Common_Collections_Collection(array_map($func, $this->_data));
}
......@@ -354,7 +332,7 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
*
* @param function $func
*/
public function filter($func)
public function filter(Closure $func)
{
return new Doctrine_Common_Collections_Collection(array_filter($this->_data, $func));
}
......@@ -376,39 +354,5 @@ class Doctrine_Common_Collections_Collection implements Countable, IteratorAggre
{
$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 @@
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())
{
return new Doctrine_DBAL_Driver_PDOConnection(
$conn = new Doctrine_DBAL_Driver_PDOConnection(
$this->_constructPdoDsn($params),
$username,
$password,
$driverOptions);
$conn->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
return $conn;
}
/**
......@@ -54,4 +64,3 @@ class Doctrine_DBAL_Driver_PDOMySql_Driver implements Doctrine_DBAL_Driver
}
?>
\ No newline at end of file
......@@ -24,12 +24,8 @@
/**
* A persistent collection wrapper.
*
* A collection object is strongly typed in the sense that it can only contain
* entities of a specific type or one of it's subtypes. A collection object is
* 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.
* A PersistentCollection represents a collection of entities. Collections of
* entities represent only the associations (links) to those entities.
* 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).
* Similarly, if you remove entities from a collection that is part of a one-many
......@@ -46,14 +42,14 @@
* @author Roman Borschel <roman@code-factory.org>
* @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.
*
* @var string
*/
protected $_entityBaseType;
private $_entityBaseType;
/**
* 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
*
* @var array
*/
protected $_snapshot = array();
private $_snapshot = array();
/**
* The entity that owns this collection.
*
* @var Doctrine\ORM\Entity
* @var object
*/
protected $_owner;
private $_owner;
/**
* The association mapping the collection belongs to.
......@@ -76,21 +72,21 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
*
* @var Doctrine\ORM\Mapping\AssociationMapping
*/
protected $_association;
private $_association;
/**
* The name of the field that is used for collection key mapping.
*
* @var string
*/
protected $_keyField;
private $_keyField;
/**
* The EntityManager that manages the persistence of the collection.
*
* @var Doctrine\ORM\EntityManager
*/
protected $_em;
private $_em;
/**
* 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
*
* @var string
*/
protected $_backRefFieldName;
private $_backRefFieldName;
/**
* Hydration flag.
......@@ -106,7 +102,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* @var boolean
* @see _setHydrationFlag()
*/
protected $_hydrationFlag;
private $_hydrationFlag;
/**
* Creates a new persistent collection.
......@@ -115,7 +111,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
{
$this->_entityBaseType = $entityBaseType;
$this->_em = $em;
if ($keyField !== null) {
if ( ! $this->_em->getClassMetadata($entityBaseType)->hasField($keyField)) {
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
}
}
/**
* setData
*
* @param array $data
* @todo Remove?
*/
public function setData(array $data)
{
$this->_data = $data;
}
/**
* INTERNAL: Sets the key column for this collection
*
......@@ -161,7 +145,8 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* INTERNAL:
* 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)
{
......@@ -184,7 +169,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* INTERNAL:
* Gets the collection owner.
*
* @return Doctrine\ORM\Entity
* @return object
*/
public function _getOwner()
{
......@@ -196,6 +181,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
*
* @param mixed $key
* @return boolean
* @override
*/
public function remove($key)
{
......@@ -205,8 +191,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/*if ($this->_association->isOneToMany() && $this->_association->shouldDeleteOrphans()) {
$this->_em->delete($removed);
}*/
return parent::remove($key);
$removed = parent::remove($key);
$this->_changed();
return $removed;
}
/**
......@@ -215,13 +202,13 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
*
* @param integer $key
* @param mixed $value
* @return void
* @override
*/
public function set($key, $value)
{
parent::set($key, $value);
//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
* @param mixed $value
* @param string $key
* @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 ($this->_hydrationFlag) {
......@@ -287,10 +275,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
* Snapshots are used for diff processing, for example
* when a fetched collection has three elements, then two of those
* 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()
{
......@@ -299,9 +283,9 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/**
* 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()
{
......@@ -366,7 +350,7 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/**
* INTERNAL: Gets the association mapping of the collection.
*
* @return Doctrine::ORM::Mapping::AssociationMapping
* @return Doctrine\ORM\Mapping\AssociationMapping
*/
public function getMapping()
{
......@@ -375,8 +359,6 @@ class Doctrine_ORM_Collection extends Doctrine_Common_Collections_Collection
/**
* Clears the collection.
*
* @return void
*/
public function clear()
{
......
......@@ -64,13 +64,12 @@ class Doctrine_ORM_EntityManager
* The currently active EntityManager. Only one EntityManager can be active
* at any time.
*
* @var Doctrine::ORM::EntityManager
* @var Doctrine\ORM\EntityManager
*/
private static $_activeEm;
/**
* The unique name of the EntityManager. The name is used to bind entity classes
* to certain EntityManagers.
* The unique name of the EntityManager.
*
* @var string
*/
......@@ -79,14 +78,14 @@ class Doctrine_ORM_EntityManager
/**
* The used Configuration.
*
* @var Configuration
* @var Doctrine\ORM\Configuration
*/
private $_config;
/**
* The database connection used by the EntityManager.
*
* @var Connection
* @var Doctrine\DBAL\Connection
*/
private $_conn;
......@@ -98,7 +97,7 @@ class Doctrine_ORM_EntityManager
private $_metadataFactory;
/**
* The EntityPersister instances.
* The EntityPersister instances used to persist entity instances.
*
* @var array
*/
......@@ -119,16 +118,16 @@ class Doctrine_ORM_EntityManager
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;
/**
* The event manager that is the central point of the event system.
*
* @var EventManager
* @var Doctrine\Common\EventManager
*/
private $_eventManager;
......@@ -139,6 +138,13 @@ class Doctrine_ORM_EntityManager
*/
private $_idGenerators = array();
/**
* The maintained (cached) hydrators. One instance per type.
*
* @var array
*/
private $_hydrators = array();
/** Whether the EntityManager is closed or not. */
private $_closed = false;
......@@ -224,7 +230,7 @@ class Doctrine_ORM_EntityManager
/**
* Returns the metadata for a class.
*
* @return Doctrine_Metadata
* @return Doctrine\ORM\Mapping\ClassMetadata
* @internal Performance-sensitive method.
*/
public function getClassMetadata($className)
......@@ -249,7 +255,7 @@ class Doctrine_ORM_EntityManager
* Used to lazily create the id generator.
*
* @param string $generatorType
* @return void
* @return object
*/
protected function _createIdGenerator($generatorType)
{
......@@ -349,6 +355,8 @@ class Doctrine_ORM_EntityManager
/**
* 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()
{
......@@ -362,7 +370,7 @@ class Doctrine_ORM_EntityManager
*
* @param string $entityName
* @param mixed $identifier
* @return Doctrine\ORM\Entity
* @return object
*/
public function find($entityName, $identifier)
{
......@@ -570,6 +578,49 @@ class Doctrine_ORM_EntityManager
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.
*
......@@ -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
$oid2 = spl_object_hash($entity2);
$sourceProp = $targetClass->getInverseAssociationMapping($fieldName)->getSourceFieldName();
$targetClass->getReflectionProperty($sourceProp)->setValue($entity2, $entity1);
$this->_entityData[$oid2][$sourceProp] = $entity1;
//$this->_entityData[$oid2][$sourceProp] = $entity1;
}
} else {
// for sure bidirectional, as there is no inverse side in unidirectional
$mappedByProp = $relation->getMappedByFieldName();
$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
public function updateResultPointer(&$resultPointers, &$coll, $index, $dqlAlias, $oneToOne)
{
if ($coll === null) {
echo "HERE!";
unset($resultPointers[$dqlAlias]); // Ticket #1228
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.
......@@ -55,6 +55,11 @@ class Doctrine_ORM_Query_ParserResultDummy
return $this->_tableToClassAliasMap;
}
public function getTableAliasMap()
{
return $this->_tableToClassAliasMap;
}
public function setTableToClassAliasMap(array $map)
{
$this->_tableToClassAliasMap = $map;
......
......@@ -68,4 +68,4 @@ class Doctrine_ORM_VirtualProxy
unset($realInstance->$prop);
}
}
?>
......@@ -6,7 +6,11 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
require_once 'lib/DoctrineTestInit.php';
// 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
{
......@@ -19,7 +23,11 @@ class Orm_Hydration_AllTests
{
$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;
}
......
This diff is collapsed.
<?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