1
0
mirror of synced 2024-12-12 22:36:02 +03:00

refactorings. made basic one-one, one-many joins work.

This commit is contained in:
romanb 2008-08-22 09:05:14 +00:00
parent efca79412d
commit 0f8e9e0ba9
52 changed files with 617 additions and 526 deletions

View File

@ -159,6 +159,7 @@ class Doctrine_Association implements Serializable
$this->_customAccessor = isset($mapping['accessor']) ? $mapping['accessor'] : null;
$this->_customMutator = isset($mapping['mutator']) ? $mapping['mutator'] : null;
$this->_isOptional = isset($mapping['isOptional']) ? (bool)$mapping['isOptional'] : true;
$this->_cascades = isset($mapping['cascade']) ? (array)$mapping['cascade'] : array();
return $mapping;
}

View File

@ -1,28 +1,94 @@
<?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::Mappings;
/**
* Represents a one-to-many mapping.
*
* NOTE: One-to-many mappings can currently not be uni-directional (one -> many).
* They must either be bidirectional (one <-> many) or unidirectional (many -> one).
* In other words, the many-side MUST be the owning side and the one-side MUST be
* the inverse side.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @todo Rename to OneToManyMapping
*/
class Doctrine_Association_OneToMany extends Doctrine_Association
{
/** The target foreign key columns that reference the sourceKeyColumns. */
protected $_targetForeignKeyColumns;
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_targetForeignKeyColumns;
/** The (typically primary) source key columns that are referenced by the targetForeignKeyColumns. */
protected $_sourceKeyColumns;
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_sourceKeyColumns;
/** This maps the target foreign key columns to the corresponding (primary) source key columns. */
protected $_targetForeignKeysToSourceKeys;
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_targetForeignKeysToSourceKeys;
/** This maps the (primary) source key columns to the corresponding target foreign key columns. */
protected $_sourceKeysToTargetForeignKeys;
/* NOTE: Currently not used because uni-directional one-many not supported atm. */
//protected $_sourceKeysToTargetForeignKeys;
/** Whether to delete orphaned elements (removed from the collection) */
protected $_deleteOrphans = false;
/**
* Constructor.
* Creates a new OneToManyMapping.
*
* @param array $mapping The mapping info.
*/
public function __construct(array $mapping)
{
parent::__construct($mapping);
// one side in one-many can currently never be owning side, we may support that later
$this->_isOwningSide = false;
}
/**
* Whether orphaned elements (removed from the collection) should be deleted.
*
* @return boolean TRUE if orphaned elements should be deleted, FALSE otherwise.
*/
public function shouldDeleteOrphans()
{
return $this->_deleteOrphans;
}
/**
* Whether the association is one-to-many.
*
* @return boolean TRUE if the association is one-to-many, FALSE otherwise.
* @override
*/
public function isOneToMany()
{
return true;
}
}
?>

View File

