Commit 886c9611 authored by romanb's avatar romanb

[2.0] Continued work on association mappings and class exporting (DDL generation). Fixed #1863.

parent e202cb1c
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\DBAL; namespace Doctrine\DBAL;
...@@ -317,7 +317,6 @@ class Connection ...@@ -317,7 +317,6 @@ class Connection
// column names are specified as array keys // column names are specified as array keys
$cols = array(); $cols = array();
// the query VALUES will contain either expressions (eg 'NOW()') or ?
$a = array(); $a = array();
foreach ($data as $columnName => $value) { foreach ($data as $columnName => $value) {
$cols[] = $this->quoteIdentifier($columnName); $cols[] = $this->quoteIdentifier($columnName);
......
<?php <?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\DBAL\Driver\PDOMySql; namespace Doctrine\DBAL\Driver\PDOMySql;
/**
* PDO MySql driver.
*
* @since 2.0
*/
class Driver implements \Doctrine\DBAL\Driver class Driver implements \Doctrine\DBAL\Driver
{ {
/** /**
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\DBAL\Platforms; namespace Doctrine\DBAL\Platforms;
...@@ -1591,7 +1591,7 @@ abstract class AbstractPlatform ...@@ -1591,7 +1591,7 @@ abstract class AbstractPlatform
$sql .= implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['local'])) $sql .= implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['local']))
. ') REFERENCES ' . ') REFERENCES '
. $this->_conn->quoteIdentifier($definition['foreignTable']) . '(' . $this->quoteIdentifier($definition['foreignTable']) . '('
. implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['foreign'])) . ')'; . implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['foreign'])) . ')';
return $sql; return $sql;
......
...@@ -431,9 +431,7 @@ class SqlitePlatform extends AbstractPlatform ...@@ -431,9 +431,7 @@ class SqlitePlatform extends AbstractPlatform
protected function _getCommonIntegerTypeDeclarationSql(array $columnDef) protected function _getCommonIntegerTypeDeclarationSql(array $columnDef)
{ {
$autoinc = ! empty($columnDef['autoincrement']) ? 'AUTOINCREMENT' : ''; $autoinc = ! empty($columnDef['autoincrement']) ? 'AUTOINCREMENT' : '';
$pk = ! empty($columnDef['primary']) ? 'PRIMARY KEY' : ''; $pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? 'PRIMARY KEY' : '';
//$unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
return "INTEGER $pk $autoinc"; return "INTEGER $pk $autoinc";
} }
...@@ -533,5 +531,18 @@ class SqlitePlatform extends AbstractPlatform ...@@ -533,5 +531,18 @@ class SqlitePlatform extends AbstractPlatform
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)') return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
: ($length ? 'VARCHAR(' . $length . ')' : 'TEXT'); : ($length ? 'VARCHAR(' . $length . ')' : 'TEXT');
} }
/**
* SQLite does support foreign key constraints, but only in CREATE TABLE statements...
* This really limits their usefulness and requires SQLite specific handling, so
* we simply say that SQLite does NOT support foreign keys for now...
*
* @return boolean
* @override
*/
public function supportsForeignKeyConstraints()
{
return false;
}
} }
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM; namespace Doctrine\ORM;
...@@ -138,7 +138,9 @@ class EntityManager ...@@ -138,7 +138,9 @@ class EntityManager
*/ */
private $_hydrators = array(); private $_hydrators = array();
/** Whether the EntityManager is closed or not. */ /**
* Whether the EntityManager is closed or not.
*/
private $_closed = false; private $_closed = false;
/** /**
...@@ -150,11 +152,7 @@ class EntityManager ...@@ -150,11 +152,7 @@ class EntityManager
* @param Doctrine\ORM\Configuration $config * @param Doctrine\ORM\Configuration $config
* @param Doctrine\Common\EventManager $eventManager * @param Doctrine\Common\EventManager $eventManager
*/ */
protected function __construct( protected function __construct(Connection $conn, $name, Configuration $config, EventManager $eventManager)
Connection $conn,
$name,
Configuration $config,
EventManager $eventManager)
{ {
$this->_conn = $conn; $this->_conn = $conn;
$this->_name = $name; $this->_name = $name;
...@@ -207,6 +205,7 @@ class EntityManager ...@@ -207,6 +205,7 @@ class EntityManager
/** /**
* Commits a running transaction. * Commits a running transaction.
*
* This causes a flush() of the EntityManager if the flush mode is set to * This causes a flush() of the EntityManager if the flush mode is set to
* AUTO or COMMIT. * AUTO or COMMIT.
* *
...@@ -245,7 +244,7 @@ class EntityManager ...@@ -245,7 +244,7 @@ class EntityManager
} }
/** /**
* Used to lazily create the id generator. * Used to lazily create an ID generator.
* *
* @param string $generatorType * @param string $generatorType
* @return object * @return object
...@@ -281,7 +280,7 @@ class EntityManager ...@@ -281,7 +280,7 @@ class EntityManager
/** /**
* Detaches an entity from the manager. It's lifecycle is no longer managed. * Detaches an entity from the manager. It's lifecycle is no longer managed.
* *
* @param Doctrine\ORM\Entity $entity * @param object $entity
* @return boolean * @return boolean
*/ */
public function detach($entity) public function detach($entity)
...@@ -337,6 +336,7 @@ class EntityManager ...@@ -337,6 +336,7 @@ class EntityManager
/** /**
* Finds an Entity by its identifier. * Finds an Entity by its identifier.
*
* This is just a convenient shortcut for getRepository($entityName)->find($id). * This is just a convenient shortcut for getRepository($entityName)->find($id).
* *
* @param string $entityName * @param string $entityName
...@@ -349,7 +349,7 @@ class EntityManager ...@@ -349,7 +349,7 @@ class EntityManager
} }
/** /**
* Sets the flush mode. * Sets the flush mode to use.
* *
* @param string $flushMode * @param string $flushMode
*/ */
...@@ -437,21 +437,21 @@ class EntityManager ...@@ -437,21 +437,21 @@ class EntityManager
* Refreshes the persistent state of the entity from the database, * Refreshes the persistent state of the entity from the database,
* overriding any local changes that have not yet been persisted. * overriding any local changes that have not yet been persisted.
* *
* @param Doctrine\ORM\Entity $entity * @param object $entity
* @todo FIX Impl * @todo FIX Impl
*/ */
public function refresh(Doctrine_ORM_Entity $entity) public function refresh($entity)
{ {
$this->_mergeData($entity, $entity->getRepository()->find( /*$this->_mergeData($entity, $this->getRepository(get_class($entity))->find(
$entity->identifier(), Query::HYDRATE_ARRAY), $entity->identifier(), Query::HYDRATE_ARRAY),
true); true);*/
} }
/** /**
* Creates a copy of the given entity. Can create a shallow or a deep copy. * Creates a copy of the given entity. Can create a shallow or a deep copy.
* *
* @param Doctrine\ORM\Entity $entity The entity to copy. * @param object $entity The entity to copy.
* @return Doctrine\ORM\Entity The new entity. * @return object The new entity.
*/ */
public function copy($entity, $deep = false) public function copy($entity, $deep = false)
{ {
...@@ -561,16 +561,16 @@ class EntityManager ...@@ -561,16 +561,16 @@ class EntityManager
case Query::HYDRATE_OBJECT: case Query::HYDRATE_OBJECT:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this); $this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this);
break; break;
case Doctrine_ORM_Query::HYDRATE_ARRAY: case Query::HYDRATE_ARRAY:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this); $this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this);
break; break;
case Doctrine_ORM_Query::HYDRATE_SCALAR: case Query::HYDRATE_SCALAR:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this); $this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this);
break; break;
case Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR: case Query::HYDRATE_SINGLE_SCALAR:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this); $this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this);
break; break;
case Doctrine_ORM_Query::HYDRATE_NONE: case Query::HYDRATE_NONE:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\NoneHydrator($this); $this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\NoneHydrator($this);
break; break;
default: default:
...@@ -617,10 +617,7 @@ class EntityManager ...@@ -617,10 +617,7 @@ class EntityManager
* @param EventManager $eventManager The EventManager instance to use. * @param EventManager $eventManager The EventManager instance to use.
* @return EntityManager The created EntityManager. * @return EntityManager The created EntityManager.
*/ */
public static function create( public static function create($conn, $name, Configuration $config = null,
$conn,
$name,
Configuration $config = null,
EventManager $eventManager = null) EventManager $eventManager = null)
{ {
if (is_array($conn)) { if (is_array($conn)) {
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Export; namespace Doctrine\ORM\Export;
use Doctrine\ORM\EntityManager;
/** /**
* The ClassExporter can generate database schemas/structures from ClassMetadata * The ClassExporter can generate database schemas/structures from ClassMetadata
* class descriptors. * class descriptors.
...@@ -41,25 +43,32 @@ class ClassExporter ...@@ -41,25 +43,32 @@ class ClassExporter
private $_sm; private $_sm;
/** The EntityManager */ /** The EntityManager */
private $_em; private $_em;
/** The DatabasePlatform */
private $_platform;
public function __construct(\Doctrine\ORM\EntityManager $em) /**
* Initializes a new ClassExporter instance that uses the connection of the
* provided EntityManager.
*
* @param Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em)
{ {
$this->_em = $em; $this->_em = $em;
$this->_sm = $em->getConnection()->getSchemaManager(); $this->_sm = $em->getConnection()->getSchemaManager();
$this->_platform = $em->getConnection()->getDatabasePlatform();
} }
/** /**
* Exports entity classes to a schema. * Exports entity classes to a database, according to the specified mappings.
*
* FIXME: This method is a big huge hack. The sql needs to be executed in the correct order. I have some stupid logic to
* make sure they are in the right order.
* *
* @param array $classes * @param array $classes
* @return void
*/ */
public function exportClasses(array $classes) public function exportClasses(array $classes)
{ {
//TODO: order them $foreignKeyConstraints = array();
// First we create the tables
foreach ($classes as $class) { foreach ($classes as $class) {
$columns = array(); $columns = array();
$options = array(); $options = array();
...@@ -70,92 +79,84 @@ class ClassExporter ...@@ -70,92 +79,84 @@ class ClassExporter
$column['type'] = $mapping['type']; $column['type'] = $mapping['type'];
$column['length'] = $mapping['length']; $column['length'] = $mapping['length'];
$column['notnull'] = ! $mapping['nullable']; $column['notnull'] = ! $mapping['nullable'];
if ($class->isIdentifier($fieldName)) { if ($class->isIdentifier($fieldName)) {
$column['primary'] = true; $column['primary'] = true;
if ($class->isIdGeneratorIdentity()) { if ($class->isIdGeneratorIdentity()) {
$column['autoincrement'] = true; $column['autoincrement'] = true;
} }
} }
$columns[$mapping['columnName']] = $column; $columns[$mapping['columnName']] = $column;
} }
foreach ($class->getAssociationMappings() as $mapping) { foreach ($class->getAssociationMappings() as $mapping) {
$foreignClass = $this->_em->getClassMetadata($mapping->getTargetEntityName());
if ($mapping->isOneToOne() && $mapping->isOwningSide()) { if ($mapping->isOneToOne() && $mapping->isOwningSide()) {
foreach ($mapping->getSourceToTargetKeyColumns() as $sourceColumn => $targetColumn) { $constraint = array();
$constraint['tableName'] = $class->getTableName();
$constraint['foreignTable'] = $foreignClass->getTableName();
$constraint['local'] = array();
$constraint['foreign'] = array();
foreach ($mapping->getJoinColumns() as $joinColumn) {
$column = array(); $column = array();
$column['name'] = $sourceColumn; $column['name'] = $joinColumn['name'];
$column['type'] = $this->_em->getClassMetadata($mapping->getTargetEntityName()) $column['type'] = $foreignClass->getTypeOfColumn($joinColumn['referencedColumnName']);
->getTypeOfColumn($targetColumn); $columns[$joinColumn['name']] = $column;
$columns[$sourceColumn] = $column; $constraint['local'][] = $joinColumn['name'];
} $constraint['foreign'][] = $joinColumn['referencedColumnName'];
} else if ($mapping->isOneToMany() && $mapping->usesJoinTable()) { }
$foreignKeyConstraints[] = $constraint;
} else if ($mapping->isOneToMany() && $mapping->isOwningSide()) {
//... create join table, one-many through join table supported later //... create join table, one-many through join table supported later
throw new Doctrine_Exception("Not yet implemented."); throw new DoctrineException("Not yet implemented.");
} else if ($mapping->isManyToMany() && $mapping->isOwningSide()) { } else if ($mapping->isManyToMany() && $mapping->isOwningSide()) {
//... create join table //... create join table
$joinTableColumns = array();
$joinTable = $mapping->getJoinTable();
$constraint1 = array();
$constraint1['tableName'] = $joinTable['name'];
$constraint1['foreignTable'] = $class->getTableName();
$constraint1['local'] = array();
$constraint1['foreign'] = array();
foreach ($joinTable['joinColumns'] as $joinColumn) {
$column = array();
$column['primary'] = true;
$column['name'] = $joinColumn['name'];
$column['type'] = $class->getTypeOfColumn($joinColumn['referencedColumnName']);
$joinTableColumns[$joinColumn['name']] = $column;
$constraint1['local'][] = $joinColumn['name'];
$constraint1['foreign'][] = $joinColumn['referencedColumnName'];
}
$foreignKeyConstraints[] = $constraint1;
$constraint2 = array();
$constraint2['tableName'] = $joinTable['name'];
$constraint2['foreignTable'] = $foreignClass->getTableName();
$constraint2['local'] = array();
$constraint2['foreign'] = array();
foreach ($joinTable['inverseJoinColumns'] as $inverseJoinColumn) {
$column = array();
$column['primary'] = true;
$column['name'] = $inverseJoinColumn['name'];
$column['type'] = $this->_em->getClassMetadata($mapping->getTargetEntityName())
->getTypeOfColumn($inverseJoinColumn['referencedColumnName']);
$joinTableColumns[$inverseJoinColumn['name']] = $column;
$constraint2['local'][] = $inverseJoinColumn['name'];
$constraint2['foreign'][] = $inverseJoinColumn['referencedColumnName'];
} }
} $foreignKeyConstraints[] = $constraint2;
$this->_sm->createTable($class->getTableName(), $columns, $options);
}
}
/**
* exportClassesSql
* method for exporting entity classes to a schema
*
* @throws Doctrine_Connection_Exception if some error other than Doctrine::ERR_ALREADY_EXISTS
* occurred during the create table operation
* @param array $classes
* @return void
*/
public function exportClassesSql(array $classes)
{
$models = Doctrine::filterInvalidModels($classes);
$sql = array();
$finishedClasses = array();
foreach ($models as $name) {
if (in_array($name, $finishedClasses)) {
continue;
}
$classMetadata = $this->conn->getClassMetadata($name); $this->_sm->createTable($joinTable['name'], $joinTableColumns, array());
// In Class Table Inheritance we have to make sure that ALL tables of parent classes
// are exported, too as soon as ONE table is exported, because the data of one class is stored
// across many tables.
if ($classMetadata->getInheritanceType() == Doctrine::INHERITANCE_TYPE_JOINED) {
$parents = $classMetadata->getParentClasses();
foreach ($parents as $parent) {
$data = $classMetadata->getConnection()->getClassMetadata($parent)->getExportableFormat();
$query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
$sql = array_merge($sql, (array) $query);
$finishedClasses[] = $parent;
} }
} }
$data = $classMetadata->getExportableFormat(); $this->_sm->createTable($class->getTableName(), $columns, $options);
$query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
if (is_array($query)) {
$sql = array_merge($sql, $query);
} else {
$sql[] = $query;
} }
if ($classMetadata->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_PLUGINS) { // Now create the foreign key constraints
$sql = array_merge($sql, $this->exportGeneratorsSql($classMetadata)); if ($this->_platform->supportsForeignKeyConstraints()) {
foreach ($foreignKeyConstraints as $fkConstraint) {
$this->_sm->createForeignKey($fkConstraint['tableName'], $fkConstraint);
} }
} }
$sql = array_unique($sql);
rsort($sql);
return $sql;
} }
} }
<?php <?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\Id; namespace Doctrine\ORM\Id;
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/** /**
* Base class for association mappings. * Base class for association mappings.
* *
...@@ -107,11 +109,11 @@ abstract class AssociationMapping ...@@ -107,11 +109,11 @@ abstract class AssociationMapping
protected $_mappedByFieldName; protected $_mappedByFieldName;
/** /**
* The name of the join table, if any. * The join table definition, if any.
* *
* @var string * @var array
*/ */
protected $_joinTable; protected $_joinTable = array();
/** /**
* Initializes a new instance of a class derived from AssociationMapping. * Initializes a new instance of a class derived from AssociationMapping.
...@@ -132,17 +134,17 @@ abstract class AssociationMapping ...@@ -132,17 +134,17 @@ abstract class AssociationMapping
{ {
// Mandatory attributes for both sides // Mandatory attributes for both sides
if ( ! isset($mapping['fieldName'])) { if ( ! isset($mapping['fieldName'])) {
throw Doctrine_MappingException::missingFieldName(); throw MappingException::missingFieldName();
} }
$this->_sourceFieldName = $mapping['fieldName']; $this->_sourceFieldName = $mapping['fieldName'];
if ( ! isset($mapping['sourceEntity'])) { if ( ! isset($mapping['sourceEntity'])) {
throw Doctrine_MappingException::missingSourceEntity($mapping['fieldName']); throw MappingException::missingSourceEntity($mapping['fieldName']);
} }
$this->_sourceEntityName = $mapping['sourceEntity']; $this->_sourceEntityName = $mapping['sourceEntity'];
if ( ! isset($mapping['targetEntity'])) { if ( ! isset($mapping['targetEntity'])) {
throw Doctrine_ORM_Exceptions_MappingException::missingTargetEntity($mapping['fieldName']); throw MappingException::missingTargetEntity($mapping['fieldName']);
} }
$this->_targetEntityName = $mapping['targetEntity']; $this->_targetEntityName = $mapping['targetEntity'];
...@@ -287,9 +289,9 @@ abstract class AssociationMapping ...@@ -287,9 +289,9 @@ abstract class AssociationMapping
} }
/** /**
* Gets the name of the join table. * Gets the join table definition, if any.
* *
* @return string * @return array
*/ */
public function getJoinTable() public function getJoinTable()
{ {
...@@ -316,36 +318,6 @@ abstract class AssociationMapping ...@@ -316,36 +318,6 @@ abstract class AssociationMapping
return $this->_mappedByFieldName; return $this->_mappedByFieldName;
} }
/*public function getInverseSideFieldName()
{
return $this->_inverseSideFieldName;
}*/
/**
* Marks the association as bidirectional, specifying the field name of
* the inverse side.
* This is called on the owning side, when an inverse side is discovered.
* This does only make sense to call on the owning side.
*
* @param string $inverseSideFieldName
*/
/*public function setBidirectional($inverseSideFieldName)
{
if ( ! $this->_isOwningSide) {
return; //TODO: exception?
}
$this->_inverseSideFieldName = $inverseSideFieldName;
}*/
/**
* Whether the association is bidirectional.
*
* @return boolean
*/
/*public function isBidirectional()
{
return $this->_mappedByFieldName || $this->_inverseSideFieldName;
}*/
public function isOneToOne() public function isOneToOne()
{ {
return false; return false;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
use \ReflectionClass; use \ReflectionClass;
use Doctrine\Common\DoctrineException;
/** /**
* A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and * A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and
...@@ -100,9 +101,18 @@ class ClassMetadata ...@@ -100,9 +101,18 @@ class ClassMetadata
*/ */
const ENTITY_TYPE_MAPPED_SUPERCLASS = 'mappedSuperclass'; const ENTITY_TYPE_MAPPED_SUPERCLASS = 'mappedSuperclass';
/** The name of the entity class. */ /**
* The name of the entity class.
*/
protected $_entityName; protected $_entityName;
/**
* The namespace the entity class is contained in.
*
* @var string
*/
protected $_namespace;
/** /**
* The name of the entity class that is at the root of the entity inheritance * The name of the entity class that is at the root of the entity inheritance
* hierarchy. If the entity is not part of an inheritance hierarchy this is the same * hierarchy. If the entity is not part of an inheritance hierarchy this is the same
...@@ -268,11 +278,16 @@ class ClassMetadata ...@@ -268,11 +278,16 @@ class ClassMetadata
protected $_discriminatorColumn; protected $_discriminatorColumn;
/** /**
* The name of the primary table. * The primary table definition. The definition is an array with the
* following entries:
* *
* @var string * name => <tableName>
* schema => <schemaName>
* catalog => <catalogName>
*
* @var array
*/ */
protected $_tableName; protected $_primaryTable;
/** /**
* The cached lifecycle listeners. There is only one instance of each * The cached lifecycle listeners. There is only one instance of each
...@@ -332,15 +347,16 @@ class ClassMetadata ...@@ -332,15 +347,16 @@ class ClassMetadata
protected $_reflectionProperties; protected $_reflectionProperties;
/** /**
* Initializes a new ClassMetadata instance that will hold the ORM metadata * Initializes a new ClassMetadata instance that will hold the object-relational mapping
* of the class with the given name. * metadata of the class with the given name.
* *
* @param string $entityName Name of the entity class the new instance is used for. * @param string $entityName Name of the entity class the new instance is used for.
*/ */
public function __construct($entityName) public function __construct($entityName)
{ {
$this->_entityName = $entityName; $this->_entityName = $entityName;
$this->_tableName = $this->_entityName; $this->_namespace = substr($entityName, 0, strrpos($entityName, '\\'));
$this->_primaryTable['name'] = str_replace($this->_namespace . '\\', '', $this->_entityName);
$this->_rootEntityName = $entityName; $this->_rootEntityName = $entityName;
$this->_reflectionClass = new ReflectionClass($entityName); $this->_reflectionClass = new ReflectionClass($entityName);
} }
...@@ -383,7 +399,7 @@ class ClassMetadata ...@@ -383,7 +399,7 @@ class ClassMetadata
public function getSingleIdReflectionProperty() public function getSingleIdReflectionProperty()
{ {
if ($this->_isIdentifierComposite) { if ($this->_isIdentifierComposite) {
throw new Doctrine_Exception("getSingleIdReflectionProperty called on entity with composite key."); throw new DoctrineException("getSingleIdReflectionProperty called on entity with composite key.");
} }
return $this->_reflectionProperties[$this->_identifier[0]]; return $this->_reflectionProperties[$this->_identifier[0]];
} }
...@@ -448,7 +464,6 @@ class ClassMetadata ...@@ -448,7 +464,6 @@ class ClassMetadata
if ($mapping !== false) { if ($mapping !== false) {
return isset($mapping['unique']) && $mapping['unique'] == true; return isset($mapping['unique']) && $mapping['unique'] == true;
} }
return false; return false;
} }
...@@ -464,7 +479,6 @@ class ClassMetadata ...@@ -464,7 +479,6 @@ class ClassMetadata
if ($mapping !== false) { if ($mapping !== false) {
return isset($mapping['notnull']) && $mapping['notnull'] == true; return isset($mapping['notnull']) && $mapping['notnull'] == true;
} }
return false; return false;
} }
...@@ -520,8 +534,8 @@ class ClassMetadata ...@@ -520,8 +534,8 @@ class ClassMetadata
*/ */
public function getInverseAssociationMapping($mappedByFieldName) public function getInverseAssociationMapping($mappedByFieldName)
{ {
if ( ! isset($this->_associationMappings[$fieldName])) { if ( ! isset($this->_inverseMappings[$mappedByFieldName])) {
throw new Doctrine_Exception("Mapping not found: " . $fieldName); throw new DoctrineException("Mapping not found: " . $mappedByFieldName);
} }
return $this->_inverseMappings[$mappedByFieldName]; return $this->_inverseMappings[$mappedByFieldName];
} }
...@@ -932,13 +946,13 @@ class ClassMetadata ...@@ -932,13 +946,13 @@ class ClassMetadata
} }
/** /**
* getTableName * Gets the name of the primary table.
* *
* @return void * @return string
*/ */
public function getTableName() public function getTableName()
{ {
return $this->_tableName; return $this->_primaryTable['name'];
} }
public function getInheritedFields() public function getInheritedFields()
...@@ -1092,34 +1106,34 @@ class ClassMetadata ...@@ -1092,34 +1106,34 @@ class ClassMetadata
*/ */
public function setTableName($tableName) public function setTableName($tableName)
{ {
$this->_tableName = $tableName; $this->_primaryTable['name'] = $tableName;
} }
/** /**
* Serializes the metadata. * Sets the primary table definition. The provided array must have th
* following structure:
* *
* Part of the implementation of the Serializable interface. * name => <tableName>
* schema => <schemaName>
* catalog => <catalogName>
* *
* @return string The serialized metadata. * @param array $primaryTableDefinition
*/ */
/* public function serialize() public function setPrimaryTable(array $primaryTableDefinition)
{ {
//$contents = get_object_vars($this); $this->_primaryTable = $primaryTableDefinition;
//return serialize($contents); }
return "";
}*/
/** /**
* Reconstructs the metadata class from it's serialized representation. * Gets the primary table definition.
* *
* Part of the implementation of the Serializable interface. * @see setPrimaryTable()
* * @return array
* @param string $serialized The serialized metadata class.
*/ */
/*public function unserialize($serialized) public function getPrimaryTable()
{ {
return true; return $this->_primaryTable;
}*/ }
/** /**
* Checks whether the given type identifies an entity type. * Checks whether the given type identifies an entity type.
...@@ -1168,12 +1182,14 @@ class ClassMetadata ...@@ -1168,12 +1182,14 @@ class ClassMetadata
* easier for the user. * easier for the user.
* *
* @param array $mapping * @param array $mapping
* @return unknown
* @todo Pass param by ref? * @todo Pass param by ref?
*/ */
private function _completeAssociationMapping(array $mapping) private function _completeAssociationMapping(array $mapping)
{ {
$mapping['sourceEntity'] = $this->_entityName; $mapping['sourceEntity'] = $this->_entityName;
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false) {
$mapping['targetEntity'] = $this->_namespace . '\\' . $mapping['targetEntity'];
}
return $mapping; return $mapping;
} }
...@@ -1260,7 +1276,7 @@ class ClassMetadata ...@@ -1260,7 +1276,7 @@ class ClassMetadata
/** /**
* Stores the association mapping. * Stores the association mapping.
* *
* @param Doctrine_Association $assocMapping * @param AssociationMapping $assocMapping
*/ */
private function _storeAssociationMapping(AssociationMapping $assocMapping) private function _storeAssociationMapping(AssociationMapping $assocMapping)
{ {
...@@ -1278,7 +1294,7 @@ class ClassMetadata ...@@ -1278,7 +1294,7 @@ class ClassMetadata
} }
/** /**
* Registers a custom mapper for the entity class. * Registers a custom repository class for the entity class.
* *
* @param string $mapperClassName The class name of the custom mapper. * @param string $mapperClassName The class name of the custom mapper.
*/ */
...@@ -1333,11 +1349,11 @@ class ClassMetadata ...@@ -1333,11 +1349,11 @@ class ClassMetadata
//Entity::TYPE_ENTITY //Entity::TYPE_ENTITY
//Entity::TYPE_MAPPED_SUPERCLASS //Entity::TYPE_MAPPED_SUPERCLASS
//Entity::TYPE_TRANSIENT //Entity::TYPE_TRANSIENT
throw new Doctrine_Exception("Not yet implemented."); throw new DoctrineException("Not yet implemented.");
} }
/** /**
* Dispatches the lifecycle event of the given Entity to the registered * Dispatches the lifecycle event of the given entity to the registered
* lifecycle callbacks and lifecycle listeners. * lifecycle callbacks and lifecycle listeners.
* *
* @param string $event The lifecycle event. * @param string $event The lifecycle event.
...@@ -1381,7 +1397,7 @@ class ClassMetadata ...@@ -1381,7 +1397,7 @@ class ClassMetadata
} }
/** /**
* Adds a lifecycle listener for Entities of this class. * Adds a lifecycle listener for entities of this class.
* *
* Note: If the same listener class is registered more than once, the old * Note: If the same listener class is registered more than once, the old
* one will be overridden. * one will be overridden.
......
<?php <?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\Mapping\Driver; namespace Doctrine\ORM\Mapping\Driver;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Exceptions\MappingException; use Doctrine\ORM\Exceptions\MappingException;
/* Addendum annotation reflection extensions */ /* Addendum annotation reflection extensions */
if ( ! class_exists('\Addendum', false)) { if ( ! class_exists('\Addendum', false)) {
require dirname(__FILE__) . '/addendum/annotations.php'; require __DIR__ . '/addendum/annotations.php';
} }
require dirname(__FILE__) . '/DoctrineAnnotations.php'; require __DIR__ . '/DoctrineAnnotations.php';
/** /**
* The AnnotationDriver reads the mapping metadata from docblock annotations. * The AnnotationDriver reads the mapping metadata from docblock annotations.
...@@ -20,23 +40,31 @@ class AnnotationDriver ...@@ -20,23 +40,31 @@ class AnnotationDriver
/** /**
* Loads the metadata for the specified class into the provided container. * Loads the metadata for the specified class into the provided container.
*/ */
public function loadMetadataForClass($className, \Doctrine\ORM\Mapping\ClassMetadata $metadata) public function loadMetadataForClass($className, ClassMetadata $metadata)
{ {
$annotClass = new \Addendum\ReflectionAnnotatedClass($className); $annotClass = new \Addendum\ReflectionAnnotatedClass($className);
// Evaluate DoctrineEntity annotation
if (($entityAnnot = $annotClass->getAnnotation('DoctrineEntity')) === false) { if (($entityAnnot = $annotClass->getAnnotation('DoctrineEntity')) === false) {
throw new MappingException("$className is no entity."); throw new MappingException("$className is no entity.");
} }
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
if ($entityAnnot->tableName) { // Evaluate DoctrineTable annotation
$metadata->setTableName($entityAnnot->tableName); if ($tableAnnot = $annotClass->getAnnotation('DoctrineTable')) {
$metadata->setPrimaryTable(array(
'name' => $tableAnnot->name,
'schema' => $tableAnnot->schema,
'catalog' => $tableAnnot->catalog
));
} }
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
// Evaluate DoctrineInheritanceType annotation
if ($inheritanceTypeAnnot = $annotClass->getAnnotation('DoctrineInheritanceType')) { if ($inheritanceTypeAnnot = $annotClass->getAnnotation('DoctrineInheritanceType')) {
$metadata->setInheritanceType($inheritanceTypeAnnot->value); $metadata->setInheritanceType($inheritanceTypeAnnot->value);
} }
// Evaluate DoctrineDiscriminatorColumn annotation
if ($discrColumnAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorColumn')) { if ($discrColumnAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorColumn')) {
$metadata->setDiscriminatorColumn(array( $metadata->setDiscriminatorColumn(array(
'name' => $discrColumnAnnot->name, 'name' => $discrColumnAnnot->name,
...@@ -45,17 +73,38 @@ class AnnotationDriver ...@@ -45,17 +73,38 @@ class AnnotationDriver
)); ));
} }
// Evaluate DoctrineDiscriminatorMap annotation
if ($discrValueAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) { if ($discrValueAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) {
$metadata->setDiscriminatorMap((array)$discrValueAnnot->value); $metadata->setDiscriminatorMap((array)$discrValueAnnot->value);
} }
// Evaluate DoctrineSubClasses annotation
if ($subClassesAnnot = $annotClass->getAnnotation('DoctrineSubClasses')) { if ($subClassesAnnot = $annotClass->getAnnotation('DoctrineSubClasses')) {
$metadata->setSubclasses($subClassesAnnot->value); $metadata->setSubclasses($subClassesAnnot->value);
} }
// Evaluate annotations on properties/fields
foreach ($annotClass->getProperties() as $property) { foreach ($annotClass->getProperties() as $property) {
$mapping = array(); $mapping = array();
$mapping['fieldName'] = $property->getName(); $mapping['fieldName'] = $property->getName();
// Check for DoctrineJoinColummn/DoctrineJoinColumns annotations
$joinColumns = array();
if ($joinColumnAnnot = $property->getAnnotation('DoctrineJoinColumn')) {
$joinColumns[] = array(
'name' => $joinColumnAnnot->name,
'referencedColumnName' => $joinColumnAnnot->referencedColumnName,
'unique' => $joinColumnAnnot->unique,
'nullable' => $joinColumnAnnot->nullable,
'onDelete' => $joinColumnAnnot->onDelete,
'onUpdate' => $joinColumnAnnot->onUpdate
);
} else if ($joinColumnsAnnot = $property->getAnnotation('DoctrineJoinColumns')) {
$joinColumns = $joinColumnsAnnot->value;
}
// Field can only be annotated with one of: DoctrineColumn,
// DoctrineOneToOne, DoctrineOneToMany, DoctrineManyToOne, DoctrineManyToMany
if ($columnAnnot = $property->getAnnotation('DoctrineColumn')) { if ($columnAnnot = $property->getAnnotation('DoctrineColumn')) {
if ($columnAnnot->type == null) { if ($columnAnnot->type == null) {
throw new MappingException("Missing type on property " . $property->getName()); throw new MappingException("Missing type on property " . $property->getName());
...@@ -72,7 +121,7 @@ class AnnotationDriver ...@@ -72,7 +121,7 @@ class AnnotationDriver
$metadata->mapField($mapping); $metadata->mapField($mapping);
} else if ($oneToOneAnnot = $property->getAnnotation('DoctrineOneToOne')) { } else if ($oneToOneAnnot = $property->getAnnotation('DoctrineOneToOne')) {
$mapping['targetEntity'] = $oneToOneAnnot->targetEntity; $mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
$mapping['joinColumns'] = $oneToOneAnnot->joinColumns; $mapping['joinColumns'] = $joinColumns;
$mapping['mappedBy'] = $oneToOneAnnot->mappedBy; $mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade; $mapping['cascade'] = $oneToOneAnnot->cascade;
$metadata->mapOneToOne($mapping); $metadata->mapOneToOne($mapping);
...@@ -82,17 +131,26 @@ class AnnotationDriver ...@@ -82,17 +131,26 @@ class AnnotationDriver
$mapping['cascade'] = $oneToManyAnnot->cascade; $mapping['cascade'] = $oneToManyAnnot->cascade;
$metadata->mapOneToMany($mapping); $metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $property->getAnnotation('DoctrineManyToOne')) { } else if ($manyToOneAnnot = $property->getAnnotation('DoctrineManyToOne')) {
$mapping['joinColumns'] = $manyToOneAnnot->joinColumns; $mapping['joinColumns'] = $joinColumns;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity; $mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$metadata->mapManyToOne($mapping); $metadata->mapManyToOne($mapping);
} else if ($manyToManyAnnot = $property->getAnnotation('DoctrineManyToMany')) { } else if ($manyToManyAnnot = $property->getAnnotation('DoctrineManyToMany')) {
$joinTable = array();
if ($joinTableAnnot = $property->getAnnotation('DoctrineJoinTable')) {
$joinTable = array(
'name' => $joinTableAnnot->name,
'schema' => $joinTableAnnot->schema,
'catalog' => $joinTableAnnot->catalog,
'joinColumns' => $joinTableAnnot->joinColumns,
'inverseJoinColumns' => $joinTableAnnot->inverseJoinColumns
);
}
$mapping['joinTable'] = $joinTable;
$mapping['targetEntity'] = $manyToManyAnnot->targetEntity; $mapping['targetEntity'] = $manyToManyAnnot->targetEntity;
$mapping['joinColumns'] = $manyToManyAnnot->joinColumns;
$mapping['inverseJoinColumns'] = $manyToManyAnnot->inverseJoinColumns;
$mapping['joinTable'] = $manyToManyAnnot->joinTable;
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy; $mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$metadata->mapManyToMany($mapping); $metadata->mapManyToMany($mapping);
} }
} }
} }
} }
<?php <?php
/* /*
* To change this template, choose Tools | Templates * $Id$
* and open the template in the editor. *
* 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>.
*/ */
/* Annotations */ /* Annotations */
final class DoctrineEntity extends \Addendum\Annotation { final class DoctrineEntity extends \Addendum\Annotation {
public $tableName;
public $repositoryClass; public $repositoryClass;
public $inheritanceType;
} }
final class DoctrineInheritanceType extends \Addendum\Annotation {} final class DoctrineInheritanceType extends \Addendum\Annotation {}
final class DoctrineDiscriminatorColumn extends \Addendum\Annotation { final class DoctrineDiscriminatorColumn extends \Addendum\Annotation {
...@@ -24,11 +37,13 @@ final class DoctrineIdGenerator extends \Addendum\Annotation {} ...@@ -24,11 +37,13 @@ final class DoctrineIdGenerator extends \Addendum\Annotation {}
final class DoctrineVersion extends \Addendum\Annotation {} final class DoctrineVersion extends \Addendum\Annotation {}
final class DoctrineJoinColumn extends \Addendum\Annotation { final class DoctrineJoinColumn extends \Addendum\Annotation {
public $name; public $name;
public $type; public $referencedColumnName;
public $length; public $unique = false;
public $nullable = true;
public $onDelete; public $onDelete;
public $onUpdate; public $onUpdate;
} }
final class DoctrineJoinColumns extends \Addendum\Annotation {}
final class DoctrineColumn extends \Addendum\Annotation { final class DoctrineColumn extends \Addendum\Annotation {
public $type; public $type;
public $length; public $length;
...@@ -38,7 +53,6 @@ final class DoctrineColumn extends \Addendum\Annotation { ...@@ -38,7 +53,6 @@ final class DoctrineColumn extends \Addendum\Annotation {
final class DoctrineOneToOne extends \Addendum\Annotation { final class DoctrineOneToOne extends \Addendum\Annotation {
public $targetEntity; public $targetEntity;
public $mappedBy; public $mappedBy;
public $joinColumns;
public $cascade; public $cascade;
} }
final class DoctrineOneToMany extends \Addendum\Annotation { final class DoctrineOneToMany extends \Addendum\Annotation {
...@@ -48,15 +62,25 @@ final class DoctrineOneToMany extends \Addendum\Annotation { ...@@ -48,15 +62,25 @@ final class DoctrineOneToMany extends \Addendum\Annotation {
} }
final class DoctrineManyToOne extends \Addendum\Annotation { final class DoctrineManyToOne extends \Addendum\Annotation {
public $targetEntity; public $targetEntity;
public $joinColumns;
public $cascade; public $cascade;
} }
final class DoctrineManyToMany extends \Addendum\Annotation { final class DoctrineManyToMany extends \Addendum\Annotation {
public $targetEntity; public $targetEntity;
public $joinColumns;
public $inverseJoinColumns;
public $joinTable;
public $mappedBy; public $mappedBy;
public $cascade; public $cascade;
} }
final class DoctrineElementCollection extends \Addendum\Annotation {
public $tableName;
}
final class DoctrineTable extends \Addendum\Annotation {
public $name;
public $catalog;
public $schema;
}
final class DoctrineJoinTable extends \Addendum\Annotation {
public $name;
public $catalog;
public $schema;
public $joinColumns;
public $inverseJoinColumns;
}
<?php <?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::Mapping; namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/** /**
* A many-to-many mapping describes the mapping between two collections of * A many-to-many mapping describes the mapping between two collections of
* entities. * entities.
* *
* @since 2.0 * @since 2.0
* @todo Rename to ManyToManyMapping * @author Roman Borschel <roman@code-factory.org>
*/ */
class Doctrine_ORM_Mapping_ManyToManyMapping extends Doctrine_ORM_Mapping_AssociationMapping class ManyToManyMapping extends AssociationMapping
{ {
/** /**
* The name of the association class (if an association class is used). * The key columns of the source table.
*
* @var string
*/ */
private $_associationClass; private $_sourceKeyColumns = array();
/** The field in the source table that corresponds to the key in the relation table */ /**
protected $_sourceKeyColumns; * The key columns of the target table.
*/
/** The field in the target table that corresponds to the key in the relation table */ private $_targetKeyColumns = array();
protected $_targetKeyColumns;
/** The field in the intermediate table that corresponds to the key in the source table */ /**
protected $_sourceRelationKeyColumns; * Maps the columns in the source table to the columns in the relation table.
*/
private $_sourceToRelationKeyColumns = array();
/** The field in the intermediate table that corresponds to the key in the target table */ /**
protected $_targetRelationKeyColumns; * Maps the columns in the target table to the columns in the relation table.
*/
private $_targetToRelationKeyColumns = array();
/** /**
* Constructor. * Initializes a new ManyToManyMapping.
* Creates a new ManyToManyMapping.
* *
* @param array $mapping The mapping info. * @param array $mapping The mapping information.
*/ */
public function __construct(array $mapping) public function __construct(array $mapping)
{ {
...@@ -50,38 +71,63 @@ class Doctrine_ORM_Mapping_ManyToManyMapping extends Doctrine_ORM_Mapping_Associ ...@@ -50,38 +71,63 @@ class Doctrine_ORM_Mapping_ManyToManyMapping extends Doctrine_ORM_Mapping_Associ
protected function _validateAndCompleteMapping(array $mapping) protected function _validateAndCompleteMapping(array $mapping)
{ {
parent::_validateAndCompleteMapping($mapping); parent::_validateAndCompleteMapping($mapping);
if ($this->isOwningSide()) { if ($this->isOwningSide()) {
// many-many owning MUST have a join table // owning side MUST have a join table
if ( ! isset($mapping['joinTable'])) { if ( ! isset($mapping['joinTable'])) {
throw Doctrine_MappingException::joinTableRequired($mapping['fieldName']); throw MappingException::joinTableRequired($mapping['fieldName']);
}
// owning side MUST specify joinColumns
if ( ! isset($mapping['joinTable']['joinColumns'])) {
throw MappingException::invalidMapping($this->_sourceFieldName);
}
foreach ($mapping['joinTable']['joinColumns'] as $joinColumn) {
$this->_sourceToRelationKeyColumns[$joinColumn['referencedColumnName']] = $joinColumn['name'];
}
$this->_sourceKeyColumns = array_keys($this->_sourceToRelationKeyColumns);
// owning side MUST specify inverseJoinColumns
if ( ! isset($mapping['joinTable']['inverseJoinColumns'])) {
throw MappingException::invalidMapping($this->_sourceFieldName);
}
foreach ($mapping['joinTable']['inverseJoinColumns'] as $inverseJoinColumn) {
$this->_targetToRelationKeyColumns[$inverseJoinColumn['referencedColumnName']] = $inverseJoinColumn['name'];
}
$this->_targetKeyColumns = array_keys($this->_targetToRelationKeyColumns);
}
} }
// optional attributes for many-many owning side public function getSourceToRelationKeyColumns()
$this->_associationClass = isset($mapping['associationClass']) ? {
$mapping['associationClass'] : null; return $this->_sourceToRelationKeyColumns;
} }
public function getTargetToRelationKeyColumns()
{
return $this->_targetToRelationKeyColumns;
} }
/** public function getSourceKeyColumns()
* Whether the mapping uses an association class for the intermediary
* table.
*
* @return boolean
*/
public function usesAssociationClass()
{ {
return $this->_associationClass !== null; return $this->_sourceKeyColumns;
}
public function getTargetKeyColumns()
{
return $this->_targetKeyColumns;
}
public function lazyLoadFor($entity, $entityManager)
{
} }
/** /**
* Gets the name of the association class. * {@inheritdoc}
* *
* @return string * @override
*/ */
public function getAssociationClassName() public function isManyToMany()
{ {
return $this->_associationClass; return true;
} }
} }
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Mapping; namespace Doctrine\ORM\Mapping;
...@@ -54,10 +54,9 @@ class OneToManyMapping extends AssociationMapping ...@@ -54,10 +54,9 @@ class OneToManyMapping extends AssociationMapping
protected $_deleteOrphans = false; protected $_deleteOrphans = false;
/** /**
* Constructor. * Initializes a new OneToManyMapping.
* Creates a new OneToManyMapping.
* *
* @param array $mapping The mapping info. * @param array $mapping The mapping information.
*/ */
public function __construct(array $mapping) public function __construct(array $mapping)
{ {
......
...@@ -35,21 +35,28 @@ class OneToOneMapping extends AssociationMapping ...@@ -35,21 +35,28 @@ class OneToOneMapping extends AssociationMapping
* i.e. source.id (pk) => target.user_id (fk). * i.e. source.id (pk) => target.user_id (fk).
* Reverse mapping of _targetToSourceKeyColumns. * Reverse mapping of _targetToSourceKeyColumns.
*/ */
protected $_sourceToTargetKeyColumns = array(); private $_sourceToTargetKeyColumns = array();
/** /**
* Maps the target primary/foreign key columns to the source foreign/primary key columns. * Maps the target primary/foreign key columns to the source foreign/primary key columns.
* i.e. target.user_id (fk) => source.id (pk). * i.e. target.user_id (fk) => source.id (pk).
* Reverse mapping of _sourceToTargetKeyColumns. * Reverse mapping of _sourceToTargetKeyColumns.
*/ */
protected $_targetToSourceKeyColumns = array(); private $_targetToSourceKeyColumns = array();
/** /**
* Whether to delete orphaned elements (when nulled out, i.e. $foo->other = null) * Whether to delete orphaned elements (when nulled out, i.e. $foo->other = null)
* *
* @var boolean * @var boolean
*/ */
protected $_deleteOrphans = false; private $_deleteOrphans = false;
/**
* The join column definitions.
*
* @var array
*/
private $_joinColumns = array();
/** /**
* Creates a new OneToOneMapping. * Creates a new OneToOneMapping.
...@@ -74,9 +81,12 @@ class OneToOneMapping extends AssociationMapping ...@@ -74,9 +81,12 @@ class OneToOneMapping extends AssociationMapping
if ($this->isOwningSide()) { if ($this->isOwningSide()) {
if ( ! isset($mapping['joinColumns'])) { if ( ! isset($mapping['joinColumns'])) {
throw Doctrine_ORM_Exceptions_MappingException::invalidMapping($this->_sourceFieldName); throw MappingException::invalidMapping($this->_sourceFieldName);
}
$this->_joinColumns = $mapping['joinColumns'];
foreach ($mapping['joinColumns'] as $joinColumn) {
$this->_sourceToTargetKeyColumns[$joinColumn['name']] = $joinColumn['referencedColumnName'];
} }
$this->_sourceToTargetKeyColumns = $mapping['joinColumns'];
$this->_targetToSourceKeyColumns = array_flip($this->_sourceToTargetKeyColumns); $this->_targetToSourceKeyColumns = array_flip($this->_sourceToTargetKeyColumns);
} }
...@@ -86,6 +96,16 @@ class OneToOneMapping extends AssociationMapping ...@@ -86,6 +96,16 @@ class OneToOneMapping extends AssociationMapping
return $mapping; return $mapping;
} }
/**
* Gets the join column definitions for this mapping.
*
* @return array
*/
public function getJoinColumns()
{
return $this->_joinColumns;
}
/** /**
* Gets the source-to-target key column mapping. * Gets the source-to-target key column mapping.
* *
......
<?php <?php
/* /*
* $Id: Collection.php 4930 2008-09-12 10:40:23Z romanb $ * $Id$
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM; namespace Doctrine\ORM;
...@@ -110,6 +110,12 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection ...@@ -110,6 +110,12 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*/ */
private $_ownerClass; private $_ownerClass;
/**
* Whether the collection is dirty and needs to be synchronized with the database
* when the UnitOfWork that manages its persistent state commits.
*
* @var boolean
*/
private $_isDirty = false; private $_isDirty = false;
/** /**
...@@ -181,11 +187,21 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection ...@@ -181,11 +187,21 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
* *
* @return object * @return object
*/ */
public function _getOwner() public function getOwner()
{ {
return $this->_owner; return $this->_owner;
} }
/**
* Gets the class descriptor for the owning entity class.
*
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
public function getOwnerClass()
{
return $this->_ownerClass;
}
/** /**
* Removes an element from the collection. * Removes an element from the collection.
* *
...@@ -251,8 +267,9 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection ...@@ -251,8 +267,9 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
/** /**
* Adds all entities of the other collection to this collection. * Adds all entities of the other collection to this collection.
* *
* @param unknown_type $otherCollection * @param object $otherCollection
* @todo Impl * @todo Impl
* @override
*/ */
public function addAll($otherCollection) public function addAll($otherCollection)
{ {
......
<?php <?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\Persisters; namespace Doctrine\ORM\Persisters;
use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityManager;
use Doctrine\ORM\PersistentCollection; use Doctrine\ORM\PersistentCollection;
/**
* Base class for all collection persisters.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractCollectionPersister abstract class AbstractCollectionPersister
{ {
protected $_em; protected $_em;
protected $_conn; protected $_conn;
protected $_uow;
/**
* Initializes a new instance of a class derived from {@link AbstractCollectionPersister}.
*
* @param Doctrine\ORM\EntityManager $em
*/
public function __construct(EntityManager $em) public function __construct(EntityManager $em)
{ {
$this->_em = $em; $this->_em = $em;
$this->_uow = $em->getUnitOfWork();
$this->_conn = $em->getConnection(); $this->_conn = $em->getConnection();
} }
...@@ -51,7 +83,7 @@ abstract class AbstractCollectionPersister ...@@ -51,7 +83,7 @@ abstract class AbstractCollectionPersister
$sql = $this->_getDeleteRowSql($coll); $sql = $this->_getDeleteRowSql($coll);
$uow = $this->_em->getUnitOfWork(); $uow = $this->_em->getUnitOfWork();
foreach ($deleteDiff as $element) { foreach ($deleteDiff as $element) {
$this->_conn->exec($sql, $uow->getEntityIdentifier($element)); $this->_conn->exec($sql, $this->_getDeleteRowSqlParameters($element));
} }
} }
...@@ -81,6 +113,8 @@ abstract class AbstractCollectionPersister ...@@ -81,6 +113,8 @@ abstract class AbstractCollectionPersister
*/ */
abstract protected function _getDeleteRowSql(PersistentCollection $coll); abstract protected function _getDeleteRowSql(PersistentCollection $coll);
abstract protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element);
/** /**
* Gets the SQL statement used for updating a row in the collection. * Gets the SQL statement used for updating a row in the collection.
* *
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM\Persisters; namespace Doctrine\ORM\Persisters;
......
<?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\Persisters;
/**
* Persister for collections of basic elements / value objects.
*
* @author robo
*/
class ElementCollectionPersister extends AbstractCollectionPersister
{
//put your code here
}
...@@ -17,9 +17,28 @@ class ManyToManyPersister extends AbstractCollectionPersister ...@@ -17,9 +17,28 @@ class ManyToManyPersister extends AbstractCollectionPersister
* *
* @param <type> $coll * @param <type> $coll
* @override * @override
* @todo Identifier quoting.
* @see _getDeleteRowSqlParameters()
*/ */
protected function _getDeleteRowSql(PersistentCollection $coll) protected function _getDeleteRowSql(PersistentCollection $coll)
{ {
$mapping = $coll->getMapping();
$joinTable = $mapping->getJoinTable();
$columns = array_merge($mapping->getSourceKeyColumns(), $mapping->getTargetKeyColumns());
return "DELETE FROM $joinTable WHERE " . implode(' = ?, ', $columns) . ' = ?';
}
/**
*
* @param <type> $element
* @override
* @see _getDeleteRowSql()
*/
protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element)
{
$owner = $coll->getOwner();
} }
} }
......
...@@ -9,7 +9,13 @@ use Doctrine\ORM\PersistentCollection; ...@@ -9,7 +9,13 @@ use Doctrine\ORM\PersistentCollection;
*/ */
class OneToManyPersister extends AbstractCollectionPersister class OneToManyPersister extends AbstractCollectionPersister
{ {
/**
* {@inheritdoc}
*
* @param <type> $coll
* @return <type>
* @override
*/
protected function _getDeleteRowSql(PersistentCollection $coll) protected function _getDeleteRowSql(PersistentCollection $coll)
{ {
$mapping = $coll->getMapping(); $mapping = $coll->getMapping();
...@@ -33,6 +39,18 @@ class OneToManyPersister extends AbstractCollectionPersister ...@@ -33,6 +39,18 @@ class OneToManyPersister extends AbstractCollectionPersister
return "UPDATE $table SET $setClause WHERE $whereClause"; return "UPDATE $table SET $setClause WHERE $whereClause";
} }
/**
* {@inheritdoc}
*
* @param <type> $element
* @return <type>
* @override
*/
protected function _getDeleteRowSqlParameters(PersistentCollection $coll, $element)
{
return $this->_uow->getEntityIdentifier($element);
}
protected function _getInsertRowSql() protected function _getInsertRowSql()
{ {
return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz"; return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz";
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* This software consists of voluntary contributions made by many individuals * This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see * and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>. * <http://www.doctrine-project.org>.
*/ */
namespace Doctrine\ORM; namespace Doctrine\ORM;
...@@ -584,13 +584,13 @@ class UnitOfWork ...@@ -584,13 +584,13 @@ class UnitOfWork
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
if (isset($this->_dirtyEntities[$oid])) { if (isset($this->_dirtyEntities[$oid])) {
throw new Doctrine_Exception("Dirty object can't be registered as new."); throw new DoctrineException("Dirty object can't be registered as new.");
} }
if (isset($this->_deletedEntities[$oid])) { if (isset($this->_deletedEntities[$oid])) {
throw new Doctrine_Exception("Removed object can't be registered as new."); throw new DoctrineException("Removed object can't be registered as new.");
} }
if (isset($this->_newEntities[$oid])) { if (isset($this->_newEntities[$oid])) {
throw new Doctrine_Exception("Object already registered as new. Can't register twice."); throw new DoctrineException("Object already registered as new. Can't register twice.");
} }
$this->_newEntities[$oid] = $entity; $this->_newEntities[$oid] = $entity;
...@@ -968,8 +968,7 @@ class UnitOfWork ...@@ -968,8 +968,7 @@ class UnitOfWork
$this->registerNew($entity); $this->registerNew($entity);
break; break;
case self::STATE_DETACHED: case self::STATE_DETACHED:
//exception? throw new DoctrineException("Behavior of save() for a detached entity "
throw new Doctrine_Exception("Behavior of save() for a detached entity "
. "is not yet defined."); . "is not yet defined.");
case self::STATE_DELETED: case self::STATE_DELETED:
// entity becomes managed again // entity becomes managed again
...@@ -983,7 +982,7 @@ class UnitOfWork ...@@ -983,7 +982,7 @@ class UnitOfWork
break; break;
default: default:
//TODO: throw UnitOfWorkException::invalidEntityState() //TODO: throw UnitOfWorkException::invalidEntityState()
throw new Doctrine_Exception("Encountered invalid entity state."); throw new DoctrineException("Encountered invalid entity state.");
} }
$this->_cascadeSave($entity, $visited, $insertNow); $this->_cascadeSave($entity, $visited, $insertNow);
} }
......
...@@ -10,7 +10,8 @@ namespace Doctrine\Tests\Models\CMS; ...@@ -10,7 +10,8 @@ namespace Doctrine\Tests\Models\CMS;
* Description of CmsAddress * Description of CmsAddress
* *
* @author robo * @author robo
* @DoctrineEntity(tableName="cms_addresses") * @DoctrineEntity
* @DoctrineTable(name="cms_addresses")
*/ */
class CmsAddress class CmsAddress
{ {
...@@ -33,9 +34,8 @@ class CmsAddress ...@@ -33,9 +34,8 @@ class CmsAddress
*/ */
public $city; public $city;
/** /**
* @DoctrineOneToOne( * @DoctrineOneToOne(targetEntity="CmsUser")
targetEntity="Doctrine\Tests\Models\CMS\CmsUser", * @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
joinColumns={"user_id" = "id"})
*/ */
public $user; public $user;
} }
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;
/** /**
* @DoctrineEntity(tableName="cms_articles") * @DoctrineEntity
* @DoctrineTable(name="cms_articles")
*/ */
class CmsArticle class CmsArticle
{ {
...@@ -22,12 +23,12 @@ class CmsArticle ...@@ -22,12 +23,12 @@ class CmsArticle
*/ */
public $text; public $text;
/** /**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsUser", * @DoctrineManyToOne(targetEntity="CmsUser")
joinColumns={"user_id" = "id"}) * @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
*/ */
public $user; public $user;
/** /**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsComment", mappedBy="article") * @DoctrineOneToMany(targetEntity="CmsComment", mappedBy="article")
*/ */
public $comments; public $comments;
} }
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;
/** /**
* @DoctrineEntity(tableName="cms_comments") * @DoctrineEntity
* @DoctrineTable(name="cms_comments")
*/ */
class CmsComment class CmsComment
{ {
...@@ -22,8 +23,8 @@ class CmsComment ...@@ -22,8 +23,8 @@ class CmsComment
*/ */
public $text; public $text;
/** /**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsArticle", * @DoctrineManyToOne(targetEntity="CmsArticle")
joinColumns={"article_id" = "id"}) * @DoctrineJoinColumn(name="article_id", referencedColumnName="id")
*/ */
public $article; public $article;
} }
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\Tests\Models\CMS;
/**
* Description of CmsGroup
*
* @author robo
* @DoctrineEntity
* @DoctrineTable(name="cms_groups")
*/
class CmsGroup
{
/**
* @DoctrineId
* @DoctrineColumn(type="integer")
* @DoctrineIdGenerator("auto")
*/
public $id;
/**
* @DoctrineColumn(type="varchar", length=50)
*/
public $name;
/**
* @DoctrineManyToMany(targetEntity="CmsUser", mappedBy="groups")
*/
public $users;
}
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;
/** /**
* @DoctrineEntity(tableName="cms_phonenumbers") * @DoctrineEntity
* @DoctrineTable(name="cms_phonenumbers")
*/ */
class CmsPhonenumber class CmsPhonenumber
{ {
...@@ -13,8 +14,8 @@ class CmsPhonenumber ...@@ -13,8 +14,8 @@ class CmsPhonenumber
*/ */
public $phonenumber; public $phonenumber;
/** /**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsUser", * @DoctrineManyToOne(targetEntity="CmsUser")
joinColumns={"user_id" = "id"}) * @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
*/ */
public $user; public $user;
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS; namespace Doctrine\Tests\Models\CMS;
/** /**
* @DoctrineEntity(tableName="cms_users") * @DoctrineEntity
* @DoctrineTable(name="cms_users")
*/ */
class CmsUser class CmsUser
{ {
...@@ -26,19 +27,24 @@ class CmsUser ...@@ -26,19 +27,24 @@ class CmsUser
*/ */
public $name; public $name;
/** /**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsPhonenumber", * @DoctrineOneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"save", "delete"})
mappedBy="user", cascade={"save", "delete"})
*/ */
public $phonenumbers; public $phonenumbers;
/** /**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsArticle", mappedBy="user") * @DoctrineOneToMany(targetEntity="CmsArticle", mappedBy="user")
*/ */
public $articles; public $articles;
/** /**
* @DoctrineOneToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsAddress", mappedBy="user", * @DoctrineOneToOne(targetEntity="CmsAddress", mappedBy="user", cascade={"save"})
cascade={"save"})
*/ */
public $address; public $address;
/**
* @DoctrineManyToMany(targetEntity="CmsGroup")
* @DoctrineJoinTable(name="cms_users_groups",
joinColumns={{"name"="user_id", "referencedColumnName"="id"}},
inverseJoinColumns={{"name"="group_id", "referencedColumnName"="id"}})
*/
public $groups;
/** /**
* Adds a phonenumber to the user. * Adds a phonenumber to the user.
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\Forum; namespace Doctrine\Tests\Models\Forum;
/** /**
* @DoctrineEntity(tableName="forum_avatars") * @DoctrineEntity
* @DoctrineTable(name="forum_avatars")
*/ */
class ForumAvatar class ForumAvatar
{ {
......
...@@ -7,6 +7,7 @@ namespace Doctrine\Tests\Models\Forum; ...@@ -7,6 +7,7 @@ namespace Doctrine\Tests\Models\Forum;
* *
* @author robo * @author robo
* @DoctrineEntity * @DoctrineEntity
* @DoctrineTable(name="forum_boards")
*/ */
class ForumBoard class ForumBoard
{ {
...@@ -20,8 +21,8 @@ class ForumBoard ...@@ -20,8 +21,8 @@ class ForumBoard
*/ */
public $position; public $position;
/** /**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\Forum\ForumCategory", * @DoctrineManyToOne(targetEntity="ForumCategory")
joinColumns={"category_id" = "id"}) * @DoctrineJoinColumn(name="category_id", referencedColumnName="id")
*/ */
public $category; public $category;
} }
...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum; ...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum;
/** /**
* @DoctrineEntity * @DoctrineEntity
* @DoctrineTable(name="forum_categories")
*/ */
class ForumCategory class ForumCategory
{ {
...@@ -21,7 +22,7 @@ class ForumCategory ...@@ -21,7 +22,7 @@ class ForumCategory
*/ */
public $name; public $name;
/** /**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\Forum\ForumBoard", mappedBy="category") * @DoctrineOneToMany(targetEntity="ForumBoard", mappedBy="category")
*/ */
public $boards; public $boards;
......
...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum; ...@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum;
/** /**
* @DoctrineEntity * @DoctrineEntity
* @DoctrineTable(name="forum_entries")
*/ */
class ForumEntry class ForumEntry
{ {
......
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\Forum; namespace Doctrine\Tests\Models\Forum;
/** /**
* @DoctrineEntity(tableName="forum_users") * @DoctrineEntity
* @DoctrineTable(name="forum_users")
* @DoctrineInheritanceType("joined") * @DoctrineInheritanceType("joined")
* @DoctrineDiscriminatorColumn(name="dtype", type="varchar", length=20) * @DoctrineDiscriminatorColumn(name="dtype", type="varchar", length=20)
* @DoctrineDiscriminatorMap({ * @DoctrineDiscriminatorMap({
...@@ -24,10 +25,8 @@ class ForumUser ...@@ -24,10 +25,8 @@ class ForumUser
*/ */
public $username; public $username;
/** /**
* @DoctrineOneToOne( * @DoctrineOneToOne(targetEntity="ForumAvatar", cascade={"save"})
targetEntity="Doctrine\Tests\Models\Forum\ForumAvatar", * @DoctrineJoinColumn(name="avatar_id", referencedColumnName="id")
joinColumns={"avatar_id" = "id"},
cascade={"save"})
*/ */
public $avatar; public $avatar;
} }
\ No newline at end of file
...@@ -11,7 +11,7 @@ class OneToOneMappingTest extends \Doctrine\Tests\OrmTestCase ...@@ -11,7 +11,7 @@ class OneToOneMappingTest extends \Doctrine\Tests\OrmTestCase
$owningSideMapping = array( $owningSideMapping = array(
'fieldName' => 'address', 'fieldName' => 'address',
'targetEntity' => 'Address', 'targetEntity' => 'Address',
'joinColumns' => array('address_id' => 'id'), 'joinColumns' => array(array('name' => 'address_id', 'referencedColumnName' => 'id')),
'sourceEntity' => 'Person', // This is normally filled by ClassMetadata 'sourceEntity' => 'Person', // This is normally filled by ClassMetadata
); );
......
...@@ -44,7 +44,6 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase ...@@ -44,7 +44,6 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(1, count($cm->getAssociationMappings())); $this->assertEquals(1, count($cm->getAssociationMappings()));
$oneOneMapping = $cm->getAssociationMapping('phonenumbers'); $oneOneMapping = $cm->getAssociationMapping('phonenumbers');
$this->assertEquals('phonenumbers', $oneOneMapping->getSourceFieldName()); $this->assertEquals('phonenumbers', $oneOneMapping->getSourceFieldName());
$this->assertEquals('Bar', $oneOneMapping->getTargetEntityName()); $this->assertEquals('Doctrine\Tests\Models\CMS\Bar', $oneOneMapping->getTargetEntityName());
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment