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 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL;
......@@ -317,7 +317,6 @@ class Connection
// column names are specified as array keys
$cols = array();
// the query VALUES will contain either expressions (eg 'NOW()') or ?
$a = array();
foreach ($data as $columnName => $value) {
$cols[] = $this->quoteIdentifier($columnName);
......
<?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;
/**
* PDO MySql driver.
*
* @since 2.0
*/
class Driver implements \Doctrine\DBAL\Driver
{
/**
......
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Platforms;
......@@ -1591,7 +1591,7 @@ abstract class AbstractPlatform
$sql .= implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['local']))
. ') REFERENCES '
. $this->_conn->quoteIdentifier($definition['foreignTable']) . '('
. $this->quoteIdentifier($definition['foreignTable']) . '('
. implode(', ', array_map(array($this, 'quoteIdentifier'), $definition['foreign'])) . ')';
return $sql;
......
......@@ -431,9 +431,7 @@ class SqlitePlatform extends AbstractPlatform
protected function _getCommonIntegerTypeDeclarationSql(array $columnDef)
{
$autoinc = ! empty($columnDef['autoincrement']) ? 'AUTOINCREMENT' : '';
$pk = ! empty($columnDef['primary']) ? 'PRIMARY KEY' : '';
//$unsigned = (isset($columnDef['unsigned']) && $columnDef['unsigned']) ? ' UNSIGNED' : '';
$pk = ! empty($columnDef['primary']) && ! empty($autoinc) ? 'PRIMARY KEY' : '';
return "INTEGER $pk $autoinc";
}
......@@ -533,5 +531,18 @@ class SqlitePlatform extends AbstractPlatform
return $fixed ? ($length ? 'CHAR(' . $length . ')' : 'CHAR(255)')
: ($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 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
......@@ -138,7 +138,9 @@ class EntityManager
*/
private $_hydrators = array();
/** Whether the EntityManager is closed or not. */
/**
* Whether the EntityManager is closed or not.
*/
private $_closed = false;
/**
......@@ -150,11 +152,7 @@ class EntityManager
* @param Doctrine\ORM\Configuration $config
* @param Doctrine\Common\EventManager $eventManager
*/
protected function __construct(
Connection $conn,
$name,
Configuration $config,
EventManager $eventManager)
protected function __construct(Connection $conn, $name, Configuration $config, EventManager $eventManager)
{
$this->_conn = $conn;
$this->_name = $name;
......@@ -207,6 +205,7 @@ class EntityManager
/**
* Commits a running transaction.
*
* This causes a flush() of the EntityManager if the flush mode is set to
* AUTO or COMMIT.
*
......@@ -245,7 +244,7 @@ class EntityManager
}
/**
* Used to lazily create the id generator.
* Used to lazily create an ID generator.
*
* @param string $generatorType
* @return object
......@@ -281,7 +280,7 @@ class EntityManager
/**
* Detaches an entity from the manager. It's lifecycle is no longer managed.
*
* @param Doctrine\ORM\Entity $entity
* @param object $entity
* @return boolean
*/
public function detach($entity)
......@@ -337,6 +336,7 @@ class EntityManager
/**
* Finds an Entity by its identifier.
*
* This is just a convenient shortcut for getRepository($entityName)->find($id).
*
* @param string $entityName
......@@ -349,7 +349,7 @@ class EntityManager
}
/**
* Sets the flush mode.
* Sets the flush mode to use.
*
* @param string $flushMode
*/
......@@ -437,21 +437,21 @@ class EntityManager
* Refreshes the persistent state of the entity from the database,
* overriding any local changes that have not yet been persisted.
*
* @param Doctrine\ORM\Entity $entity
* @param object $entity
* @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),
true);
true);*/
}
/**
* Creates a copy of the given entity. Can create a shallow or a deep copy.
*
* @param Doctrine\ORM\Entity $entity The entity to copy.
* @return Doctrine\ORM\Entity The new entity.
* @param object $entity The entity to copy.
* @return object The new entity.
*/
public function copy($entity, $deep = false)
{
......@@ -561,16 +561,16 @@ class EntityManager
case Query::HYDRATE_OBJECT:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_ARRAY:
case Query::HYDRATE_ARRAY:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_SCALAR:
case Query::HYDRATE_SCALAR:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\ScalarHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_SINGLE_SCALAR:
case Query::HYDRATE_SINGLE_SCALAR:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\SingleScalarHydrator($this);
break;
case Doctrine_ORM_Query::HYDRATE_NONE:
case Query::HYDRATE_NONE:
$this->_hydrators[$hydrationMode] = new \Doctrine\ORM\Internal\Hydration\NoneHydrator($this);
break;
default:
......@@ -617,10 +617,7 @@ class EntityManager
* @param EventManager $eventManager The EventManager instance to use.
* @return EntityManager The created EntityManager.
*/
public static function create(
$conn,
$name,
Configuration $config = null,
public static function create($conn, $name, Configuration $config = null,
EventManager $eventManager = null)
{
if (is_array($conn)) {
......
......@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Export;
use Doctrine\ORM\EntityManager;
/**
* The ClassExporter can generate database schemas/structures from ClassMetadata
* class descriptors.
......@@ -41,25 +43,32 @@ class ClassExporter
private $_sm;
/** The EntityManager */
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->_sm = $em->getConnection()->getSchemaManager();
$this->_platform = $em->getConnection()->getDatabasePlatform();
}
/**
* Exports entity classes to a schema.
*
* 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.
* Exports entity classes to a database, according to the specified mappings.
*
* @param array $classes
* @return void
*/
public function exportClasses(array $classes)
{
//TODO: order them
$foreignKeyConstraints = array();
// First we create the tables
foreach ($classes as $class) {
$columns = array();
$options = array();
......@@ -70,92 +79,84 @@ class ClassExporter
$column['type'] = $mapping['type'];
$column['length'] = $mapping['length'];
$column['notnull'] = ! $mapping['nullable'];
if ($class->isIdentifier($fieldName)) {
$column['primary'] = true;
if ($class->isIdGeneratorIdentity()) {
$column['autoincrement'] = true;
}
}
$columns[$mapping['columnName']] = $column;
}
foreach ($class->getAssociationMappings() as $mapping) {
$foreignClass = $this->_em->getClassMetadata($mapping->getTargetEntityName());
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['name'] = $sourceColumn;
$column['type'] = $this->_em->getClassMetadata($mapping->getTargetEntityName())
->getTypeOfColumn($targetColumn);
$columns[$sourceColumn] = $column;
}
} else if ($mapping->isOneToMany() && $mapping->usesJoinTable()) {
$column['name'] = $joinColumn['name'];
$column['type'] = $foreignClass->getTypeOfColumn($joinColumn['referencedColumnName']);
$columns[$joinColumn['name']] = $column;
$constraint['local'][] = $joinColumn['name'];
$constraint['foreign'][] = $joinColumn['referencedColumnName'];
}
$foreignKeyConstraints[] = $constraint;
} else if ($mapping->isOneToMany() && $mapping->isOwningSide()) {
//... 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()) {
//... 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'];
}
}
$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;
}
$foreignKeyConstraints[] = $constraint2;
$classMetadata = $this->conn->getClassMetadata($name);
// 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;
$this->_sm->createTable($joinTable['name'], $joinTableColumns, array());
}
}
$data = $classMetadata->getExportableFormat();
$query = $this->conn->export->createTableSql($data['tableName'], $data['columns'], $data['options']);
if (is_array($query)) {
$sql = array_merge($sql, $query);
} else {
$sql[] = $query;
$this->_sm->createTable($class->getTableName(), $columns, $options);
}
if ($classMetadata->getAttribute(Doctrine::ATTR_EXPORT) & Doctrine::EXPORT_PLUGINS) {
$sql = array_merge($sql, $this->exportGeneratorsSql($classMetadata));
// Now create the foreign key constraints
if ($this->_platform->supportsForeignKeyConstraints()) {
foreach ($foreignKeyConstraints as $fkConstraint) {
$this->_sm->createForeignKey($fkConstraint['tableName'], $fkConstraint);
}
}
$sql = array_unique($sql);
rsort($sql);
return $sql;
}
}
<?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;
......
......@@ -21,6 +21,8 @@
namespace Doctrine\ORM\Mapping;
use Doctrine\ORM\Exceptions\MappingException;
/**
* Base class for association mappings.
*
......@@ -107,11 +109,11 @@ abstract class AssociationMapping
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.
......@@ -132,17 +134,17 @@ abstract class AssociationMapping
{
// Mandatory attributes for both sides
if ( ! isset($mapping['fieldName'])) {
throw Doctrine_MappingException::missingFieldName();
throw MappingException::missingFieldName();
}
$this->_sourceFieldName = $mapping['fieldName'];
if ( ! isset($mapping['sourceEntity'])) {
throw Doctrine_MappingException::missingSourceEntity($mapping['fieldName']);
throw MappingException::missingSourceEntity($mapping['fieldName']);
}
$this->_sourceEntityName = $mapping['sourceEntity'];
if ( ! isset($mapping['targetEntity'])) {
throw Doctrine_ORM_Exceptions_MappingException::missingTargetEntity($mapping['fieldName']);
throw MappingException::missingTargetEntity($mapping['fieldName']);
}
$this->_targetEntityName = $mapping['targetEntity'];
......@@ -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()
{
......@@ -316,36 +318,6 @@ abstract class AssociationMapping
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()
{
return false;
......
......@@ -22,6 +22,7 @@
namespace Doctrine\ORM\Mapping;
use \ReflectionClass;
use Doctrine\Common\DoctrineException;
/**
* A <tt>ClassMetadata</tt> instance holds all the information (metadata) of an entity and
......@@ -100,9 +101,18 @@ class ClassMetadata
*/
const ENTITY_TYPE_MAPPED_SUPERCLASS = 'mappedSuperclass';
/** The name of the entity class. */
/**
* The name of the entity class.
*/
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
* hierarchy. If the entity is not part of an inheritance hierarchy this is the same
......@@ -268,11 +278,16 @@ class ClassMetadata
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
......@@ -332,15 +347,16 @@ class ClassMetadata
protected $_reflectionProperties;
/**
* Initializes a new ClassMetadata instance that will hold the ORM metadata
* of the class with the given name.
* Initializes a new ClassMetadata instance that will hold the object-relational mapping
* metadata of the class with the given name.
*
* @param string $entityName Name of the entity class the new instance is used for.
*/
public function __construct($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->_reflectionClass = new ReflectionClass($entityName);
}
......@@ -383,7 +399,7 @@ class ClassMetadata
public function getSingleIdReflectionProperty()
{
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]];
}
......@@ -448,7 +464,6 @@ class ClassMetadata
if ($mapping !== false) {
return isset($mapping['unique']) && $mapping['unique'] == true;
}
return false;
}
......@@ -464,7 +479,6 @@ class ClassMetadata
if ($mapping !== false) {
return isset($mapping['notnull']) && $mapping['notnull'] == true;
}
return false;
}
......@@ -520,8 +534,8 @@ class ClassMetadata
*/
public function getInverseAssociationMapping($mappedByFieldName)
{
if ( ! isset($this->_associationMappings[$fieldName])) {
throw new Doctrine_Exception("Mapping not found: " . $fieldName);
if ( ! isset($this->_inverseMappings[$mappedByFieldName])) {
throw new DoctrineException("Mapping not found: " . $mappedByFieldName);
}
return $this->_inverseMappings[$mappedByFieldName];
}
......@@ -932,13 +946,13 @@ class ClassMetadata
}
/**
* getTableName
* Gets the name of the primary table.
*
* @return void
* @return string
*/
public function getTableName()
{
return $this->_tableName;
return $this->_primaryTable['name'];
}
public function getInheritedFields()
......@@ -1092,34 +1106,34 @@ class ClassMetadata
*/
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);
//return serialize($contents);
return "";
}*/
$this->_primaryTable = $primaryTableDefinition;
}
/**
* Reconstructs the metadata class from it's serialized representation.
* Gets the primary table definition.
*
* Part of the implementation of the Serializable interface.
*
* @param string $serialized The serialized metadata class.
* @see setPrimaryTable()
* @return array
*/
/*public function unserialize($serialized)
public function getPrimaryTable()
{
return true;
}*/
return $this->_primaryTable;
}
/**
* Checks whether the given type identifies an entity type.
......@@ -1168,12 +1182,14 @@ class ClassMetadata
* easier for the user.
*
* @param array $mapping
* @return unknown
* @todo Pass param by ref?
*/
private function _completeAssociationMapping(array $mapping)
{
$mapping['sourceEntity'] = $this->_entityName;
if (isset($mapping['targetEntity']) && strpos($mapping['targetEntity'], '\\') === false) {
$mapping['targetEntity'] = $this->_namespace . '\\' . $mapping['targetEntity'];
}
return $mapping;
}
......@@ -1260,7 +1276,7 @@ class ClassMetadata
/**
* Stores the association mapping.
*
* @param Doctrine_Association $assocMapping
* @param AssociationMapping $assocMapping
*/
private function _storeAssociationMapping(AssociationMapping $assocMapping)
{
......@@ -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.
*/
......@@ -1333,11 +1349,11 @@ class ClassMetadata
//Entity::TYPE_ENTITY
//Entity::TYPE_MAPPED_SUPERCLASS
//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.
*
* @param string $event The lifecycle event.
......@@ -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
* one will be overridden.
......
<?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;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Exceptions\MappingException;
/* Addendum annotation reflection extensions */
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.
......@@ -20,23 +40,31 @@ class AnnotationDriver
/**
* 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);
// Evaluate DoctrineEntity annotation
if (($entityAnnot = $annotClass->getAnnotation('DoctrineEntity')) === false) {
throw new MappingException("$className is no entity.");
}
$metadata->setCustomRepositoryClass($entityAnnot->repositoryClass);
if ($entityAnnot->tableName) {
$metadata->setTableName($entityAnnot->tableName);
// Evaluate DoctrineTable annotation
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')) {
$metadata->setInheritanceType($inheritanceTypeAnnot->value);
}
// Evaluate DoctrineDiscriminatorColumn annotation
if ($discrColumnAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorColumn')) {
$metadata->setDiscriminatorColumn(array(
'name' => $discrColumnAnnot->name,
......@@ -45,17 +73,38 @@ class AnnotationDriver
));
}
// Evaluate DoctrineDiscriminatorMap annotation
if ($discrValueAnnot = $annotClass->getAnnotation('DoctrineDiscriminatorMap')) {
$metadata->setDiscriminatorMap((array)$discrValueAnnot->value);
}
// Evaluate DoctrineSubClasses annotation
if ($subClassesAnnot = $annotClass->getAnnotation('DoctrineSubClasses')) {
$metadata->setSubclasses($subClassesAnnot->value);
}
// Evaluate annotations on properties/fields
foreach ($annotClass->getProperties() as $property) {
$mapping = array();
$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->type == null) {
throw new MappingException("Missing type on property " . $property->getName());
......@@ -72,7 +121,7 @@ class AnnotationDriver
$metadata->mapField($mapping);
} else if ($oneToOneAnnot = $property->getAnnotation('DoctrineOneToOne')) {
$mapping['targetEntity'] = $oneToOneAnnot->targetEntity;
$mapping['joinColumns'] = $oneToOneAnnot->joinColumns;
$mapping['joinColumns'] = $joinColumns;
$mapping['mappedBy'] = $oneToOneAnnot->mappedBy;
$mapping['cascade'] = $oneToOneAnnot->cascade;
$metadata->mapOneToOne($mapping);
......@@ -82,17 +131,26 @@ class AnnotationDriver
$mapping['cascade'] = $oneToManyAnnot->cascade;
$metadata->mapOneToMany($mapping);
} else if ($manyToOneAnnot = $property->getAnnotation('DoctrineManyToOne')) {
$mapping['joinColumns'] = $manyToOneAnnot->joinColumns;
$mapping['joinColumns'] = $joinColumns;
$mapping['targetEntity'] = $manyToOneAnnot->targetEntity;
$metadata->mapManyToOne($mapping);
} 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['joinColumns'] = $manyToManyAnnot->joinColumns;
$mapping['inverseJoinColumns'] = $manyToManyAnnot->inverseJoinColumns;
$mapping['joinTable'] = $manyToManyAnnot->joinTable;
$mapping['mappedBy'] = $manyToManyAnnot->mappedBy;
$metadata->mapManyToMany($mapping);
}
}
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
/* Annotations */
final class DoctrineEntity extends \Addendum\Annotation {
public $tableName;
public $repositoryClass;
public $inheritanceType;
}
final class DoctrineInheritanceType extends \Addendum\Annotation {}
final class DoctrineDiscriminatorColumn extends \Addendum\Annotation {
......@@ -24,11 +37,13 @@ final class DoctrineIdGenerator extends \Addendum\Annotation {}
final class DoctrineVersion extends \Addendum\Annotation {}
final class DoctrineJoinColumn extends \Addendum\Annotation {
public $name;
public $type;
public $length;
public $referencedColumnName;
public $unique = false;
public $nullable = true;
public $onDelete;
public $onUpdate;
}
final class DoctrineJoinColumns extends \Addendum\Annotation {}
final class DoctrineColumn extends \Addendum\Annotation {
public $type;
public $length;
......@@ -38,7 +53,6 @@ final class DoctrineColumn extends \Addendum\Annotation {
final class DoctrineOneToOne extends \Addendum\Annotation {
public $targetEntity;
public $mappedBy;
public $joinColumns;
public $cascade;
}
final class DoctrineOneToMany extends \Addendum\Annotation {
......@@ -48,15 +62,25 @@ final class DoctrineOneToMany extends \Addendum\Annotation {
}
final class DoctrineManyToOne extends \Addendum\Annotation {
public $targetEntity;
public $joinColumns;
public $cascade;
}
final class DoctrineManyToMany extends \Addendum\Annotation {
public $targetEntity;
public $joinColumns;
public $inverseJoinColumns;
public $joinTable;
public $mappedBy;
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
/*
* $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
* entities.
*
* @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).
*
* @var string
* The key columns of the source table.
*/
private $_associationClass;
private $_sourceKeyColumns = array();
/** The field in the source table that corresponds to the key in the relation table */
protected $_sourceKeyColumns;
/** The field in the target table that corresponds to the key in the relation table */
protected $_targetKeyColumns;
/**
* The key columns of the target table.
*/
private $_targetKeyColumns = array();
/** 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.
* Creates a new ManyToManyMapping.
* Initializes a new ManyToManyMapping.
*
* @param array $mapping The mapping info.
* @param array $mapping The mapping information.
*/
public function __construct(array $mapping)
{
......@@ -50,38 +71,63 @@ class Doctrine_ORM_Mapping_ManyToManyMapping extends Doctrine_ORM_Mapping_Associ
protected function _validateAndCompleteMapping(array $mapping)
{
parent::_validateAndCompleteMapping($mapping);
if ($this->isOwningSide()) {
// many-many owning MUST have a join table
// owning side MUST have a join table
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
$this->_associationClass = isset($mapping['associationClass']) ?
$mapping['associationClass'] : null;
public function getSourceToRelationKeyColumns()
{
return $this->_sourceToRelationKeyColumns;
}
public function getTargetToRelationKeyColumns()
{
return $this->_targetToRelationKeyColumns;
}
/**
* Whether the mapping uses an association class for the intermediary
* table.
*
* @return boolean
*/
public function usesAssociationClass()
public function getSourceKeyColumns()
{
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 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Mapping;
......@@ -54,10 +54,9 @@ class OneToManyMapping extends AssociationMapping
protected $_deleteOrphans = false;
/**
* Constructor.
* Creates a new OneToManyMapping.
* Initializes a new OneToManyMapping.
*
* @param array $mapping The mapping info.
* @param array $mapping The mapping information.
*/
public function __construct(array $mapping)
{
......
......@@ -35,21 +35,28 @@ class OneToOneMapping extends AssociationMapping
* i.e. source.id (pk) => target.user_id (fk).
* Reverse mapping of _targetToSourceKeyColumns.
*/
protected $_sourceToTargetKeyColumns = array();
private $_sourceToTargetKeyColumns = array();
/**
* Maps the target primary/foreign key columns to the source foreign/primary key columns.
* i.e. target.user_id (fk) => source.id (pk).
* Reverse mapping of _sourceToTargetKeyColumns.
*/
protected $_targetToSourceKeyColumns = array();
private $_targetToSourceKeyColumns = array();
/**
* Whether to delete orphaned elements (when nulled out, i.e. $foo->other = null)
*
* @var boolean
*/
protected $_deleteOrphans = false;
private $_deleteOrphans = false;
/**
* The join column definitions.
*
* @var array
*/
private $_joinColumns = array();
/**
* Creates a new OneToOneMapping.
......@@ -74,9 +81,12 @@ class OneToOneMapping extends AssociationMapping
if ($this->isOwningSide()) {
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);
}
......@@ -86,6 +96,16 @@ class OneToOneMapping extends AssociationMapping
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.
*
......
<?php
/*
* $Id: Collection.php 4930 2008-09-12 10:40:23Z romanb $
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
......@@ -110,6 +110,12 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*/
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;
/**
......@@ -181,11 +187,21 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
*
* @return object
*/
public function _getOwner()
public function getOwner()
{
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.
*
......@@ -251,8 +267,9 @@ final class PersistentCollection extends \Doctrine\Common\Collections\Collection
/**
* Adds all entities of the other collection to this collection.
*
* @param unknown_type $otherCollection
* @param object $otherCollection
* @todo Impl
* @override
*/
public function addAll($otherCollection)
{
......
<?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;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\PersistentCollection;
/**
* Base class for all collection persisters.
*
* @since 2.0
* @author Roman Borschel <roman@code-factory.org>
*/
abstract class AbstractCollectionPersister
{
protected $_em;
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)
{
$this->_em = $em;
$this->_uow = $em->getUnitOfWork();
$this->_conn = $em->getConnection();
}
......@@ -51,7 +83,7 @@ abstract class AbstractCollectionPersister
$sql = $this->_getDeleteRowSql($coll);
$uow = $this->_em->getUnitOfWork();
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
*/
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.
*
......
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\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
*
* @param <type> $coll
* @override
* @todo Identifier quoting.
* @see _getDeleteRowSqlParameters()
*/
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;
*/
class OneToManyPersister extends AbstractCollectionPersister
{
/**
* {@inheritdoc}
*
* @param <type> $coll
* @return <type>
* @override
*/
protected function _getDeleteRowSql(PersistentCollection $coll)
{
$mapping = $coll->getMapping();
......@@ -33,6 +39,18 @@ class OneToManyPersister extends AbstractCollectionPersister
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()
{
return "UPDATE xxx SET foreign_key = yyy WHERE foreign_key = zzz";
......
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM;
......@@ -584,13 +584,13 @@ class UnitOfWork
$oid = spl_object_hash($entity);
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])) {
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])) {
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;
......@@ -968,8 +968,7 @@ class UnitOfWork
$this->registerNew($entity);
break;
case self::STATE_DETACHED:
//exception?
throw new Doctrine_Exception("Behavior of save() for a detached entity "
throw new DoctrineException("Behavior of save() for a detached entity "
. "is not yet defined.");
case self::STATE_DELETED:
// entity becomes managed again
......@@ -983,7 +982,7 @@ class UnitOfWork
break;
default:
//TODO: throw UnitOfWorkException::invalidEntityState()
throw new Doctrine_Exception("Encountered invalid entity state.");
throw new DoctrineException("Encountered invalid entity state.");
}
$this->_cascadeSave($entity, $visited, $insertNow);
}
......
......@@ -10,7 +10,8 @@ namespace Doctrine\Tests\Models\CMS;
* Description of CmsAddress
*
* @author robo
* @DoctrineEntity(tableName="cms_addresses")
* @DoctrineEntity
* @DoctrineTable(name="cms_addresses")
*/
class CmsAddress
{
......@@ -33,9 +34,8 @@ class CmsAddress
*/
public $city;
/**
* @DoctrineOneToOne(
targetEntity="Doctrine\Tests\Models\CMS\CmsUser",
joinColumns={"user_id" = "id"})
* @DoctrineOneToOne(targetEntity="CmsUser")
* @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
*/
public $user;
}
......
......@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS;
/**
* @DoctrineEntity(tableName="cms_articles")
* @DoctrineEntity
* @DoctrineTable(name="cms_articles")
*/
class CmsArticle
{
......@@ -22,12 +23,12 @@ class CmsArticle
*/
public $text;
/**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsUser",
joinColumns={"user_id" = "id"})
* @DoctrineManyToOne(targetEntity="CmsUser")
* @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
*/
public $user;
/**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsComment", mappedBy="article")
* @DoctrineOneToMany(targetEntity="CmsComment", mappedBy="article")
*/
public $comments;
}
......@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS;
/**
* @DoctrineEntity(tableName="cms_comments")
* @DoctrineEntity
* @DoctrineTable(name="cms_comments")
*/
class CmsComment
{
......@@ -22,8 +23,8 @@ class CmsComment
*/
public $text;
/**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsArticle",
joinColumns={"article_id" = "id"})
* @DoctrineManyToOne(targetEntity="CmsArticle")
* @DoctrineJoinColumn(name="article_id", referencedColumnName="id")
*/
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 @@
namespace Doctrine\Tests\Models\CMS;
/**
* @DoctrineEntity(tableName="cms_phonenumbers")
* @DoctrineEntity
* @DoctrineTable(name="cms_phonenumbers")
*/
class CmsPhonenumber
{
......@@ -13,8 +14,8 @@ class CmsPhonenumber
*/
public $phonenumber;
/**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsUser",
joinColumns={"user_id" = "id"})
* @DoctrineManyToOne(targetEntity="CmsUser")
* @DoctrineJoinColumn(name="user_id", referencedColumnName="id")
*/
public $user;
......
......@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\CMS;
/**
* @DoctrineEntity(tableName="cms_users")
* @DoctrineEntity
* @DoctrineTable(name="cms_users")
*/
class CmsUser
{
......@@ -26,19 +27,24 @@ class CmsUser
*/
public $name;
/**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsPhonenumber",
mappedBy="user", cascade={"save", "delete"})
* @DoctrineOneToMany(targetEntity="CmsPhonenumber", mappedBy="user", cascade={"save", "delete"})
*/
public $phonenumbers;
/**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\CMS\CmsArticle", mappedBy="user")
* @DoctrineOneToMany(targetEntity="CmsArticle", mappedBy="user")
*/
public $articles;
/**
* @DoctrineOneToOne(targetEntity="Doctrine\Tests\Models\CMS\CmsAddress", mappedBy="user",
cascade={"save"})
* @DoctrineOneToOne(targetEntity="CmsAddress", mappedBy="user", cascade={"save"})
*/
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.
......
......@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\Forum;
/**
* @DoctrineEntity(tableName="forum_avatars")
* @DoctrineEntity
* @DoctrineTable(name="forum_avatars")
*/
class ForumAvatar
{
......
......@@ -7,6 +7,7 @@ namespace Doctrine\Tests\Models\Forum;
*
* @author robo
* @DoctrineEntity
* @DoctrineTable(name="forum_boards")
*/
class ForumBoard
{
......@@ -20,8 +21,8 @@ class ForumBoard
*/
public $position;
/**
* @DoctrineManyToOne(targetEntity="Doctrine\Tests\Models\Forum\ForumCategory",
joinColumns={"category_id" = "id"})
* @DoctrineManyToOne(targetEntity="ForumCategory")
* @DoctrineJoinColumn(name="category_id", referencedColumnName="id")
*/
public $category;
}
......@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum;
/**
* @DoctrineEntity
* @DoctrineTable(name="forum_categories")
*/
class ForumCategory
{
......@@ -21,7 +22,7 @@ class ForumCategory
*/
public $name;
/**
* @DoctrineOneToMany(targetEntity="Doctrine\Tests\Models\Forum\ForumBoard", mappedBy="category")
* @DoctrineOneToMany(targetEntity="ForumBoard", mappedBy="category")
*/
public $boards;
......
......@@ -4,6 +4,7 @@ namespace Doctrine\Tests\Models\Forum;
/**
* @DoctrineEntity
* @DoctrineTable(name="forum_entries")
*/
class ForumEntry
{
......
......@@ -3,7 +3,8 @@
namespace Doctrine\Tests\Models\Forum;
/**
* @DoctrineEntity(tableName="forum_users")
* @DoctrineEntity
* @DoctrineTable(name="forum_users")
* @DoctrineInheritanceType("joined")
* @DoctrineDiscriminatorColumn(name="dtype", type="varchar", length=20)
* @DoctrineDiscriminatorMap({
......@@ -24,10 +25,8 @@ class ForumUser
*/
public $username;
/**
* @DoctrineOneToOne(
targetEntity="Doctrine\Tests\Models\Forum\ForumAvatar",
joinColumns={"avatar_id" = "id"},
cascade={"save"})
* @DoctrineOneToOne(targetEntity="ForumAvatar", cascade={"save"})
* @DoctrineJoinColumn(name="avatar_id", referencedColumnName="id")
*/
public $avatar;
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ class OneToOneMappingTest extends \Doctrine\Tests\OrmTestCase
$owningSideMapping = array(
'fieldName' => 'address',
'targetEntity' => 'Address',
'joinColumns' => array('address_id' => 'id'),
'joinColumns' => array(array('name' => 'address_id', 'referencedColumnName' => 'id')),
'sourceEntity' => 'Person', // This is normally filled by ClassMetadata
);
......
......@@ -44,7 +44,6 @@ class ClassMetadataTest extends \Doctrine\Tests\OrmTestCase
$this->assertEquals(1, count($cm->getAssociationMappings()));
$oneOneMapping = $cm->getAssociationMapping('phonenumbers');
$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