@ -83,9 +83,7 @@ class Doctrine_Cache_Apc extends Doctrine_Cache_Driver
*/
public function save($id, $data, $lifeTime = false)
{
$lifeTime = $this->getLifeTime($lifeTime);
return (bool) apc_store($id, array($data, time()), $lifeTime);
return (bool) apc_store($id, $data, $lifeTime);
}
/**

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Cache_Driver');
/**
* Doctrine_Cache_Memcache
*
@ -80,15 +80,7 @@ class Doctrine_Cache_Memcache extends Doctrine_Cache_Driver
*/
public function fetch($id, $testCacheValidity = true)
{
$tmp = $this->_memcache->get($id);
if (is_array($tmp)) {
return $tmp[0];
} else if (is_string($tmp)) {
return $tmp;
}
return false;
return $this->_memcache->get($id);
}
/**

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Cache_Driver');
/**
* Doctrine_Cache_Xcache
*

View File

@ -25,26 +25,65 @@
/**
* A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and
* it's associations and how they're mapped to the relational database.
* it's associations and how they're mapped to a relational database.
* It is the backbone of Doctrine's metadata mapping.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
* @todo Rename to ClassDescriptor?
* @todo Rename to ClassDescriptor.
*/
class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
{
/* The inheritance mapping types */
/**
* NONE means the class does not participate in an inheritance hierarchy
* and therefore does not need an inheritance mapping type.
*/
const INHERITANCE_TYPE_NONE = 'none';
/**
* JOINED means the class will be persisted according to the rules of
* <tt>Class Table Inheritance</tt>.
*/
const INHERITANCE_TYPE_JOINED = 'joined';
/**
* SINGLE_TABLE means the class will be persisted according to the rules of
* <tt>Single Table Inheritance</tt>.
*/
const INHERITANCE_TYPE_SINGLE_TABLE = 'singleTable';
/**
* TABLE_PER_CLASS means the class will be persisted according to the rules
* of <tt>Concrete Table Inheritance</tt>.
*/
const INHERITANCE_TYPE_TABLE_PER_CLASS = 'tablePerClass';
/* The Id generator types. TODO: belongs more in a DBAL class */
/* The Id generator types. */
/**
* AUTO means the generator type will depend on what the used platform prefers.
* Offers full portability.
*/
const GENERATOR_TYPE_AUTO = 'auto';
/**
* SEQUENCE means a separate sequence object will be used. Platforms that do
* not have native sequence support may emulate it. Full portability is currently
* not guaranteed.
*/
const GENERATOR_TYPE_SEQUENCE = 'sequence';
/**
* TABLE means a separate table is used for id generation.
* Offers full portability.
*/
const GENERATOR_TYPE_TABLE = 'table';
/**
* IDENTITY means an identity column is used for id generation. The database
* will fill in the id column on insertion. Platforms that do not support
* native identity columns may emulate them. Full portability is currently
* not guaranteed.
*/
const GENERATOR_TYPE_IDENTITY = 'identity';
/**
* NONE means the class does not have a generated id. That means the class
* must have a natural id.
*/
const GENERATOR_TYPE_NONE = 'none';
/* The Entity types */
@ -53,7 +92,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
const ENTITY_TYPE_REGULAR = 'regular';
/**
* A transient entity is ignored by Doctrine.
* A transient entity is ignored by Doctrine (so ... it's not an entity really).
*/
const ENTITY_TYPE_TRANSIENT = 'transient';
/**
@ -216,14 +255,6 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
*/
protected $_lcColumnToFieldNames = array();
/**
* Relation parser object. Manages the relations for the class.
*
* @var Doctrine_Relation_Parser $_parser
* @todo Remove.
*/
protected $_parser;
/**
* Inheritance options.
*/
@ -315,8 +346,6 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
$this->_entityName = $entityName;
$this->_rootEntityName = $entityName;
$this->_em = $em;
$this->_parser = new Doctrine_Relation_Parser($this);
}
/**
@ -503,6 +532,11 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
return $this->_fieldMappings[$fieldName];
}
public function addFieldMapping($fieldName, array $mapping)
{
$this->_fieldMappings[$fieldName] = $mapping;
}
/**
* Gets the mapping of an association.
*
@ -519,6 +553,11 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
return $this->_associationMappings[$fieldName];
}
public function addAssociationMapping($fieldName, Doctrine_Association $assoc)
{
$this->_associationMappings[$fieldName] = $assoc;
}
/**
* Gets all association mappings of the class.
*
@ -879,6 +918,21 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
return $this->_generatorType != self::GENERATOR_TYPE_NONE;
}
public function isInheritanceTypeJoined()
{
return $this->_inheritanceType == self::INHERITANCE_TYPE_JOINED;
}
public function isInheritanceTypeSingleTable()
{
return $this->_inheritanceType == self::INHERITANCE_TYPE_SINGLE_TABLE;
}
public function isInheritanceTypeTablePerClass()
{
return $this->_inheritanceType == self::INHERITANCE_TYPE_TABLE_PER_CLASS;
}
/**
* Checks whether the class uses an identity column for the Id generation.
*
@ -1008,6 +1062,29 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
{
return $this->_subClasses;
}
/**
* Gets the name of the class in the entity hierarchy that owns the field with
* the given name. The owning class is the one that defines the field.
*
* @param string $fieldName
* @return string
* @todo Consider using 'inherited' => 'ClassName' to make the lookup simpler.
*/
public function getOwningClass($fieldName)
{
if ($this->_inheritanceType == self::INHERITANCE_TYPE_NONE) {
return $this;
} else {
foreach ($this->_parentClasses as $parentClass) {
if ( ! $this->_em->getClassMetadata($parentClass)->isInheritedField($fieldName)) {
return $parentClass;
}
}
}
throw new Doctrine_ClassMetadata_Exception("Unable to find defining class of field '$fieldName'.");
}
/**
* Checks whether the class has any persistent subclasses.
@ -1408,9 +1485,9 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
}
/**
* Adds a one-to-one association mapping.
* Adds a one-to-one mapping.
*
* @todo Implementation.
* @param array $mapping The mapping.
*/
public function mapOneToOne(array $mapping)
{
@ -1425,7 +1502,9 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
}
/**
* @todo Implementation.
* Adds a one-to-many mapping.
*
* @param array $mapping The mapping.
*/
public function mapOneToMany(array $mapping)
{
@ -1440,11 +1519,14 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
}
/**
* @todo Implementation.
* Adds a many-to-one mapping.
*
* @param array $mapping The mapping.
*/
public function mapManyToOne(array $mapping)
{
// A many-to-one mapping is simply a one-one backreference
$this->mapOneToOne($mapping);
}
/**
@ -1585,6 +1667,8 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
/**
* Completes the identifier mapping of the class.
* NOTE: Should only be called by the ClassMetadataFactory!
*
* @return void
*/
public function completeIdentifierMapping()
{
@ -1603,7 +1687,7 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
/**
* @todo Implementation. Immutable entities can not be updated or deleted once
* they are created. This means the entity can only be modified as long as it's
* in transient state (TCLEAN, TDIRTY).
* new (STATE_NEW).
*/
public function isImmutable()
{
@ -1634,121 +1718,11 @@ class Doctrine_ClassMetadata implements Doctrine_Configurable, Serializable
}
}
/* The following stuff needs to be touched for the association mapping rewrite */
/**
* hasOne
* binds One-to-One aggregate relation
*
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Entity this object
* @deprecated
*/
public function hasOne()
{
$this->bind(func_get_args(), Doctrine_Relation::ONE_AGGREGATE);
return $this;
}
/**
* hasMany
* binds One-to-Many / Many-to-Many aggregate relation
*
* @param string $componentName the name of the related component
* @param string $options relation options
* @see Doctrine_Relation::_$definition
* @return Doctrine_Entity this object
* @deprecated
*/
public function hasMany()
{
$this->bind(func_get_args(), Doctrine_Relation::MANY_AGGREGATE);
return $this;
}
/**
* @deprecated
*/
public function bindRelation($args, $type)
{
return $this->bind($args, $type);
}
/**
* @todo Relation mapping rewrite.
* @deprecated
*/
public function bind($args, $type)
{
$options = array();
$options['type'] = $type;
if ( ! isset($args[1])) {
$args[1] = array();
}
if ( ! is_array($args[1])) {
try {
throw new Exception();
} catch (Exception $e) {
echo $e->getTraceAsString();
}
}
$options = array_merge($args[1], $options);
$this->_parser->bind($args[0], $options);
}
/**
* hasRelation
*
* @param string $alias the relation to check if exists
* @return boolean true if the relation exists otherwise false
* @deprecated
*/
public function hasRelation($alias)
{
return $this->_parser->hasRelation($alias);
}
public function hasAssociation($fieldName)
{
return isset($this->_associationMappings[$fieldName]);
}
/**
* getRelation
*
* @param string $alias relation alias
* @deprecated
*/
public function getRelation($alias, $recursive = true)
{
return $this->_parser->getRelation($alias, $recursive);
}
/**
* @deprecated
*/
public function getRelationParser()
{
return $this->_parser;
}
/**
* getRelations
* returns an array containing all relation objects
*
* @return array an array of Doctrine_Relation objects
* @deprecated
*/
public function getRelations()
{
return $this->_parser->getRelations();
}
/**
*
*/

View File

