1
0
mirror of synced 2025-01-22 08:11:40 +03:00

Small reorganizations, improvements and progress.

This commit is contained in:
romanb 2009-02-07 17:02:13 +00:00
parent 2eb4a16dd4
commit 9dcab5ee63
33 changed files with 547 additions and 491 deletions

View File

@ -1,7 +1,22 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
* $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.doctrine-project.org>.
*/
namespace Doctrine\Common\Collections;
@ -12,10 +27,11 @@ use \ArrayAccess;
use \ArrayIterator;
/**
* A Collection is a wrapper around a php array and just like a php array a
* collection instance can be a list, a set or a map, depending on how it is used.
* A Collection is a thin wrapper around a php array. Think of it as an OO version
* of a plain array.
*
* @author robo
* @since 2.0
*/
class Collection implements Countable, IteratorAggregate, ArrayAccess
{
@ -25,7 +41,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*
* @var array
*/
protected $_data = array();
protected $_elements = array();
/**
*
@ -33,7 +49,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function __construct(array $elements = array())
{
$this->_data = $elements;
$this->_elements = $elements;
}
/**
@ -43,49 +59,49 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function unwrap()
{
return $this->_data;
return $this->_elements;
}
/**
* returns the first entry in the collection
* Gets the first element in the collection.
*
* @return mixed
*/
public function first()
{
return reset($this->_data);
return reset($this->_elements);
}
/**
* returns the last record in the collection
* Gets the last element in the collection.
*
* @return mixed
*/
public function last()
{
return end($this->_data);
return end($this->_elements);
}
/**
* returns the current key
* Gets the current key.
*
* @return mixed
*/
public function key()
{
return key($this->_data);
return key($this->_elements);
}
/**
* Removes an entry with a specific key from the collection.
* Removes an element with a specific key from the collection.
*
* @param mixed $key
* @return mixed
*/
public function remove($key)
{
$removed = $this->_data[$key];
unset($this->_data[$key]);
$removed = $this->_elements[$key];
unset($this->_elements[$key]);
return $removed;
}
@ -97,9 +113,9 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function removeElement($element)
{
$key = array_search($element, $this->_data, true);
$key = array_search($element, $this->_elements, true);
if ($key !== false) {
unset($this->_data[$key]);
unset($this->_elements[$key]);
return true;
}
return false;
@ -169,7 +185,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function containsKey($key)
{
return isset($this->_data[$key]);
return isset($this->_elements[$key]);
}
/**
@ -184,24 +200,23 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function contains($element)
{
return in_array($element, $this->_data, true);
return in_array($element, $this->_elements, true);
}
/**
* Tests for the existance of an element that satisfies the given predicate.
*
* @param function $func
* @param Closure $p The predicate.
* @return boolean TRUE if the predicate is TRUE for at least one element, FALSE otherwise.
*/
public function exists(Closure $func) {
foreach ($this->_data as $key => $element)
if ($func($key, $element))
return true;
public function exists(Closure $p) {
foreach ($this->_elements as $key => $element)
if ($p($key, $element)) return true;
return false;
}
/**
* Enter description here...
* TODO
*
* @param unknown_type $otherColl
* @todo Impl
@ -222,7 +237,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function search($element)
{
return array_search($element, $this->_data, true);
return array_search($element, $this->_elements, true);
}
/**
@ -233,20 +248,20 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function get($key)
{
if (isset($this->_data[$key])) {
return $this->_data[$key];
if (isset($this->_elements[$key])) {
return $this->_elements[$key];
}
return null;
}
/**
* Gets all keys/indexes.
* Gets all keys/indexes of the collection elements.
*
* @return array
*/
public function getKeys()
{
return array_keys($this->_data);
return array_keys($this->_elements);
}
/**
@ -256,7 +271,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function getElements()
{
return array_values($this->_data);
return array_values($this->_elements);
}
/**
@ -268,7 +283,7 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
*/
public function count()
{
return count($this->_data);
return count($this->_elements);
}
/**
@ -277,24 +292,23 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
* When the collection is a Map this is like put(key,value)/add(key,value).
* When the collection is a List this is like add(position,value).
*
* @param integer $key
* @param mixed $key
* @param mixed $value
*/
public function set($key, $value)
{
$this->_data[$key] = $value;
$this->_elements[$key] = $value;
}
/**
* Adds an element to the collection.
*
* @param mixed $value
* @param string $key
* @return boolean Always returns TRUE.
* @return boolean Always TRUE.
*/
public function add($value)
{
$this->_data[] = $value;
$this->_elements[] = $value;
return true;
}
@ -317,45 +331,80 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
public function isEmpty()
{
// Note: Little "trick". Empty arrays evaluate to FALSE. No need to count().
return ! (bool)$this->_data;
return ! (bool)$this->_elements;
}
/**
* Gets an iterator that enables foreach() iteration over the elements in
* the collection.
* Gets an iterator for iterating over the elements in the collection.
*
* @return ArrayIterator
*/
public function getIterator()
{
$data = $this->_data;
return new ArrayIterator($data);
return new ArrayIterator($this->_elements);
}
/**
* Applies the given function to each element in the collection and returns
* a new collection with the modified values.
* a new collection with the elements returned by the function.
*
* @param function $func
* @param Closure $func
*/
public function map(Closure $func)
{
return new Collection(array_map($func, $this->_data));
return new Collection(array_map($func, $this->_elements));
}
/**
* Applies the given function to each element in the collection and returns
* a new collection with the new values.
* Returns all the elements of this collection that satisfy the predicate p.
* The order of the elements is preserved.
*
* @param function $func
* @param Closure $p The predicate used for filtering.
* @return Collection A collection with the results of the filter operation.
*/
public function filter(Closure $func)
public function filter(Closure $p)
{
return new Collection(array_filter($this->_data, $func));
return new Collection(array_filter($this->_elements, $p));
}
/**
* returns a string representation of this object
* Applies the given predicate p to all elements of this collection,
* returning true, if the predicate yields true for all elements.
*
* @param Closure $p The predicate.
* @return boolean TRUE, if the predicate yields TRUE for all elements, FALSE otherwise.
*/
public function forall(Closure $p)
{
foreach ($this->_elements as $key => $element)
if ( ! $p($key, $element)) return false;
return true;
}
/**
* Partitions this collection in two collections according to a predicate.
* Keys are preserved in the resulting collections.
*
* @param Closure $p The predicate on which to partition.
* @return array An array with two elements. The first element contains the collection
* of elements where the predicate returned TRUE, the second element
* contains the collection of elements where the predicate returned FALSE.
*/
public function partition(Closure $p)
{
$coll1 = $coll2 = array();
foreach ($this->_elements as $key => $element) {
if ($p($key, $element)) {
$coll1[$key] = $element;
} else {
$coll2[$key] = $element;
}
}
return array(new Collection($coll1), new Collection($coll2));
}
/**
* Returns a string representation of this object.
*/
public function __toString()
{
@ -364,12 +413,10 @@ class Collection implements Countable, IteratorAggregate, ArrayAccess
/**
* Clears the collection.
*
* @return void
*/
public function clear()
{
$this->_data = array();
$this->_elements = array();
}
}

View File

@ -16,60 +16,51 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Events;
namespace Doctrine\Common;
/**
* Doctrine_Event
* EventArgs is the base class for classes containing event data.
*
* This class contains no event data and cannot be instantiated.
* It is used by events that do not pass state information to an event handler
* when an event is raised. The single empty EventArgs instance can be obtained
* through {@link getEmptyInstance()}.
*
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
*/
class Event
class EventArgs
{
/* Event callback constants */
const preDelete = 'preDelete';
const postDelete = 'postDelete';
//...more
private static $_emptyEventArgsInstance;
private $_defaultPrevented;
protected $_type;
protected $_target;
protected $_defaultPrevented;
public function __construct($type, $target = null)
protected function __construct()
{
$this->_type = $type;
$this->_target = $target;
$this->_defaultPrevented = false;
}
public function getType()
{
return $this->_type;
}
public function preventDefault()
{
$this->_defaultPrevented = true;
}
public function getDefaultPrevented()
{
return $this->_defaultPrevented;
}
public function getTarget()
public static function getEmptyInstance()
{
return $this->_target;
if ( ! self::$_emptyEventArgsInstance) {
self::$_emptyEventArgsInstance = new EventArgs;
}
return self::$_emptyEventArgsInstance;
}
}

View File

@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common;
@ -45,20 +45,20 @@ class EventManager
/**
* Dispatches an event to all registered listeners.
*
* @param string|Event $event The name of the event or the event object.
* @param string $eventName The name of the event to dispatch. The name of the event is
* the name of the method that is invoked on listeners.
* @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners.
* If not supplied, the single empty EventArgs instance is used.
* @return boolean
*/
public function dispatchEvent($event)
public function dispatchEvent($eventName, EventArgs $eventArgs = null)
{
$argIsCallback = is_string($event);
$callback = $argIsCallback ? $event : $event->getType();
if (isset($this->_listeners[$callback])) {
$event = $argIsCallback ? new Event($event) : $event;
foreach ($this->_listeners[$callback] as $listener) {
$listener->$callback($event);
if (isset($this->_listeners[$eventName])) {
$eventArgs = is_null($eventArgs) ? EventArgs::getEmptyInstance() : $eventArgs;
foreach ($this->_listeners[$eventName] as $listener) {
$listener->$eventName($eventArgs);
}
return ! $event->getDefaultPrevented();
return ! $eventArgs->getDefaultPrevented();
}
return true;
}
@ -95,7 +95,7 @@ class EventManager
{
// TODO: maybe check for duplicate registrations?
foreach ((array)$events as $event) {
$this->_listeners[$event] = $listener;
$this->_listeners[$event][] = $listener;
}
}
@ -110,4 +110,3 @@ class EventManager
$this->addEventListener($subscriber->getSubscribedEvents(), $subscriber);
}
}

View File

@ -154,9 +154,11 @@ class Connection
* Initializes a new instance of the Connection class.
*
* @param array $params The connection parameters.
* @param Driver $driver
* @param Configuration $config
* @param EventManager $eventManager
*/
public function __construct(array $params, Driver $driver,
Configuration $config = null,
public function __construct(array $params, Driver $driver, Configuration $config = null,
EventManager $eventManager = null)
{
$this->_driver = $driver;
@ -182,7 +184,7 @@ class Connection
/**
* Gets the Configuration used by the Connection.
*
* @return Configuration
* @return Doctrine\DBAL\Configuration
*/
public function getConfiguration()
{
@ -389,23 +391,23 @@ class Connection
}
/**
* fetchAll
* Convenience method for PDO::query("...") followed by $stmt->fetchAll(PDO::FETCH_ASSOC).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
* @param string $sql The SQL query.
* @param array $params The query parameters.
* @return array
*/
public function fetchAll($statement, array $params = array())
public function fetchAll($sql, array $params = array())
{
return $this->execute($statement, $params)->fetchAll(PDO::FETCH_ASSOC);
return $this->execute($sql, $params)->fetchAll(PDO::FETCH_ASSOC);
}
/**
* fetchOne
* Convenience method for PDO::query("...") followed by $stmt->fetchColumn().
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
* @param int $colnum 0-indexed column number to retrieve
* @param string $statement The SQL query.
* @param array $params The query parameters.
* @param int $colnum 0-indexed column number to retrieve
* @return mixed
*/
public function fetchOne($statement, array $params = array(), $colnum = 0)
@ -414,10 +416,10 @@ class Connection
}
/**
* fetchRow
* Convenience method for PDO::query("...") followed by $stmt->fetch(PDO::FETCH_ASSOC).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
* @param string $statement The SQL query.
* @param array $params The query parameters.
* @return array
*/
public function fetchRow($statement, array $params = array())
@ -426,7 +428,7 @@ class Connection
}
/**
* fetchArray
* Convenience method for PDO::query("...") followed by $stmt->fetch(PDO::FETCH_NUM).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
@ -438,7 +440,7 @@ class Connection
}
/**
* fetchColumn
* Convenience method for PDO::query("...") followed by $stmt->fetchAll(PDO::FETCH_COLUMN, ...).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
@ -451,19 +453,7 @@ class Connection
}
/**
* fetchAssoc
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
* @return array
*/
public function fetchAssoc($statement, array $params = array())
{
return $this->execute($statement, $params)->fetchAll(PDO::FETCH_ASSOC);
}
/**
* fetchBoth
* Convenience method for PDO::query("...") followed by $stmt->fetchAll(PDO::FETCH_BOTH).
*
* @param string $statement sql query to be executed
* @param array $params prepared statement params
@ -478,7 +468,7 @@ class Connection
* Prepares an SQL statement.
*
* @param string $statement
* @return Doctrine::DBAL::Statement
* @return PDOStatement
*/
public function prepare($statement)
{
@ -487,13 +477,13 @@ class Connection
}
/**
* 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 Statement object.
*
* @param string $query
* @param integer $limit
* @param integer $offset
* @return Doctrine_Connection_Statement
* @return Statement
*/
public function select($query, $limit = 0, $offset = 0)
{

View File

@ -17,23 +17,21 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
/**
* Doctrine_ORM_Query_Abstract
* Base class for Query and NativeQuery.
*
* @package Doctrine
* @subpackage Query
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.com
* @link www.doctrine-project.com
* @since 1.0
* @version $Revision: 1393 $
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo See {@link Doctrine_ORM_Query}
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractQuery
{
@ -101,7 +99,7 @@ abstract class AbstractQuery
/**
* @var integer $type Query type.
*
* @see Doctrine_ORM_Query::* constants
* @see Query::* constants
*/
protected $_type = self::SELECT;
@ -112,19 +110,19 @@ abstract class AbstractQuery
/**
* @var array $params Parameters of this query.
* @see Doctrine_ORM_Query::free that initializes this property
* @see Query::free that initializes this property
*/
protected $_params = array();
/**
* @var array $_enumParams Array containing the keys of the parameters that should be enumerated.
* @see Doctrine_ORM_Query::free that initializes this property
* @see Query::free that initializes this property
*/
protected $_enumParams = array();
/**
* @var array $_dqlParts An array containing all DQL query parts.
* @see Doctrine_ORM_Query::free that initializes this property
* @see Query::free that initializes this property
*/
protected $_dqlParts = array();

View File

@ -24,7 +24,6 @@ namespace Doctrine\ORM;
use Doctrine\Common\EventManager;
use Doctrine\Common\DoctrineException;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Exceptions\EntityManagerException;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataFactory;
@ -90,7 +89,7 @@ class EntityManager
private $_conn;
/**
* The metadata factory, used to retrieve the metadata of entity classes.
* The metadata factory, used to retrieve the ORM metadata of entity classes.
*
* @var Doctrine\ORM\Mapping\ClassMetadataFactory
*/
@ -330,7 +329,7 @@ class EntityManager
*/
public function flush()
{
$this->_errorIfNotActiveOrClosed();
$this->_errorIfClosed();
$this->_unitOfWork->commit();
}
@ -412,7 +411,7 @@ class EntityManager
*/
public function save($object)
{
$this->_errorIfNotActiveOrClosed();
$this->_errorIfClosed();
$this->_unitOfWork->save($object);
if ($this->_flushMode == self::FLUSHMODE_IMMEDIATE) {
$this->flush();
@ -426,7 +425,7 @@ class EntityManager
*/
public function delete($entity)
{
$this->_errorIfNotActiveOrClosed();
$this->_errorIfClosed();
$this->_unitOfWork->delete($entity);
if ($this->_flushMode == self::FLUSHMODE_IMMEDIATE) {
$this->flush();
@ -459,7 +458,7 @@ class EntityManager
}
/**
* Gets the repository for an Entity.
* Gets the repository for an entity class.
*
* @param string $entityName The name of the Entity.
* @return Doctrine\ORM\EntityRepository The repository.
@ -520,7 +519,7 @@ class EntityManager
*
* @throws EntityManagerException If the EntityManager is closed or not active.
*/
private function _errorIfNotActiveOrClosed()
private function _errorIfClosed()
{
if ($this->_closed) {
throw EntityManagerException::notActiveOrClosed($this->_name);

View File

@ -16,10 +16,10 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Exceptions;
namespace Doctrine\ORM;
/**
* Doctrine_EntityManager_Exception
@ -27,7 +27,7 @@ namespace Doctrine\ORM\Exceptions;
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @link www.doctrine-project.org
* @since 2.0
* @version $Revision$
*/

View File

@ -1,6 +1,6 @@
<?php
/*
* $Id: Exception.php 4776 2008-08-16 19:40:59Z romanb $
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@ -16,22 +16,27 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
#namespace Doctrine::ORM::Exceptions;
namespace Doctrine\ORM;
/**
* Doctrine_Exception
* Container for all ORM events.
*
* @package Doctrine
* @subpackage Exception
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 4776 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* This class cannot be instantiated.
*
* @author robo
* @since 2.0
*/
class Doctrine_ORM_Exceptions_ORMException extends Doctrine_Common_Exceptions_DoctrineException
{}
final class Events
{
private function __construct() {}
const preDelete = 'preDelete';
const postDelete = 'postDelete';
const preSave = 'preSave';
const postSave = 'postSave';
}

View File

@ -1,65 +0,0 @@
<?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>.
*/
#namespace Doctrine::ORM::Exceptions;
/**
* Doctrine_Entity_Exception
*
* @package Doctrine
* @subpackage Entity
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Roman Borschel <roman@code-factory.org>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_ORM_Exceptions_EntityException extends Doctrine_ORM_Exceptions_ORMException
{
public static function unknownField($field)
{
return new self("Undefined field: '$field'.");
}
public static function invalidValueForOneToManyReference()
{
return new self("Invalid value. The value of a reference in a OneToMany "
. "association must be a Collection.");
}
public static function invalidValueForOneToOneReference()
{
return new self("Invalid value. The value of a reference in a OneToOne "
. "association must be an Entity.");
}
public static function invalidValueForManyToManyReference()
{
return new self("Invalid value. The value of a reference in a ManyToMany "
. "association must be a Collection.");
}
public static function invalidField($field)
{
return new self("Invalid field: '$field'.");
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace Doctrine\ORM\Exceptions;
namespace Doctrine\ORM\Internal\Hydration;
class HydrationException extends \Doctrine\Common\DoctrineException
{

View File

@ -1,13 +1,33 @@
<?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.doctrine-project.org>.
*/
namespace Doctrine\ORM\Internal\Hydration;
use \PDO;
/**
* Description of ObjectHydrator
* The ObjectHydrator constructs an object graph out of an SQL result set.
*
* @author robo
* @since 2.0
*/
class ObjectHydrator extends AbstractHydrator
{
@ -64,8 +84,8 @@ class ObjectHydrator extends AbstractHydrator
// Take snapshots from all initialized collections
foreach ($this->_collections as $coll) {
$coll->_takeSnapshot();
$coll->_setHydrationFlag(false);
$coll->takeSnapshot();
$coll->setHydrationFlag(false);
}
// Clean up
@ -128,8 +148,8 @@ class ObjectHydrator extends AbstractHydrator
$relation = $classMetadata->getAssociationMapping($name);
$relatedClass = $this->_em->getClassMetadata($relation->getTargetEntityName());
$coll = $this->getCollection($relatedClass->getClassName());
$coll->_setOwner($entity, $relation);
$coll->_setHydrationFlag(true);
$coll->setOwner($entity, $relation);
$coll->setHydrationFlag(true);
$classMetadata->getReflectionProperty($name)->setValue($entity, $coll);
$this->_initializedRelations[$oid][$name] = true;
$this->_uow->setOriginalEntityProperty($oid, $name, $coll);

View File

@ -7,7 +7,6 @@
namespace Doctrine\ORM\Internal\Hydration;
use \PDO;
use Doctrine\ORM\Exceptions\HydrationException;
/**
* Description of SingleScalarHydrator

View File

@ -21,8 +21,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/**
* Base class for association mappings.
*

View File

@ -16,19 +16,17 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
use \ReflectionClass;
use Doctrine\Common\DoctrineException;
use Doctrine\ORM\Exceptions\MappingException;
/**
* A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and
* it's associations and how they're mapped to a relational database.
* It is the backbone of Doctrine's metadata mapping.
* A <tt>ClassMetadata</tt> instance holds all the ORM metadata of an entity and
* it's associations. It is the backbone of Doctrine's metadata mapping.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
@ -176,8 +174,8 @@ class ClassMetadata
* - <b>fieldName</b> (string)
* The name of the field in the Entity.
*
* - <b>type</b> (object Doctrine::DBAL::Types::* or custom type)
* The database type of the column. Can be one of Doctrine's portable types
* - <b>type</b> (object Doctrine\DBAL\Types\* or custom type)
* The type of the column. Can be one of Doctrine's portable types
* or a custom type.
*
* - <b>columnName</b> (string, optional)
@ -198,7 +196,7 @@ class ClassMetadata
* therefore cant be used as a generator name!
*
* - <b>nullable</b> (boolean, optional)
* Whether the column is nullable. Defaults to TRUE.
* Whether the column is nullable. Defaults to FALSE.
*
* - <b>columnDefinition</b> (string, optional, schema-only)
* The SQL fragment that is used when generating the DDL for the column.
@ -226,7 +224,7 @@ class ClassMetadata
protected $_fieldMappings = array();
/**
* An array of field names. used to look up field names from column names.
* An array of field names. Used to look up field names from column names.
* Keys are column names and values are field names.
* This is the reverse lookup map of $_columnNames.
*
@ -244,7 +242,7 @@ class ClassMetadata
protected $_columnNames = array();
/**
* Map that maps lowercased column names to field names.
* Map that maps lowercased column names (keys) to field names (values).
* Mainly used during hydration because Doctrine enforces PDO_CASE_LOWER
* for portability.
*
@ -254,7 +252,8 @@ class ClassMetadata
/**
* Whether to automatically OUTER JOIN subtypes when a basetype is queried.
* This does only apply to the JOINED inheritance mapping strategy.
*
* <b>This does only apply to the JOINED inheritance mapping strategy.</b>
*
* @var boolean
*/
@ -262,8 +261,9 @@ class ClassMetadata
/**
* A map that maps discriminator values to class names.
* This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
* where a discriminator column is used.
*
* <b>This does only apply to the JOINED and SINGLE_TABLE inheritance mapping strategies
* where a discriminator column is used.</b>
*
* @var array
* @see _discriminatorColumn
@ -299,14 +299,14 @@ class ClassMetadata
protected $_lifecycleListenerInstances = array();
/**
* The registered lifecycle callbacks for Entities of this class.
* The registered lifecycle callbacks for entities of this class.
*
* @var array
*/
protected $_lifecycleCallbacks = array();
/**
* The registered lifecycle listeners for Entities of this class.
* The registered lifecycle listeners for entities of this class.
*
* @var array
*/
@ -394,8 +394,10 @@ class ClassMetadata
}
/**
* Gets the ReflectionProperty for the single identifier field.
*
* @return <type>
* @return ReflectionProperty
* @throws DoctrineException If the class has a composite identifier.
*/
public function getSingleIdReflectionProperty()
{
@ -478,7 +480,7 @@ class ClassMetadata
{
$mapping = $this->getFieldMapping($fieldName);
if ($mapping !== false) {
return isset($mapping['notnull']) && $mapping['notnull'] == true;
return isset($mapping['nullable']) && $mapping['nullable'] == false;
}
return false;
}
@ -502,7 +504,7 @@ class ClassMetadata
* reference to another object.
*
* @param string $fieldName The field name.
* @return array The mapping.
* @return array The field mapping.
*/
public function getFieldMapping($fieldName)
{
@ -522,7 +524,7 @@ class ClassMetadata
public function getAssociationMapping($fieldName)
{
if ( ! isset($this->_associationMappings[$fieldName])) {
throw new Doctrine_Exception("Mapping not found: $fieldName");
throw MappingException::mappingNotFound($fieldName);
}
return $this->_associationMappings[$fieldName];
}
@ -536,7 +538,7 @@ class ClassMetadata
public function getInverseAssociationMapping($mappedByFieldName)
{
if ( ! isset($this->_inverseMappings[$mappedByFieldName])) {
throw new DoctrineException("Mapping not found: " . $mappedByFieldName);
throw MappingException::mappingNotFound($mappedByFieldName);
}
return $this->_inverseMappings[$mappedByFieldName];
}
@ -564,6 +566,7 @@ class ClassMetadata
/**
* Gets all association mappings of the class.
*
* Alias for getAssociationMappings().
*
* @return array
@ -590,9 +593,8 @@ class ClassMetadata
* Gets the field name for a completely lowercased column name.
* Mainly used during hydration.
*
* @param string $lcColumnName
* @return string
* @todo Better name.
* @param string $lcColumnName The all-lowercase column name.
* @return string The field name.
*/
public function getFieldNameForLowerColumnName($lcColumnName)
{
@ -612,7 +614,7 @@ class ClassMetadata
}
/**
* Validates & completes the field mapping.
* Validates & completes the given field mapping.
*
* @param array $mapping The field mapping to validated & complete.
* @return array The validated and completed field mapping.
@ -669,11 +671,6 @@ class ClassMetadata
$this->_reflectionProperties[$mapping['fieldName']] = $refProp;
}
private function _validateAndCompleteClassMapping(array &$mapping)
{
}
/**
* @todo Implementation of Optimistic Locking.
*/
@ -760,7 +757,6 @@ class ClassMetadata
* Gets all field mappings.
*
* @return array
* @deprecated
*/
public function getFieldMappings()
{
@ -792,7 +788,7 @@ class ClassMetadata
*/
public function getIdentifierColumnNames()
{
return $this->getColumnNames((array) $this->getIdentifier());
return $this->getColumnNames((array)$this->getIdentifierFieldNames());
}
/**
@ -920,18 +916,18 @@ class ClassMetadata
* Gets the type of a field.
*
* @param string $fieldName
* @return string
* @return Doctrine\DBAL\Types\Type
*/
public function getTypeOfField($fieldName)
{
return isset($this->_fieldMappings[$fieldName]) ?
$this->_fieldMappings[$fieldName]['type'] : false;
$this->_fieldMappings[$fieldName]['type'] : null;
}
/**
* getTypeOfColumn
* Gets the type of a column.
*
* @return mixed The column type or FALSE if the type cant be determined.
* @return Doctrine\DBAL\Types\Type
*/
public function getTypeOfColumn($columnName)
{
@ -985,8 +981,9 @@ class ClassMetadata
/**
* Sets the subclasses of the mapped class.
* All entity classes that participate in a hierarchy and have subclasses
* need to declare them this way.
*
* <b>All entity classes that participate in a hierarchy and have subclasses
* need to declare them this way.</b>
*
* @param array $subclasses The names of all subclasses.
*/
@ -1055,11 +1052,6 @@ class ClassMetadata
*/
public function setInheritanceType($type)
{
if ($parentClassNames = $this->getParentClasses()) {
throw new MappingException("All classes in an inheritance hierarchy"
. " must share the same inheritance mapping type and this type must be set"
. " in the root class of the hierarchy.");
}
if ( ! $this->_isInheritanceType($type)) {
throw MappingException::invalidInheritanceType($type);
}
@ -1067,31 +1059,7 @@ class ClassMetadata
}
/**
* exports this class to the database based on its mapping.
*
* @throws Doctrine_Connection_Exception If some error other than Doctrine::ERR_ALREADY_EXISTS
* occurred during the create table operation.
* @return boolean Whether or not the export operation was successful
* false if table already existed in the database.
* @todo Reimpl. & Placement.
*/
public function export()
{
}
/**
* Returns an array with all the information needed to create the main database table
* for the class.
*
* @return array
* @todo Reimpl. & placement.
*/
public function getExportableFormat($parseForeignKeys = true)
{
}
/**
* Checks whether a persistent field is inherited from a superclass.
* Checks whether a mapped field is inherited from a superclass.
*
* @return boolean TRUE if the field is inherited, FALSE otherwise.
*/
@ -1104,6 +1072,7 @@ class ClassMetadata
* Sets the name of the primary table the class is mapped to.
*
* @param string $tableName The table name.
* @deprecated
*/
public function setTableName($tableName)
{
@ -1208,6 +1177,13 @@ class ClassMetadata
$this->_fieldMappings[$mapping['fieldName']] = $mapping;
}
/**
* INTERNAL:
* Adds an association mapping without completing/validating it.
* This is mainly used to add inherited association mappings to derived classes.
*
* @param AssociationMapping $mapping
*/
public function addAssociationMapping(AssociationMapping $mapping)
{
$this->_storeAssociationMapping($mapping);
@ -1320,7 +1296,7 @@ class ClassMetadata
* class is queried in a class hierarchy that uses the JOINED inheritance mapping
* strategy.
*
* This options does only apply to the JOINED inheritance mapping strategy.
* <b>This options does only apply to the JOINED inheritance mapping strategy.</b>
*
* @param boolean $bool
* @see getJoinSubClasses()
@ -1415,7 +1391,7 @@ class ClassMetadata
}
/**
* Adds a lifecycle callback for Entities of this class.
* Adds a lifecycle callback for entities of this class.
*
* Note: If the same callback is registered more than once, the old one
* will be overridden.
@ -1444,16 +1420,6 @@ class ClassMetadata
$this->_discriminatorColumn = $columnDef;
}
/**
*
* @param <type> $fieldName
* @param <type> $mapping
*/
/*public function addFieldMapping($fieldName, array $mapping)
{
$this->_fieldMappings[$fieldName] = $mapping;
}*/
/**
* Gets the discriminator column definition.
*

View File

@ -22,7 +22,7 @@
namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Exceptions\MappingException;
use Doctrine\ORM\Mapping\MappingException;
/* Addendum annotation reflection extensions */
if ( ! class_exists('\Addendum', false)) {
@ -134,6 +134,7 @@ class AnnotationDriver
$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $property->getAnnotation('DoctrineManyToOne')) {
$mapping['joinColumns'] = $joinColumns;
$mapping['cascade'] = $manyToOneAnnot->cascade;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $property->getAnnotation('DoctrineManyToMany')) {
@ -150,6 +151,7 @@ class AnnotationDriver
$mapping['joinTable'] = $joinTable;
$mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$mapping['cascade'] = $manyToManyAnnot->cascade;
$metadata->mapManyToMany($mapping);
}

View File

@ -21,8 +21,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/**
* A many-to-many mapping describes the mapping between two collections of
* entities.

View File

@ -19,7 +19,7 @@
* <http://www.phpdoctrine.org>.
*/
namespace Doctrine\ORM\Exceptions;
namespace Doctrine\ORM\Mapping;
/**
* A MappingException indicates that something is wrong with the mapping setup.

View File

@ -21,8 +21,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/**
* Represents a one-to-many mapping.
*
@ -53,7 +51,7 @@ class OneToManyMapping extends AssociationMapping
//protected $_sourceKeysToTargetForeignKeys;
/** Whether to delete orphaned elements (removed from the collection) */
protected $_deleteOrphans = false;
private $_deleteOrphans = false;
/**
* Initializes a new OneToManyMapping.
@ -96,9 +94,8 @@ class OneToManyMapping extends AssociationMapping
}
/**
* Whether the association is one-to-many.
* {@inheritdoc}
*
* @return boolean TRUE if the association is one-to-many, FALSE otherwise.
* @override
*/
public function isOneToMany()

View File

@ -21,8 +21,6 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/**
* A one-to-one mapping describes a uni-directional mapping from one entity
* to another entity.

View File

@ -48,7 +48,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*
* @var string
*/
private $_entityBaseType;
private $_type;
/**
* A snapshot of the collection at the moment it was fetched from the database.
@ -99,7 +99,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
* Hydration flag.
*
* @var boolean
* @see _setHydrationFlag()
* @see setHydrationFlag()
*/
private $_hydrationFlag;
@ -119,12 +119,12 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
/**
* Creates a new persistent collection.
*/
public function __construct(EntityManager $em, $entityBaseType, array $data = array(), $keyField = null)
public function __construct(EntityManager $em, $type, array $data = array(), $keyField = null)
{
parent::__construct($data);
$this->_entityBaseType = $entityBaseType;
$this->_type = $type;
$this->_em = $em;
$this->_ownerClass = $em->getClassMetadata($entityBaseType);
$this->_ownerClass = $em->getClassMetadata($type);
if ($keyField !== null) {
if ( ! $this->_ownerClass->hasField($keyField)) {
throw new DoctrineException("Invalid field '$keyField' can't be used as key.");
@ -162,7 +162,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
* @param object $entity
* @param AssociationMapping $assoc
*/
public function _setOwner($entity, AssociationMapping $assoc)
public function setOwner($entity, AssociationMapping $assoc)
{
$this->_owner = $entity;
$this->_association = $assoc;
@ -289,7 +289,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*
* @param boolean $bool
*/
public function _setHydrationFlag($bool)
public function setHydrationFlag($bool)
{
$this->_hydrationFlag = $bool;
}
@ -301,9 +301,9 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
* when a fetched collection has three elements, then two of those
* are being removed the diff would contain one element.
*/
public function _takeSnapshot()
public function takeSnapshot()
{
$this->_snapshot = $this->_data;
$this->_snapshot = $this->_elements;
}
/**
@ -312,7 +312,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*
* @return array The last snapshot of the elements.
*/
public function _getSnapshot()
public function getSnapshot()
{
return $this->_snapshot;
}
@ -325,7 +325,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*/
public function getDeleteDiff()
{
return array_udiff($this->_snapshot, $this->_data, array($this, '_compareRecords'));
return array_udiff($this->_snapshot, $this->_elements, array($this, '_compareRecords'));
}
/**
@ -335,7 +335,7 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*/
public function getInsertDiff()
{
return array_udiff($this->_data, $this->_snapshot, array($this, '_compareRecords'));
return array_udiff($this->_elements, $this->_snapshot, array($this, '_compareRecords'));
}
/**

View File

@ -66,20 +66,36 @@ abstract class AbstractCollectionPersister
if ($coll->getMapping()->isInverseSide()) {
return; // ignore inverse side
}
$sql = $this->_getDeleteSql($coll);
$this->_conn->exec($sql, $this->_getDeleteSqlParameters($coll));
}
/**
* Gets the SQL statement for deleting the given collection.
*
* @param PersistentCollection $coll
*/
abstract protected function _getDeleteSql(PersistentCollection $coll);
/**
* Gets the SQL parameters for the corresponding SQL statement to delete
* the given collection.
*
* @param PersistentCollection $coll
*/
abstract protected function _getDeleteSqlParameters(PersistentCollection $coll);
/**
* Updates the given collection, synchronizing it's state with the database
* by inserting, updating and deleting individual elements.
*
* @param PersistentCollection $coll
*/
public function update(PersistentCollection $coll)
{
if ($coll->getMapping()->isInverseSide()) {
return; // ignore inverse side
}
$this->deleteRows($coll);
//$this->updateRows($coll);
$this->insertRows($coll);
@ -113,6 +129,13 @@ abstract class AbstractCollectionPersister
*/
abstract protected function _getDeleteRowSql(PersistentCollection $coll);
/**
* Gets the SQL parameters for the corresponding SQL statement to delete the given
* element from the given collection.
*
* @param PersistentCollection $coll
* @param mixed $element
*/
abstract protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element);
/**
@ -129,6 +152,13 @@ abstract class AbstractCollectionPersister
*/
abstract protected function _getInsertRowSql(PersistentCollection $coll);
/**
* Gets the SQL parameters for the corresponding SQL statement to insert the given
* element of the given collection into the database.
*
* @param PersistentCollection $coll
* @param mixed $element
*/
abstract protected function _getInsertRowSqlParameters(PersistentCollection $coll, $element);
}

View File

@ -21,6 +21,9 @@
namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\ClassMetadata;
/**
* Base class for all EntityPersisters.
*
@ -65,7 +68,7 @@ abstract class AbstractEntityPersister
* that uses the given EntityManager and persists instances of the class described
* by the given class metadata descriptor.
*/
public function __construct(\Doctrine\ORM\EntityManager $em, \Doctrine\ORM\Mapping\ClassMetadata $classMetadata)
public function __construct(EntityManager $em, ClassMetadata $classMetadata)
{
$this->_em = $em;
$this->_entityName = $classMetadata->getClassName();
@ -112,8 +115,10 @@ abstract class AbstractEntityPersister
*/
public function delete($entity)
{
$id = array_combine($this->_classMetadata->getIdentifierFieldNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity));
$id = array_combine(
$this->_classMetadata->getIdentifierFieldNames(),
$this->_em->getUnitOfWork()->getEntityIdentifier($entity)
);
$this->_conn->delete($this->_classMetadata->getTableName(), $id);
}
@ -132,7 +137,7 @@ abstract class AbstractEntityPersister
*
* @param string $fieldName
* @return string
* @todo Consider using 'inherited' => 'ClassName' to make the lookup simpler.
* @todo Move to ClassMetadata?
*/
public function getOwningClass($fieldName)
{
@ -180,11 +185,9 @@ abstract class AbstractEntityPersister
if ($this->_classMetadata->hasAssociation($field)) {
$assocMapping = $this->_classMetadata->getAssociationMapping($field);
if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) {
//echo "NOT TO-ONE OR INVERSE!";
continue;
}
foreach ($assocMapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) {
//TODO: throw exc if field not set
$otherClass = $this->_em->getClassMetadata($assocMapping->getTargetEntityName());
if (is_null($newVal)) {
$result[$sourceColumn] = null;
@ -192,7 +195,6 @@ abstract class AbstractEntityPersister
$result[$sourceColumn] = $otherClass->getReflectionProperty(
$otherClass->getFieldName($targetColumn))->getValue($newVal);
}
}
} else if (is_null($newVal)) {
$result[$columnName] = null;

View File

@ -65,9 +65,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
* @override
*/
protected function _getUpdateRowSql(PersistentCollection $coll)
{
}
{}
/**
* {@inheritdoc}
@ -96,7 +94,7 @@ class ManyToManyPersister extends AbstractCollectionPersister
$this->_uow->getEntityIdentifier($coll->getOwner()),
$this->_uow->getEntityIdentifier($element)
);
var_dump($params);
//var_dump($params);
return $params;
}

View File

@ -23,7 +23,6 @@
namespace Doctrine\ORM\Query;
use Doctrine\ORM\Query\AST;
use Doctrine\ORM\Exceptions\QueryException;
use Doctrine\ORM\Query\Exec;
/**

View File

@ -4,7 +4,7 @@
* and open the template in the editor.
*/
namespace Doctrine\ORM\Exceptions;
namespace Doctrine\ORM\Query;
/**
* Description of QueryException

View File

@ -120,41 +120,35 @@ class UnitOfWork
private $_scheduledForDirtyCheck = array();
/**
* A list of all new entities that need to be INSERTed.
* A list of all pending entity insertions.
*
* @var array
* @todo Index by class name.
* @todo Rename to _inserts?
*/
private $_newEntities = array();
private $_entityInsertions = array();
/**
* A list of all dirty entities that need to be UPDATEd.
* A list of all pending entity updates.
*
* @var array
* @todo Rename to _updates?
*/
private $_dirtyEntities = array();
private $_entityUpdates = array();
/**
* A list of all deleted entities.
* Removed entities are entities that are "scheduled for removal" but have
* not yet been removed from the database.
* A list of all pending entity deletions.
*
* @var array
* @todo Rename to _deletions?
*/
private $_deletedEntities = array();
private $_entityDeletions = array();
/**
* All collection deletions.
* All pending collection deletions.
*
* @var array
*/
private $_collectionDeletions = array();
/**
* All collection creations.
* All pending collection creations.
*
* @var array
*/
@ -226,9 +220,9 @@ class UnitOfWork
// Compute changes done since last commit
$this->computeChangeSets();
if (empty($this->_newEntities) &&
empty($this->_deletedEntities) &&
empty($this->_dirtyEntities) &&
if (empty($this->_entityInsertions) &&
empty($this->_entityDeletions) &&
empty($this->_entityUpdates) &&
empty($this->_collectionUpdates) &&
empty($this->_collectionDeletions)) {
return; // Nothing to do.
@ -267,13 +261,13 @@ class UnitOfWork
// Take new snapshots from visited collections
foreach ($this->_visitedCollections as $coll) {
$coll->_takeSnapshot();
$coll->takeSnapshot();
}
// Clear up
$this->_newEntities = array();
$this->_dirtyEntities = array();
$this->_deletedEntities = array();
$this->_entityInsertions = array();
$this->_entityUpdates = array();
$this->_entityDeletions = array();
$this->_entityChangeSets = array();
$this->_collectionUpdates = array();
$this->_collectionDeletions = array();
@ -341,15 +335,14 @@ class UnitOfWork
&& ! ($actualData[$name] instanceof PersistentCollection)) {
//TODO: If $actualData[$name] is Collection then unwrap the array
$assoc = $class->getAssociationMapping($name);
if ($assoc->isOwningSide()) {
// Inject PersistentCollection
$coll = new PersistentCollection($this->_em, $assoc->getTargetEntityName(),
$actualData[$name] ? $actualData[$name] : array());
$coll->_setOwner($entity, $assoc);
if ( ! $coll->isEmpty()) $coll->setDirty(true);
$class->getReflectionProperty($name)->setValue($entity, $coll);
$actualData[$name] = $coll;
}
echo PHP_EOL . "INJECTING PCOLL into $name" . PHP_EOL;
// Inject PersistentCollection
$coll = new PersistentCollection($this->_em, $assoc->getTargetEntityName(),
$actualData[$name] ? $actualData[$name] : array());
$coll->setOwner($entity, $assoc);
if ( ! $coll->isEmpty()) $coll->setDirty(true);
$class->getReflectionProperty($name)->setValue($entity, $coll);
$actualData[$name] = $coll;
}
}
@ -381,7 +374,7 @@ class UnitOfWork
$assoc = $class->getAssociationMapping($propName);
if ($assoc->isOneToOne() && $assoc->isOwningSide()) {
$entityIsDirty = true;
} else if (/*is_null($actualValue) && */$orgValue instanceof PersistentCollection) {
} else if ($orgValue instanceof PersistentCollection) {
// A PersistentCollection was de-referenced, so delete it.
if ( ! in_array($orgValue, $this->_collectionDeletions, true)) {
$this->_collectionDeletions[] = $orgValue;
@ -394,7 +387,7 @@ class UnitOfWork
}
if ($changeSet) {
if ($entityIsDirty) {
$this->_dirtyEntities[$oid] = $entity;
$this->_entityUpdates[$oid] = $entity;
}
$this->_entityChangeSets[$oid] = $changeSet;
$this->_originalEntityData[$oid] = $actualData;
@ -418,19 +411,28 @@ class UnitOfWork
/**
* Computes the changes of an association.
*
* @param <type> $assoc
* @param <type> $value
* @param AssociationMapping $assoc
* @param mixed $value The value of the association.
*/
private function _computeAssociationChanges($assoc, $value)
{
/*if ( ! $assoc->isCascadeSave()) {
return; // "Persistence by reachability" only if save cascade enabled
}*/
if ($value instanceof PersistentCollection && $value->isDirty()) {
if ($assoc->isOwningSide()) {
$this->_collectionUpdates[] = $value;
}
$this->_visitedCollections[] = $value;
}
if ( ! $assoc->isCascadeSave()) {
echo "NOT CASCADING INTO " . $assoc->getSourceFieldName() . PHP_EOL;
return; // "Persistence by reachability" only if save cascade specified
}
// Look through the entities, and in any of their associations, for transient
// enities, recursively. ("Persistence by reachability")
if ($assoc->isOneToOne()) {
$value = array($value);
}
$targetClass = $this->_em->getClassMetadata($assoc->getTargetEntityName());
foreach ($value as $entry) {
$state = $this->getEntityState($entry);
@ -450,28 +452,21 @@ class UnitOfWork
$this->addToIdentityMap($entry);
}
// NEW entities are INSERTed within the current unit of work.
// Collect the original data and changeset, recursing into associations.
$data = array();
$changeSet = array();
foreach ($targetClass->getReflectionProperties() as $name => $refProp) {
$data[$name] = $refProp->getValue($entry);
$changeSet[$name] = array(null, $data[$name]);
// --
/*if ($targetClass->isCollectionValuedAssociation($name) && ! ($data[$name] instanceof PersistentCollection)) {
// Inject PersistentCollection
//TODO: If $actualData[$name] is Collection then unwrap the array
$assoc = $targetClass->getAssociationMapping($name);
$coll = new PersistentCollection($this->_em, $assoc->getTargetEntityName(),
$data[$name] ? $data[$name] : array());
$coll->_setOwner($entry, $assoc);
if ( ! $coll->isEmpty()) $coll->setDirty(true);
$targetClass->getReflectionProperty($name)->setValue($entry, $coll);
$data[$name] = $coll;
}*/
//--
if ($targetClass->hasAssociation($name)) {
//echo "RECURSING INTO $name" . PHP_EOL;
//TODO: Prevent infinite recursion
$this->_computeAssociationChanges($targetClass->getAssociationMapping($name), $data[$name]);
}
}
$this->_newEntities[$oid] = $entry;
// NEW entities are INSERTed within the current unit of work.
$this->_entityInsertions[$oid] = $entry;
$this->_entityChangeSets[$oid] = $changeSet;
$this->_originalEntityData[$oid] = $data;
} else if ($state == self::STATE_DELETED) {
@ -480,13 +475,6 @@ class UnitOfWork
// MANAGED associated entities are already taken into account
// during changeset calculation anyway, since they are in the identity map.
}
if ($value instanceof PersistentCollection && $value->isDirty()) {
if ($assoc->isOwningSide()) {
$this->_collectionUpdates[] = $value;
}
$this->_visitedCollections[] = $value;
}
}
/**
@ -502,7 +490,7 @@ class UnitOfWork
// Same for update/delete.
$className = $class->getClassName();
$persister = $this->getEntityPersister($className);
foreach ($this->_newEntities as $entity) {
foreach ($this->_entityInsertions as $entity) {
if (get_class($entity) == $className) {
$returnVal = $persister->insert($entity);
if ( ! is_null($returnVal)) {
@ -528,7 +516,7 @@ class UnitOfWork
{
$className = $class->getClassName();
$persister = $this->getEntityPersister($className);
foreach ($this->_dirtyEntities as $entity) {
foreach ($this->_entityUpdates as $entity) {
if (get_class($entity) == $className) {
$persister->update($entity);
}
@ -544,7 +532,7 @@ class UnitOfWork
{
$className = $class->getClassName();
$persister = $this->getEntityPersister($className);
foreach ($this->_deletedEntities as $entity) {
foreach ($this->_entityDeletions as $entity) {
if (get_class($entity) == $className) {
$persister->delete($entity);
}
@ -560,9 +548,9 @@ class UnitOfWork
{
if (is_null($entityChangeSet)) {
$entityChangeSet = array_merge(
$this->_newEntities,
$this->_dirtyEntities,
$this->_deletedEntities);
$this->_entityInsertions,
$this->_entityUpdates,
$this->_entityDeletions);
}
// TODO: We can cache computed commit orders in the metadata cache!
@ -590,7 +578,7 @@ class UnitOfWork
if ($assocMapping->isOwningSide()) {
$targetClass = $this->_em->getClassMetadata($assocMapping->getTargetEntityName());
$targetClassName = $targetClass->getClassName();
// if the target class does not yet have a node, create it
// If the target class does not yet have a node, create it
if ( ! $this->_commitOrderCalculator->hasNodeWithKey($targetClassName)) {
$this->_commitOrderCalculator->addNodeWithItem(
$targetClassName, // index/key
@ -616,17 +604,17 @@ class UnitOfWork
{
$oid = spl_object_hash($entity);
if (isset($this->_dirtyEntities[$oid])) {
if (isset($this->_entityUpdates[$oid])) {
throw new DoctrineException("Dirty object can't be registered as new.");
}
if (isset($this->_deletedEntities[$oid])) {
if (isset($this->_entityDeletions[$oid])) {
throw new DoctrineException("Removed object can't be registered as new.");
}
if (isset($this->_newEntities[$oid])) {
if (isset($this->_entityInsertions[$oid])) {
throw new DoctrineException("Object already registered as new. Can't register twice.");
}
$this->_newEntities[$oid] = $entity;
$this->_entityInsertions[$oid] = $entity;
if (isset($this->_entityIdentifiers[$oid])) {
$this->addToIdentityMap($entity);
}
@ -641,7 +629,7 @@ class UnitOfWork
*/
public function isRegisteredNew($entity)
{
return isset($this->_newEntities[spl_object_hash($entity)]);
return isset($this->_entityInsertions[spl_object_hash($entity)]);
}
/**
@ -657,12 +645,12 @@ class UnitOfWork
throw new DoctrineException("Entity without identity "
. "can't be registered as dirty.");
}
if (isset($this->_deletedEntities[$oid])) {
if (isset($this->_entityDeletions[$oid])) {
throw new DoctrineException("Removed object can't be registered as dirty.");
}
if ( ! isset($this->_dirtyEntities[$oid]) && ! isset($this->_newEntities[$oid])) {
$this->_dirtyEntities[$oid] = $entity;
if ( ! isset($this->_entityUpdates[$oid]) && ! isset($this->_entityInsertions[$oid])) {
$this->_entityUpdates[$oid] = $entity;
}
}
@ -677,7 +665,7 @@ class UnitOfWork
*/
public function isRegisteredDirty($entity)
{
return isset($this->_dirtyEntities[spl_object_hash($entity)]);
return isset($this->_entityUpdates[spl_object_hash($entity)]);
}
/**
@ -695,16 +683,16 @@ class UnitOfWork
$this->removeFromIdentityMap($entity);
$className = get_class($entity);
if (isset($this->_newEntities[$oid])) {
unset($this->_newEntities[$oid]);
if (isset($this->_entityInsertions[$oid])) {
unset($this->_entityInsertions[$oid]);
return; // entity has not been persisted yet, so nothing more to do.
}
if (isset($this->_dirtyEntities[$oid])) {
unset($this->_dirtyEntities[$oid]);
if (isset($this->_entityUpdates[$oid])) {
unset($this->_entityUpdates[$oid]);
}
if ( ! isset($this->_deletedEntities[$oid])) {
$this->_deletedEntities[$oid] = $entity;
if ( ! isset($this->_entityDeletions[$oid])) {
$this->_entityDeletions[$oid] = $entity;
}
}
@ -718,7 +706,7 @@ class UnitOfWork
*/
public function isRegisteredRemoved($entity)
{
return isset($this->_deletedEntities[spl_object_hash($entity)]);
return isset($this->_entityDeletions[spl_object_hash($entity)]);
}
/**
@ -732,8 +720,8 @@ class UnitOfWork
{
$oid = spl_object_hash($entity);
$this->removeFromIdentityMap($entity);
unset($this->_newEntities[$oid], $this->_dirtyEntities[$oid],
$this->_deletedEntities[$oid], $this->_entityIdentifiers[$oid],
unset($this->_entityInsertions[$oid], $this->_entityUpdates[$oid],
$this->_entityDeletions[$oid], $this->_entityIdentifiers[$oid],
$this->_entityStates[$oid]);
}
@ -747,9 +735,9 @@ class UnitOfWork
public function isEntityRegistered($entity)
{
$oid = spl_object_hash($entity);
return isset($this->_newEntities[$oid]) ||
isset($this->_dirtyEntities[$oid]) ||
isset($this->_deletedEntities[$oid]);
return isset($this->_entityInsertions[$oid]) ||
isset($this->_entityUpdates[$oid]) ||
isset($this->_entityDeletions[$oid]);
}
/**
@ -774,9 +762,9 @@ class UnitOfWork
} else {
$numDetached = count($this->_identityMap);
$this->_identityMap = array();
$this->_newEntities = array();
$this->_dirtyEntities = array();
$this->_deletedEntities = array();
$this->_entityInsertions = array();
$this->_entityUpdates = array();
$this->_entityDeletions = array();
}
return $numDetached;
@ -817,7 +805,7 @@ class UnitOfWork
{
$oid = spl_object_hash($entity);
if ( ! isset($this->_entityStates[$oid])) {
if (isset($this->_entityIdentifiers[$oid]) && ! isset($this->_newEntities[$oid])) {
if (isset($this->_entityIdentifiers[$oid]) && ! isset($this->_entityInsertions[$oid])) {
$this->_entityStates[$oid] = self::STATE_DETACHED;
} else {
$this->_entityStates[$oid] = self::STATE_NEW;
@ -951,8 +939,8 @@ class UnitOfWork
foreach ($commitOrder as $class) {
$this->_executeInserts($class);
}
// remove them from _newEntities and _entityChangeSets
$this->_newEntities = array_diff_key($this->_newEntities, $insertNow);
// remove them from _entityInsertions and _entityChangeSets
$this->_entityInsertions = array_diff_key($this->_entityInsertions, $insertNow);
$this->_entityChangeSets = array_diff_key($this->_entityChangeSets, $insertNow);
}
}
@ -1007,7 +995,7 @@ class UnitOfWork
// entity becomes managed again
if ($this->isRegisteredRemoved($entity)) {
//TODO: better a method for this?
unset($this->_deletedEntities[$oid]);
unset($this->_entityDeletions[$oid]);
} else {
//FIXME: There's more to think of here...
$this->registerNew($entity);
@ -1385,7 +1373,3 @@ class UnitOfWork
return $this->_collectionPersisters[$type];
}
}

View File

@ -1,5 +1,27 @@
<?php
#namespace Doctrine\ORM;
/*
* $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.doctrine-project.org>.
*/
namespace Doctrine\ORM;
use Doctrine\ORM\Mapping\AssociationMapping;
/**
* Represents a virtual proxy that is used for lazy to-one associations.
@ -7,7 +29,7 @@
* @author robo
* @since 2.0
*/
class Doctrine_ORM_VirtualProxy
class VirtualProxy
{
private $_assoc;
private $_refProp;
@ -22,7 +44,7 @@ class Doctrine_ORM_VirtualProxy
* @param <type> $assoc
* @param <type> $refProp
*/
public function __construct($owner, Doctrine_ORM_Mapping_AssociationMapping $assoc, ReflectionProperty $refProp)
public function __construct($owner, AssociationMapping $assoc, \ReflectionProperty $refProp)
{
$this->_owner = $owner;
$this->_assoc = $assoc;

View File

@ -10,9 +10,6 @@ if (!defined('PHPUnit_MAIN_METHOD')) {
require_once __DIR__ . '/../TestInit.php';
// Suites
#require_once 'Common/Collections/AllTests.php';
class AllTests
{
public static function main()
@ -24,6 +21,8 @@ class AllTests
{
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Common Tests');
$suite->addTestSuite('Doctrine\Tests\Common\EventManagerTest');
$suite->addTest(Collections\AllTests::suite());
return $suite;

View File

@ -0,0 +1,72 @@
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\Tests\Common;
use Doctrine\Common\EventManager;
use Doctrine\Common\EventArgs;
/**
* Description of EventManagerTest
*
* @author robo
*/
class EventManagerTest extends \Doctrine\Tests\DoctrineTestCase
{
/* Some pseudo events */
const preFoo = 'preFoo';
const postFoo = 'postFoo';
private $_preFooInvoked = false;
private $_postFooInvoked = false;
private $_eventManager;
protected function setUp() {
$this->_eventManager = new EventManager;
$this->_preFooInvoked = false;
$this->_postFooInvoked = false;
}
public function testInitialState()
{
$this->assertEquals(array(), $this->_eventManager->getListeners());
$this->assertFalse($this->_eventManager->hasListeners(self::preFoo));
$this->assertFalse($this->_eventManager->hasListeners(self::postFoo));
}
public function testAddEventListener()
{
$this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this);
$this->assertTrue($this->_eventManager->hasListeners(self::preFoo));
$this->assertTrue($this->_eventManager->hasListeners(self::postFoo));
$this->assertEquals(1, count($this->_eventManager->getListeners(self::preFoo)));
$this->assertEquals(1, count($this->_eventManager->getListeners(self::postFoo)));
$this->assertEquals(2, count($this->_eventManager->getListeners()));
}
public function testDispatchEvent()
{
$this->_eventManager->addEventListener(array('preFoo', 'postFoo'), $this);
$this->_eventManager->dispatchEvent(self::preFoo);
$this->assertTrue($this->_preFooInvoked);
$this->assertFalse($this->_postFooInvoked);
}
/* Listener methods */
public function preFoo(EventArgs $e)
{
$this->_preFooInvoked = true;
}
public function postFoo(EventArgs $e)
{
$this->_postFooInvoked = true;
}
}

View File

@ -39,7 +39,7 @@ class CmsUser
*/
public $address;
/**
* @DoctrineManyToMany(targetEntity="CmsGroup")
* @DoctrineManyToMany(targetEntity="CmsGroup", cascade={"save"})
* @DoctrineJoinTable(name="cms_users_groups",
joinColumns={{"name"="user_id", "referencedColumnName"="id"}},
inverseJoinColumns={{"name"="group_id", "referencedColumnName"="id"}})

View File

@ -22,7 +22,7 @@ class EntityManagerTest extends \Doctrine\Tests\OrmTestCase
try {
$this->_em->setFlushMode('foobar');
$this->fail("Setting invalid flushmode did not trigger exception.");
} catch (\Doctrine\ORM\Exceptions\EntityManagerException $expected) {}
} catch (\Doctrine\ORM\EntityManagerException $expected) {}
$this->_em->setFlushMode($prev);
}
}

View File

@ -157,6 +157,8 @@ class BasicCRUDTest extends \Doctrine\Tests\OrmFunctionalTestCase {
public function testManyToManyCollectionClearing()
{
echo PHP_EOL . "MANY-MANY" . PHP_EOL;
$user = new CmsUser;
$user->name = 'Guilherme';
$user->username = 'gblanco';
@ -171,11 +173,17 @@ class BasicCRUDTest extends \Doctrine\Tests\OrmFunctionalTestCase {
$this->_em->save($user); // Saves the user, cause of post-insert ID
$this->_em->flush(); // Saves the groups, cause they're attached to a persistent entity ($user)
$this->_em->flush();
// Check that there are indeed 10 links in the association table
$count = $this->_em->getConnection()->execute("SELECT COUNT(*) FROM cms_users_groups",
array())->fetchColumn();
$this->assertEquals(10, $count);
//$user->groups->clear();
unset($user->groups);
echo PHP_EOL . "FINAL FLUSH" . PHP_EOL;
$this->_em->flush();
// Check that the links in the association table have been deleted

View File

@ -89,7 +89,7 @@ class SingleScalarHydratorTest extends HydrationTest
$result = $hydrator->hydrateall($stmt, $this->_createParserResult(
$queryComponents, $tableAliasMap));
$this->fail();
} catch (\Doctrine\ORM\Exceptions\HydrationException $ex) {}
} catch (\Doctrine\ORM\Internal\Hydration\HydrationException $ex) {}
}
}