@ -31,7 +31,7 @@
* @version $Revision$
* @link www.phpdoctrine.org
* @since 2.0
* @todo Rename to ClassMetadataFactory.
* @todo Rename to ClassDescriptorFactory.
*/
class Doctrine_ClassMetadata_Factory
{
@ -114,6 +114,7 @@ class Doctrine_ClassMetadata_Factory
// load metadata of subclasses
// -> child1 -> child2 -> $name
// Move down the hierarchy of parent classes, starting from the topmost class
$parent = $class;
foreach ($parentClasses as $subclassName) {
$subClass = new Doctrine_ClassMetadata($subclassName, $this->_em);
@ -121,7 +122,7 @@ class Doctrine_ClassMetadata_Factory
$this->_addInheritedFields($subClass, $parent);
$this->_addInheritedRelations($subClass, $parent);
$this->_loadMetadata($subClass, $subclassName);
if ($parent->getInheritanceType() == Doctrine::INHERITANCE_TYPE_SINGLE_TABLE) {
if ($parent->isInheritanceTypeSingleTable()) {
$subClass->setTableName($parent->getTableName());
}
$classes[$subclassName] = $subClass;
@ -132,15 +133,17 @@ class Doctrine_ClassMetadata_Factory
/**
* Adds inherited fields to the subclass mapping.
*
* @param unknown_type $subClass
* @param unknown_type $parentClass
* @param Doctrine::ORM::Mapping::ClassMetadata $subClass
* @param Doctrine::ORM::Mapping::ClassMetadata $parentClass
* @return void
*/
protected function _addInheritedFields($subClass, $parentClass)
{
foreach ($parentClass->getFieldMappings() as $fieldName => $mapping) {
$fullName = "$name as " . $parentClass->getFieldName($name);
$mapping['inherited'] = true;
$subClass->mapField($mapping);
if ( ! isset($mapping['inherited'])) {
$mapping['inherited'] = $parentClass->getClassName();
}
$subClass->addFieldMapping($fieldName, $mapping);
}
}
@ -152,8 +155,8 @@ class Doctrine_ClassMetadata_Factory
*/
protected function _addInheritedRelations($subClass, $parentClass)
{
foreach ($parentClass->getRelationParser()->getRelationDefinitions() as $name => $definition) {
$subClass->getRelationParser()->addRelationDefinition($name, $definition);
foreach ($parentClass->getAssociationMappings() as $fieldName => $mapping) {
$subClass->addAssociationMapping($name, $mapping);
}
}

View File

@ -83,7 +83,7 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
*
* @var Doctrine::ORM::Mapping::AssociationMapping
*/
protected $_associationMapping;
protected $_association;
/**
* The name of the column that is used for collection key mapping.
@ -99,8 +99,6 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
*/
//protected static $null;
protected $_mapping;
/**
* The EntityManager.
*
@ -261,10 +259,10 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
*
* @return void
*/
public function setReference(Doctrine_Entity $entity, $relation)
public function setReference(Doctrine_Entity $entity, Doctrine_Association $relation)
{
$this->_owner = $entity;
//$this->relation = $relation;
$this->_association = $relation;
/*if ($relation instanceof Doctrine_Relation_ForeignKey ||
$relation instanceof Doctrine_Relation_LocalKey) {
@ -304,6 +302,12 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
$removed = $this->_data[$key];
unset($this->_data[$key]);
//TODO: Register collection as dirty with the UoW if necessary
//$this->_em->getUnitOfWork()->scheduleCollectionUpdate($this);
//TODO: delete entity if shouldDeleteOrphans
/*if ($this->_association->isOneToMany() && $this->_association->shouldDeleteOrphans()) {
$this->_em->delete($removed);
}*/
return $removed;
}
@ -323,7 +327,7 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
*
* @param string $name
* @since 1.0
* @return void
* @return mixed
*/
public function __unset($key)
{
@ -508,7 +512,7 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
throw new Doctrine_Record_Exception('Value variable in set is not an instance of Doctrine_Entity.');
}
// Neither Maps nor Lists allow duplicates, both are Sets
// TODO: Really prohibit duplicates?
if (in_array($value, $this->_data, true)) {
return false;
}
@ -956,7 +960,7 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
public function mapElements($lambda) {
$result = array();
foreach ($this->_data as $key => $entity) {
list($key, $value) = $lambda($key, $entity);
list($key, $value) = each($lambda($key, $entity));
$result[$key] = $value;
}
return $result;
@ -969,14 +973,20 @@ class Doctrine_Collection implements Countable, IteratorAggregate, Serializable,
*/
public function clear()
{
$this->_data = array();
//TODO: Register collection as dirty with the UoW if necessary
//TODO: If oneToMany() && shouldDeleteOrphan() delete entities
/*if ($this->_association->isOneToMany() && $this->_association->shouldDeleteOrphans()) {
foreach ($this->_data as $entity) {
$this->_em->delete($entity);
}
}*/
$this->_data = array();
}
private function _changed()
{
/*if ( ! $this->_em->getUnitOfWork()->isCollectionScheduledForUpdate($this)) {
$this->_em->getUnitOfWork()->scheduleCollectionUpdate($this);
}*/
}*/
}
}

View File

@ -932,7 +932,7 @@ abstract class Doctrine_Connection
*/
public function lastInsertId($table = null, $field = null)
{
return $this->sequence->lastInsertId($table, $field);
return $this->getSequenceManager()->lastInsertId($table, $field);
}
/**

View File

@ -160,6 +160,8 @@ class Doctrine_Connection_UnitOfWork
foreach ($commitOrder as $class) {
$this->_executeInserts($class);
}
foreach ($commitOrder as $class) {
$this->_executeUpdates($class);
}
@ -268,7 +270,7 @@ class Doctrine_Connection_UnitOfWork
}
// add dependency
$otherNode = $this->_commitOrderCalculator->getNodeForKey($targetClassName);
$node->before($otherNode);
$otherNode->before($node);
}
}
}

View File

@ -27,7 +27,8 @@
* @author Lukas Smith <smith@pooteeweet.org> (PEAR MDB2 library)
* @version $Revision$
* @link www.phpdoctrine.org
* @since 1.0
* @since 1.0
* @todo Remove.
*/
class Doctrine_DataDict_Informix extends Doctrine_DataDict
{

View File

@ -227,6 +227,26 @@ class Doctrine_DatabasePlatform_MySqlPlatform extends Doctrine_DatabasePlatform
return 'CONCAT(' . join(', ', (array) $args) . ')';
}
/**
* @TEST
*/
public function getVarcharDeclaration(array $field)
{
if ( ! isset($field['length'])) {
if (array_key_exists('default', $field)) {
$field['length'] = $this->getVarcharMaxLength();
} else {
$field['length'] = false;
}
}
$length = ($field['length'] <= $this->getVarcharMaxLength()) ? $field['length'] : false;
$fixed = (isset($field['fixed'])) ? $field['fixed'] : false;
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
: ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
}
/**
* Obtain DBMS specific SQL code portion needed to declare an text type
* field to be used in statements like CREATE TABLE.

View File

@ -143,6 +143,14 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
* @var integer
*/
private $_state;
/**
* Name => Value map of join columns.
*
* @var array
* @todo Not yet clear if needed.
*/
//private $_joinColumns = array();
/**
* The changes that happened to fields of the entity.
@ -189,14 +197,6 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*/
private $_oid;
/**
* Flag that indicates whether the entity is dirty.
* (which means it has local changes)
*
* @var boolean
*/
//private $_isDirty = false;
/**
* Constructor.
* Creates a new Entity instance.
@ -444,6 +444,7 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
$this->_internalSetReference($fieldName, $value);
$this->_referenceChangeSet[$fieldName] = array($old => $value);
$this->_registerDirty();
//TODO: Allow arrays in $value. Wrap them in a collection transparently.
if ($old instanceof Doctrine_Collection) {
$this->_em->getUnitOfWork()->scheduleCollectionDeletion($old);
}
@ -524,67 +525,6 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*
* @param string $fieldName
* @param mixed $value
* @todo Refactor.
*/
final public function _internalSetReference_OLD($name, $value)
{
if ($value === Doctrine_Null::$INSTANCE) {
$this->_references[$name] = $value;
return;
}
$rel = $this->_class->getRelation($name);
// one-to-many or one-to-one relation
if ($rel instanceof Doctrine_Relation_ForeignKey ||
$rel instanceof Doctrine_Relation_LocalKey) {
if ( ! $rel->isOneToOne()) {
// one-to-many relation
if ( ! $value instanceof Doctrine_Collection) {
throw Doctrine_Entity_Exception::invalidValueForOneToManyReference();
}
if (isset($this->_references[$name])) {
$this->_references[$name]->setData($value->getData());
return;
}
} else {
$relatedTable = $value->getTable();
$foreignFieldName = $rel->getForeignFieldName();
$localFieldName = $rel->getLocalFieldName();
// one-to-one relation found
if ( ! ($value instanceof Doctrine_Entity)) {
throw Doctrine_Entity_Exception::invalidValueForOneToOneReference();
}
if ($rel instanceof Doctrine_Relation_LocalKey) {
$idFieldNames = $value->getTable()->getIdentifier();
if ( ! empty($foreignFieldName) && $foreignFieldName != $idFieldNames[0]) {
$this->set($localFieldName, $value->_get($foreignFieldName));
} else {
$this->set($localFieldName, $value);
}
} else {
$value->set($foreignFieldName, $this);
}
}
} else if ($rel instanceof Doctrine_Relation_Association) {
if ( ! ($value instanceof Doctrine_Collection)) {
throw Doctrine_Entity_Exception::invalidValueForManyToManyReference();
}
}
$this->_references[$name] = $value;
}
/**
* INTERNAL:
* Sets a reference to another entity or a collection of entities.
*
* NOTE: Use of this method in userland code is strongly discouraged.
*
* @param string $fieldName
* @param mixed $value
* @todo Refactor.
*/
final public function _internalSetReference($name, $value)
{
@ -595,31 +535,14 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
$rel = $this->_class->getAssociationMapping($name);
// one-to-many or one-to-one relation
if ($rel->isOneToOne() || $rel->isOneToMany()) {
if ( ! $rel->isOneToOne()) {
// one-to-many relation
if ( ! $value instanceof Doctrine_Collection) {
throw Doctrine_Entity_Exception::invalidValueForOneToManyReference();
}
if (isset($this->_references[$name])) {
$this->_references[$name]->setData($value->getData());
return;
}
} else {
$relatedClass = $value->getClass();
//$foreignFieldName = $rel->getForeignFieldName();
//$localFieldName = $rel->getLocalFieldName();
// one-to-one relation found
if ( ! ($value instanceof Doctrine_Entity)) {
throw Doctrine_Entity_Exception::invalidValueForOneToOneReference();
}
}
} else if ($rel instanceof Doctrine_Relation_Association) {
if ( ! ($value instanceof Doctrine_Collection)) {
throw Doctrine_Entity_Exception::invalidValueForManyToManyReference();
}
if ($rel->isOneToOne() && ! $value instanceof Doctrine_Entity) {
throw Doctrine_Entity_Exception::invalidValueForOneToOneReference();
}
if ($rel->isOneToMany() && ! $value instanceof Doctrine_Collection) {
throw Doctrine_Entity_Exception::invalidValueForOneToManyReference();
}
if ($rel->isManyToMany() && ! $value instanceof Doctrine_Collection) {
throw Doctrine_Entity_Exception::invalidValueForManyToManyReference();
}
$this->_references[$name] = $value;
@ -734,7 +657,7 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
* @param string $name
* @return boolean
*/
final public function contains($fieldName)
private function _contains($fieldName)
{
if (isset($this->_data[$fieldName])) {
if ($this->_data[$fieldName] === Doctrine_Null::$INSTANCE) {
@ -755,28 +678,29 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
/**
* Clears the value of a field.
*
* Invoked by Doctrine::ORM::Access#__unset().
*
* @param string $name
* @return void
*/
final public function remove($fieldName)
private function _unset($fieldName)
{
if (isset($this->_data[$fieldName])) {
$this->_data[$fieldName] = array();
$this->_data[$fieldName] = null;
} else if (isset($this->_references[$fieldName])) {
if ($this->_references[$fieldName] instanceof Doctrine_Entity) {
// todo: delete related record when saving $this (ONLY WITH deleteOrphans!)
$this->_references[$fieldName] = Doctrine_Null::$INSTANCE;
} else if ($this->_references[$fieldName] instanceof Doctrine_Collection) {
$this->_references[$fieldName]->setData(array());
$assoc = $this->_class->getAssociationMapping($fieldName);
if ($assoc->isOneToOne() && $assoc->shouldDeleteOrphans()) {
$this->_em->delete($this->_references[$fieldName]);
} else if ($assoc->isOneToMany() && $assoc->shouldDeleteOrphans()) {
foreach ($this->_references[$fieldName] as $entity) {
$this->_em->delete($entity);
}
}
$this->_references[$fieldName] = null;
}
}
/**
* INTERNAL:
* Gets the changeset of the entities persistent state.
* Gets the changeset of the entities data.
*
* @return array
*/
@ -785,6 +709,12 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
return $this->_dataChangeSet;
}
/**
* INTERNAL:
* Gets the changeset of the entities references to other entities.
*
* @return array
*/
final public function _getReferenceChangeSet()
{
return $this->_referenceChangeSet;
@ -831,11 +761,28 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
$this->_data[$name] = $id;
}
$this->_dataChangeSet = array();
$this->_referenceChangeSet = array();
}
/**
* @todo Not yet clear if needed.
*/
/*final public function _setJoinColumn($columnName, $value)
{
$this->_joinColumns[$columnName] = $value;
}*/
/**
* @todo Not yet clear if needed.
*/
/*final public function _getJoinColumn($columnName)
{
return $this->_joinColumns[$columnName];
}*/
/**
* INTERNAL:
* Returns the primary keys of the entity (key => value pairs).
* Returns the primary keys of the entity (field => value pairs).
*
* @return array
*/
@ -844,32 +791,6 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
return $this->_id;
}
/**
* hasRefence
* @param string $name
* @return boolean
* @todo Better name? hasAssociation() ? Remove?
*/
final public function hasReference($name)
{
return isset($this->_references[$name]);
}
/**
* obtainReference
*
* @param string $name
* @throws Doctrine_Record_Exception if trying to get an unknown related component
* @todo Better name? Remove?
*/
final public function obtainReference($name)
{
if (isset($this->_references[$name])) {
return $this->_references[$name];
}
throw new Doctrine_Record_Exception("Unknown reference $name.");
}
/**
* INTERNAL:
*
@ -881,19 +802,6 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
return $this->_references;
}
/**
* INTERNAL:
* setRelated
*
* @param string $alias
* @param Doctrine_Access $coll
* @todo Name? Remove?
*/
final public function _setRelated($alias, Doctrine_Access $coll)
{
$this->_references[$alias] = $coll;
}
/**
* Gets the ClassMetadata object that describes the entity class.
*
@ -925,23 +833,6 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
return $this->_em->getRepository($this->_entityName);
}
/**
* @todo Why toString() and __toString() ?
*/
public function toString()
{
return Doctrine::dump(get_object_vars($this));
}
/**
* returns a string representation of this object
* @todo Why toString() and __toString() ?
*/
public function __toString()
{
return (string)$this->_oid;
}
/**
* Helps freeing the memory occupied by the entity.
* Cuts all references the entity has to other entities and removes the entity
@ -980,7 +871,7 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*/
public function offsetExists($offset)
{
return $this->contains($offset);
return $this->_contains($offset);
}
/**
@ -1020,7 +911,7 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*/
public function offsetUnset($offset)
{
return $this->remove($offset);
return $this->_unset($offset);
}
/**
@ -1058,7 +949,7 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*/
public function __isset($name)
{
return $this->contains($name);
return $this->_contains($name);
}
/**
@ -1070,6 +961,14 @@ abstract class Doctrine_Entity implements ArrayAccess, Serializable
*/
public function __unset($name)
{
return $this->remove($name);
return $this->_unset($name);
}
/**
* returns a string representation of this object
*/
public function __toString()
{
return (string)$this->_oid;
}
}

View File

@ -44,7 +44,7 @@ class Doctrine_EntityManager
* IMMEDIATE: Flush occurs automatically after each operation that issues database
* queries. No operations are queued.
*/
const FLUSHMODE_IMMEDIATE = 'immediated';
const FLUSHMODE_IMMEDIATE = 'immediate';
/**
* AUTO: Flush occurs automatically in the following situations:
* - Before any query executions (to prevent getting stale data)
@ -86,7 +86,7 @@ class Doctrine_EntityManager
/**
* The metadata factory, used to retrieve the metadata of entity classes.
*
* @var Doctrine_ClassMetadata_Factory
* @var Doctrine::ORM::Mapping::ClassMetadataFactory
*/
private $_metadataFactory;
@ -539,7 +539,8 @@ class Doctrine_EntityManager
}
} else {
foreach ($data as $field => $value) {
if ( ! $entity->contains($field) || $entity->_internalGetField($field) === null) {
$currentValue = $entity->get($field);
if ( ! isset($currentValue) || $entity->_internalGetField($field) === null) {
$entity->_internalSetField($field, $value);
}
}

View File

@ -72,7 +72,7 @@ abstract class Doctrine_EntityPersister_Abstract
private $_nullObject;
/**
* Constructs a new persister.
* Constructs a new EntityPersister.
*/
public function __construct(Doctrine_EntityManager $em, Doctrine_ClassMetadata $classMetadata)
{
@ -83,37 +83,78 @@ abstract class Doctrine_EntityPersister_Abstract
$this->_nullObject = Doctrine_Null::$INSTANCE;
}
/**
* Inserts an entity.
*
* @param Doctrine::ORM::Entity $entity The entity to insert.
* @return void
*/
public function insert(Doctrine_Entity $entity)
{
$insertData = array();
$dataChangeSet = $entity->_getDataChangeSet();
$class = $entity->getClass();
$referenceChangeSet = $entity->_getReferenceChangeSet();
foreach ($referenceChangeSet as $field => $change) {
list($old, $new) = each($change);
$assocMapping = $entity->getClass()->getAssociationMapping($field);
if ($assocMapping->isOneToOne()) {
if ($assocMapping->isInverseSide()) {
//echo "INVERSE!";
continue; // ignore inverse side
}
foreach ($assocMapping->getSourceToTargetKeyColumns() as $localColumn => $foreignColumn) {
//echo "$localColumn -- $foreignColumn<br/>";
//$insertData[$localColumn] = 1; //FIX
}
// ... set the foreign key column to the id of the related entity ($new)
$assocMapping = $class->getAssociationMapping($field);
if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) {
//echo "NOT TO-ONE OR INVERSE!";
continue;
}
foreach ($assocMapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) {
//TODO: What if both join columns (local/foreign) are just db-only
// columns (no fields in models) ? Currently we assume the foreign column
// is mapped to a field in the foreign entity.
$insertData[$sourceColumn] = $new->_internalGetField(
$new->getClass()->getFieldName($targetColumn)
);
}
//...
}
foreach ($dataChangeSet as $field => $change) {
$insertData[$entity->getClass()->getColumnName($field)] = current($change);
}
$this->_prepareData($entity, $insertData, true);
//TODO: perform insert
$this->_conn->insert($entity->getClass()->getTableName(), $insertData);
$this->_conn->insert($class->getTableName(), $insertData);
//TODO: if IDENTITY pk, assign it
if ($class->isIdGeneratorIdentity()) {
//TODO: Postgres IDENTITY columns (SERIAL) use a sequence, so we need to pass the
// sequence name to lastInsertId().
$entity->_assignIdentifier($this->_conn->lastInsertId());
}
}
/*protected function _fillJoinColumns($entity, array &$data)
{
$referenceChangeSet = $entity->_getReferenceChangeSet();
foreach ($referenceChangeSet as $field => $change) {
list($old, $new) = each($change);
$assocMapping = $entity->getClass()->getAssociationMapping($field);
if ( ! $assocMapping->isOneToOne() || $assocMapping->isInverseSide()) {
//echo "NOT TO-ONE OR INVERSE!";
continue;
}
foreach ($assocMapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) {
//TODO: What if both join columns (local/foreign) are just db-only
// columns (no fields in models) ? Currently we assume the foreign column
// is mapped to a field in the foreign entity.
$insertData[$sourceColumn] = $new->_internalGetField(
$new->getClass()->getFieldName($targetColumn)
);
}
}
}*/
/**
* Updates an entity.
*
* @param Doctrine::ORM::Entity $entity The entity to update.
* @return void
*/
public function update(Doctrine_Entity $entity)
{
$dataChangeSet = $entity->_getDataChangeSet();
@ -134,6 +175,12 @@ abstract class Doctrine_EntityPersister_Abstract
//TODO: perform update
}
/**
* Deletes an entity.
*
* @param Doctrine::ORM::Entity $entity The entity to delete.
* @return void
*/
public function delete(Doctrine_Entity $entity)
{
//TODO: perform delete
@ -177,6 +224,9 @@ abstract class Doctrine_EntityPersister_Abstract
return $this->_classMetadata;
}
/**
* @todo Move to ClassMetadata?
*/
public function getFieldNames()
{
if ($this->_fieldNames) {
@ -186,6 +236,9 @@ abstract class Doctrine_EntityPersister_Abstract
return $this->_fieldNames;
}
/**
* @todo Move to ClassMetadata?
*/
public function getOwningClass($fieldName)
{
return $this->_classMetadata;
@ -193,6 +246,7 @@ abstract class Doctrine_EntityPersister_Abstract
/**
* Callback that is invoked during the SQL construction process.
* @todo Move to ClassMetadata?
*/
public function getCustomJoins()
{
@ -201,6 +255,7 @@ abstract class Doctrine_EntityPersister_Abstract
/**
* Callback that is invoked during the SQL construction process.
* @todo Move to ClassMetadata?
*/
public function getCustomFields()
{
@ -213,7 +268,7 @@ abstract class Doctrine_EntityPersister_Abstract
*
* @return array
*/
protected function _convertFieldToColumnNames(array $fields, Doctrine_ClassMetadata $class)
/*protected function _convertFieldToColumnNames(array $fields, Doctrine_ClassMetadata $class)
{
$converted = array();
foreach ($fields as $fieldName => $value) {
@ -221,65 +276,52 @@ abstract class Doctrine_EntityPersister_Abstract
}
return $converted;
}
}*/
/**
* Returns an array of modified fields and values with data preparation
* adds column aggregation inheritance and converts Records into primary key values
*
* @param array $array
* @return array
* @return void
* @todo Move to EntityPersister. There call _getChangeSet() and apply this logic.
*/
public function prepareData(array $data = array())
protected function _prepareData($entity, array &$result, $isInsert = false)
{
$dataSet = array();
foreach ($entity->_getDataChangeSet() as $field => $change) {
list ($oldVal, $newVal) = each($change);
$type = $entity->getClass()->getTypeOfField($field);
$columnName = $entity->getClass()->getColumnName($field);
$modifiedFields = $fields;
foreach ($data as $field => $value) {
$type = $this->_classMetadata->getTypeOfField($field);
if ($value === Doctrine_Null::$INSTANCE) {
$dataSet[$field] = null;
if ($newVal === Doctrine_Null::$INSTANCE) {
$result[$columnName] = null;
continue;
}
switch ($type) {
case 'array':
case 'object':
$dataSet[$field] = serialize($value);
$result[$columnName] = serialize($newVal);
break;
case 'gzip':
$dataSet[$field] = gzcompress($value, 5);
$result[$columnName] = gzcompress($newVal, 5);
break;
case 'boolean':
$dataSet[$field] = $this->_em->getConnection()
->convertBooleans($value);
$result[$columnName] = $this->_em->getConnection()->convertBooleans($newVal);
break;
case 'enum':
$dataSet[$field] = $this->_class->enumIndex($field, $value);
break;
default:
$dataSet[$field] = $value;
$result[$columnName] = $newVal;
}
}
// @todo cleanup
// populates the discriminator field in Single & Class Table Inheritance
if ($this->_classMetadata->getInheritanceType() == Doctrine_ClassMetadata::INHERITANCE_TYPE_JOINED ||
$this->_class->getInheritanceType() == Doctrine_ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE) {
$discCol = $this->_classMetadata->getInheritanceOption('discriminatorColumn');
$discMap = $this->_classMetadata->getInheritanceOption('discriminatorMap');
$old = $this->get($discCol, false);
$discValue = array_search($this->_entityName, $discMap);
if ((string) $old !== (string) $discValue || $old === null) {
$dataSet[$discCol] = $discValue;
//$this->_data[$discCol] = $discValue;
}
// @todo Cleanup
// populates the discriminator column on insert in Single & Class Table Inheritance
if ($isInsert && ($entity->getClass()->isInheritanceTypeJoined() ||
$entity->getClass()->isInheritanceTypeSingleTable())) {
$discColumn = $entity->getClass()->getInheritanceOption('discriminatorColumn');
$discMap = $entity->getClass()->getInheritanceOption('discriminatorMap');
$result[$discColumn] = array_search($this->_entityName, $discMap);
}
return $dataSet;
}

View File

@ -30,58 +30,53 @@
* @since 2.0
*/
class Doctrine_EntityPersister_JoinedSubclass extends Doctrine_EntityPersister_Abstract
{
//protected $_columnNameFieldNameMap = array();
{
/**
* Inserts an entity that is part of a Class Table Inheritance hierarchy.
*
* @param Doctrine_Entity $record record to be inserted
* @return boolean
* @override
*/
protected function _doInsert(Doctrine_Entity $record)
public function insert(Doctrine_Entity $entity)
{
$class = $this->_classMetadata;
$conn = $this->_conn;
$dataSet = $this->_groupFieldsByDefiningClass($record);
$class = $entity->getClass();
$dataSet = array();
$this->_prepareData($entity, $dataSet, true);
$dataSet = $this->_groupFieldsByDefiningClass($class, $dataSet);
$component = $class->getClassName();
$classes = $class->getParentClasses();
array_unshift($classes, $component);
try {
$conn->beginInternalTransaction();
$identifier = null;
foreach (array_reverse($classes) as $k => $parent) {
$parentClass = $conn->getClassMetadata($parent);
if ($k == 0) {
$identifierType = $parentClass->getIdentifierType();
if ($identifierType == Doctrine::IDENTIFIER_AUTOINC) {
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
$identifier = $conn->sequence->lastInsertId();
} else if ($identifierType == Doctrine::IDENTIFIER_SEQUENCE) {
$seq = $record->getClassMetadata()->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $conn->sequence->nextId($seq);
$identifierFields = (array)$parentClass->getIdentifier();
$dataSet[$parent][$identifierFields[0]] = $id;
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
} else {
throw new Doctrine_Mapper_Exception("Unsupported identifier type '$identifierType'.");
}
$record->assignIdentifier($identifier);
} else {
foreach ((array) $record->identifier() as $id => $value) {
$dataSet[$parent][$parentClass->getColumnName($id)] = $value;
}
$identifier = null;
foreach (array_reverse($classes) as $k => $parent) {
$parentClass = $this->_em->getClassMetadata($parent);
if ($k == 0) {
if ($parentClass->isIdGeneratorIdentity()) {
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
$identifier = $this->_conn->lastInsertId();
} else if ($parentClass->isIdGeneratorSequence()) {
$seq = $entity->getClassMetadata()->getTableOption('sequenceName');
if ( ! empty($seq)) {
$id = $this->_conn->getSequenceManager()->nextId($seq);
$identifierFields = $parentClass->getIdentifier();
$dataSet[$parent][$identifierFields[0]] = $id;
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
} else {
throw new Doctrine_Mapper_Exception("Unsupported identifier type '$identifierType'.");
}
$entity->_assignIdentifier($identifier);
} else {
foreach ($entity->_identifier() as $id => $value) {
$dataSet[$parent][$parentClass->getColumnName($id)] = $value;
}
$this->_insertRow($parentClass->getTableName(), $dataSet[$parent]);
}
$conn->commit();
} catch (Exception $e) {
$conn->rollback();
throw $e;
}
return true;
@ -255,29 +250,26 @@ class Doctrine_EntityPersister_JoinedSubclass extends Doctrine_EntityPersister_A
*
* @return array
*/
protected function _groupFieldsByDefiningClass(Doctrine_Entity $record)
protected function _groupFieldsByDefiningClass(Doctrine_ClassMetadata $class, array $fields)
{
$conn = $this->_conn;
$classMetadata = $this->_classMetadata;
$dataSet = array();
$component = $classMetadata->getClassName();
$array = $record->getPrepared();
$component = $class->getClassName();
$classes = array_merge(array($component), $classMetadata->getParentClasses());
$classes = array_merge(array($component), $class->getParentClasses());
foreach ($classes as $class) {
$dataSet[$class] = array();
$parentClassMetadata = $conn->getClassMetadata($class);
foreach ($parentClassMetadata->getColumns() as $columnName => $definition) {
if ((isset($definition['primary']) && $definition['primary'] === true) ||
(isset($definition['inherited']) && $definition['inherited'] === true)) {
$parentClassMetadata = $this->_em->getClassMetadata($class);
foreach ($parentClassMetadata->getFieldMappings() as $fieldName => $mapping) {
if ((isset($mapping['id']) && $mapping['id'] === true) ||
(isset($mapping['inherited']) && $mapping['inherited'] === true)) {
continue;
}
$fieldName = $classMetadata->getFieldName($columnName);
if ( ! array_key_exists($fieldName, $array)) {
if ( ! array_key_exists($fieldName, $fields)) {
continue;
}
$dataSet[$class][$columnName] = $array[$fieldName];
$columnName = $parentClassMetadata->getColumnName($fieldName);
$dataSet[$class][$columnName] = $fields[$fieldName];
}
}

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Hook_Parser');
/**
* Doctrine_Hook_Equal
*
@ -28,7 +28,9 @@ Doctrine::autoload('Doctrine_Hook_Parser');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Can be removed?
* @deprecated
*/
class Doctrine_Hook_Equal extends Doctrine_Hook_Parser
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Hook_Parser_Complex');
/**
* Doctrine_Hook_Integer
*
@ -28,7 +28,9 @@ Doctrine::autoload('Doctrine_Hook_Parser_Complex');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Can be removed?
* @deprecated
*/
class Doctrine_Hook_Integer extends Doctrine_Hook_Parser_Complex
{

View File

@ -28,7 +28,9 @@
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Can be removed?
* @deprecated
*/
abstract class Doctrine_Hook_Parser
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Hook_Parser');
/**
* Doctrine_Hook_Parser_Complex
*
@ -28,7 +28,9 @@ Doctrine::autoload('Doctrine_Hook_Parser');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Can be removed?
* @deprecated
*/
abstract class Doctrine_Hook_Parser_Complex extends Doctrine_Hook_Parser
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Hook_Parser');
/**
* Doctrine_Hook_WordLike
*
@ -28,7 +28,9 @@ Doctrine::autoload('Doctrine_Hook_Parser');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated
* @todo Can be removed?
*/
class Doctrine_Hook_WordLike extends Doctrine_Hook_Parser_Complex
{

View File

@ -88,33 +88,51 @@ class Doctrine_Query_Production_Join extends Doctrine_Query_Production
return $sql . ' ON ' . $conditionExpression;
}
// We need to build the relationship conditions. Retrieving AssociationMapping
$queryComponent = $this->_rangeVariableDeclaration->getQueryComponent();
$relationColumns = $queryComponent['relation']->getSourceToTargetKeyColumns();
$relationConditionExpression = '';
// We need to build the join conditions. Retrieving AssociationMapping
$queryComponent = $this->_rangeVariableDeclaration->getQueryComponent();
$association = $queryComponent['relation'];
$joinColumns = array();
if ($association->isOneToMany() || $association->isOneToOne()) {
if ($association->isInverseSide()) {
// joinColumns are found on the other (owning) side
$targetClass = $this->_em->getClassMetadata($association->getTargetEntityName());
$joinColumns = $targetClass->getAssociationMapping($association->getMappedByFieldName())
->getTargetToSourceKeyColumns();
} else {
$joinColumns = $association->getSourceToTargetKeyColumns();
}
} else {
//TODO: many-many
}
$relationConditionExpression = '';
// We have an array('localColumn' => 'foreignColumn', ...) here
foreach ($relationColumns as $localColumn => $foreignColumn) {
// leftExpression = rightExpression
// We have an array('localColumn' => 'foreignColumn', ...) here
foreach ($joinColumns as $localColumn => $foreignColumn) {
// leftExpression = rightExpression
// Defining leftExpression
$leftExpression = $conn->quoteIdentifier(
$parserResult->getTableAliasFromComponentAlias($queryComponent['parent']) . '.' . $localColumn
);
// Defining leftExpression
$leftExpression = $conn->quoteIdentifier(
$parserResult->getTableAliasFromComponentAlias($queryComponent['parent']) . '.' . $localColumn
);
// Defining rightExpression
$rightExpression = $conn->quoteIdentifier(
$parserResult->getTableAliasFromComponentAlias(
$this->_rangeVariableDeclaration->getIdentificationVariable()
) . '.' . $foreignColumn
);
// Defining rightExpression
$rightExpression = $conn->quoteIdentifier(
$parserResult->getTableAliasFromComponentAlias(
$this->_rangeVariableDeclaration->getIdentificationVariable()
) . '.' . $foreignColumn
);
// Building the relation
$relationConditionExpression .= (($relationConditionExpression != '') ? ' AND ' : '')
. $leftExpression . ' = ' . $rightExpression;
}
// Building the relation
$relationConditionExpression .= (($relationConditionExpression != '') ? ' AND ' : '')
. $leftExpression . ' = ' . $rightExpression;
}
$sql .= ' ON ' . $relationConditionExpression;
$sql .= empty($conditionExpression) ? '' : ' AND (' . $conditionExpression . ')';
return $sql . ' ON ' . $relationConditionExpression . ' AND (' . $conditionExpression . ')';
return $sql;
}

View File

@ -52,7 +52,7 @@ class Doctrine_Query_Production_JoinVariableDeclaration extends Doctrine_Query_P
public function buildSql()
{
return $this->_join->buildSql() . ' ' . (isset($this->_indexby) ? $this->_indexby->buildSql() . ' ' : '');
return $this->_join->buildSql() . (isset($this->_indexby) ? $this->_indexby->buildSql() . ' ' : '');
}

View File

@ -18,7 +18,9 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Exception');
#namespace Doctrine::ORM::Exceptions;
/**
* Doctrine_RawSql_Exception
*
@ -28,7 +30,8 @@ Doctrine::autoload('Doctrine_Exception');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Rename to NativeSqlException or maybe remove.
*/
class Doctrine_RawSql_Exception extends Doctrine_Exception
{ }

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Exception');
/**
* Doctrine_Exception
*
@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Exception');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated Remove.
*/
class Doctrine_Record_Exception extends Doctrine_Exception
{ }

View File

@ -29,7 +29,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 1298 $
* @version $Revision: 1298 $
* @deprecated Remove.
*/
abstract class Doctrine_Record_Filter
{

View File

@ -28,7 +28,9 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 1298 $
* @version $Revision: 1298 $
* @todo Remove.
* @deprecated
*/
class Doctrine_Record_Filter_Compound extends Doctrine_Record_Filter
{

View File

@ -29,7 +29,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 1298 $
* @version $Revision: 1298 $
* @deprecated Remove.
*/
class Doctrine_Record_Filter_Standard extends Doctrine_Record_Filter
{

View File

@ -28,7 +28,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @version $Revision$
* @link www.phpdoctrine.org
* @since 1.0
* @since 1.0
* @todo Rename. Move. Reimpl?
*/
abstract class Doctrine_Record_Generator
{

View File

@ -28,7 +28,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated Remove.
*/
class Doctrine_Record_Iterator extends ArrayIterator
{

View File

@ -28,7 +28,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated Remove.
*/
class Doctrine_Record_Listener implements Doctrine_Record_Listener_Interface
{

View File

@ -18,7 +18,6 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Access');
/**
* Doctrine_Record_Listener_Chain
@ -31,7 +30,9 @@ Doctrine::autoload('Doctrine_Access');
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated
* @todo Remove
*/
class Doctrine_Record_Listener_Chain extends Doctrine_Access implements Doctrine_Record_Listener_Interface
{

View File

@ -28,7 +28,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated Remove.
*/
interface Doctrine_Record_Listener_Interface
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Record_Exception');
/**
* Doctrine_Exception
*
@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Record_Exception');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @todo Deprecated. Remove
*/
class Doctrine_Record_State_Exception extends Doctrine_Record_Exception
{ }

View File

@ -29,7 +29,8 @@
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated
*/
abstract class Doctrine_Relation implements ArrayAccess
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Relation');
/**
* Doctrine_Relation_Association
*
@ -30,7 +30,8 @@ Doctrine::autoload('Doctrine_Relation');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated
*/
class Doctrine_Relation_Association extends Doctrine_Relation
{

View File

@ -28,7 +28,8 @@
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated
*/
class Doctrine_Relation_Association_Self extends Doctrine_Relation_Association
{

View File

@ -29,7 +29,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated
*/
class Doctrine_Relation_ForeignKey extends Doctrine_Relation
{

View File

@ -29,7 +29,8 @@
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @version $Revision$
* @deprecated
*/
class Doctrine_Relation_LocalKey extends Doctrine_Relation
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Relation_Association');
/**
* Doctrine_Relation_Association_Self
*
@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Relation_Association');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision: 1434 $
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated
*/
class Doctrine_Relation_Nest extends Doctrine_Relation_Association
{

View File

@ -30,7 +30,8 @@
* @link www.phpdoctrine.org
* @since 1.0
* @todo Composite key support?
* @todo Remove. Association mapping needs a reimplementation.
* @todo Remove. Association mapping is being reimplemented.
* @deprecated
*/
class Doctrine_Relation_Parser
{

View File

@ -18,7 +18,7 @@
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Relation_Exception');
/**
* Doctrine_Relation_Parser_Exception
*
@ -28,7 +28,8 @@ Doctrine::autoload('Doctrine_Relation_Exception');
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @deprecated Remove.
*/
class Doctrine_Relation_Parser_Exception extends Doctrine_Relation_Exception
{ }

View File

@ -83,7 +83,7 @@ class Doctrine_Sequence_Mysql extends Doctrine_Sequence
*/
public function lastInsertId($table = null, $field = null)
{
return $this->conn->getDbh()->lastInsertId();
return $this->conn->getPdo()->lastInsertId();
}
/**

View File

@ -84,7 +84,7 @@ class Doctrine_Sequence_Sqlite extends Doctrine_Sequence
*/
public function lastInsertId($table = null, $field = null)
{
return $this->conn->getDbh()->lastInsertId();
return $this->conn->getPdo()->lastInsertId();
}
/**

View File

@ -11,32 +11,54 @@ class Orm_EntityPersisterTest extends Doctrine_OrmTestCase
private $_persister; // SUT
private $_connMock;
private $_emMock;
private $_seqManagerMock;
protected function setUp() {
parent::setUp();
$this->_connMock = new Doctrine_ConnectionMock(array());
$this->_emMock = new Doctrine_EntityManagerMock($this->_connMock);
$this->_seqManagerMock = new Doctrine_SequenceMock($this->_connMock);
$this->_connMock->setDatabasePlatform(new Doctrine_DatabasePlatformMock());
$this->_connMock->setSequenceManager($this->_seqManagerMock);
$this->_persister = new Doctrine_EntityPersister_Standard(
$this->_emMock, $this->_emMock->getClassMetadata("ForumUser"));
}
public function testTest() {
public function testInsert() {
$user = new ForumUser();
$user->username = "romanb";
$user->avatar = new ForumAvatar();
$this->_persister->insert($user);
$this->_seqManagerMock->autoinc(); //fake identity column autoinc
$this->_persister->insert($user->avatar);
$inserts = $this->_connMock->getInserts();
//var_dump($inserts);
//check
$this->assertEquals(1, count($inserts));
$this->assertEquals(0, $user->avatar->id);
$this->assertTrue(isset($inserts['forum_avatar']));
$this->assertEquals(1, count($inserts['forum_avatar']));
$this->assertTrue(empty($inserts['forum_avatar'][0]));
$this->_seqManagerMock->autoinc(); //fake identity column autoinc
$this->_persister->insert($user);
$inserts = $this->_connMock->getInserts();
//check
$this->assertEquals(2, count($inserts));
$this->assertEquals(1, $user->id);
$this->assertTrue(isset($inserts['forum_user']));
$this->assertEquals(1, count($inserts['forum_user']));
$this->assertEquals(1, count($inserts['forum_user'][0]));
$this->assertEquals(3, count($inserts['forum_user'][0]));
//username column
$this->assertTrue(isset($inserts['forum_user'][0]['username']));
$this->assertEquals('romanb', $inserts['forum_user'][0]['username']);
//avatar_id join column
$this->assertTrue(isset($inserts['forum_user'][0]['avatar_id']));
$this->assertEquals(0, $inserts['forum_user'][0]['avatar_id']);
//dtype discriminator column
$this->assertTrue(isset($inserts['forum_user'][0]['dtype']));
$this->assertEquals('user', $inserts['forum_user'][0]['dtype']);
}
}

View File

@ -172,7 +172,7 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
{
$this->assertSqlGeneration(
'SELECT u.id, a.id FROM CmsUser u LEFT JOIN u.articles a',
'SELECT cu.id AS cu__id, ca.id AS ca__id FROM cms_user cu LEFT JOIN cms_article ca ON ca.user_id = cu.id WHERE 1 = 1'
'SELECT cu.id AS cu__id, ca.id AS ca__id FROM cms_user cu LEFT JOIN cms_article ca ON cu.id = ca.user_id WHERE 1 = 1'
);
}

View File

@ -126,6 +126,23 @@ class Orm_UnitOfWorkTest extends Doctrine_OrmTestCase
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
}
public function testCommitOrder()
{
$avatar = new ForumAvatar();
$this->_user->avatar = $avatar;
$this->_unitOfWork->save($this->_user); // save cascaded to avatar
$this->assertEquals(2, count($this->_persisterMock->getInserts())); // insert forced
$this->assertEquals(0, count($this->_persisterMock->getUpdates()));
$this->assertEquals(0, count($this->_persisterMock->getDeletes()));
// verify order of inserts()s
$inserts = $this->_persisterMock->getInserts();
$this->assertSame($avatar, $inserts[0]);
$this->assertSame($this->_user, $inserts[1]);
//...
}
public function testSavingSingleEntityWithSequenceIdGeneratorSchedulesInsert()
{
//...

View File

@ -34,6 +34,11 @@ class Doctrine_SequenceMock extends Doctrine_Sequence
{
$this->_sequenceNumber = 0;
}
public function autoinc()
{
$this->_sequenceNumber++;
}
}
?>

View File

@ -35,17 +35,16 @@ class CmsArticle extends Doctrine_Entity
'length' => 4
));
/*$mapping->hasMany('CmsComment as comments', array(
'local' => 'id', 'foreign' => 'article_id'));*/
$mapping->mapOneToMany(array(
'fieldName' => 'comments',
'targetEntity' => 'CmsComment',
));
/*$mapping->mapManyToOne(array(
'fieldName' => 'author',
$mapping->mapManyToOne(array(
'fieldName' => 'user',
'targetEntity' => 'CmsUser',
'joinColumns' => array('user_id' => 'id')
));*/
));
}
}

View File

@ -17,5 +17,11 @@ class CmsPhonenumber extends Doctrine_Entity
'length' => 50,
'id' => true
));
$mapping->mapManyToOne(array(
'fieldName' => 'user',
'targetEntity' => 'CmsUser',
'joinColumns' => array('user_id' => 'id')
));
}
}

View File

@ -35,21 +35,17 @@ class CmsUser extends Doctrine_Entity
'type' => 'string',
'length' => 255
));
/*$mapping->hasMany('CmsPhonenumber as phonenumbers', array(
'local' => 'id', 'foreign' => 'user_id'));
$mapping->hasMany('CmsArticle as articles', array(
'local' => 'id', 'foreign' => 'user_id'));*/
$mapping->mapOneToMany(array(
'fieldName' => 'phonenumbers',
'targetEntity' => 'CmsPhonenumber',
'mappedBy' => 'user'
));
$mapping->mapOneToMany(array(
'fieldName' => 'articles',
'targetEntity' => 'CmsArticle',
'mappedBy' => 'user'
));
}

View File

@ -21,12 +21,6 @@ class ForumUser extends Doctrine_Entity
));
// register subclasses
$mapping->setSubclasses(array('ForumAdministrator'));
// the discriminator column
$mapping->mapField(array(
'fieldName' => 'dtype',
'type' => 'string',
'length' => 50
));
// column-to-field mapping
$mapping->mapField(array(
@ -46,6 +40,7 @@ class ForumUser extends Doctrine_Entity
'fieldName' => 'avatar',
'targetEntity' => 'ForumAvatar',
'joinColumns' => array('avatar_id' => 'id'),
'cascade' => array('save')
));
}