Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The schema tool now doesn't add a foreign constraint when subclassess of... #440

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 38 additions & 12 deletions lib/Doctrine/ORM/Tools/SchemaTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
* @author Jonathan Wage <[email protected]>
* @author Roman Borschel <[email protected]>
* @author Benjamin Eberlei <[email protected]>
* @author Stefano Rodriguez <[email protected]>
*/
class SchemaTool
{
Expand Down Expand Up @@ -140,6 +141,9 @@ public function getSchemaFromMetadata(array $classes)
$metadataSchemaConfig->setExplicitForeignKeyIndexes(false);
$schema = new Schema(array(), array(), $metadataSchemaConfig);

$addedFks = array();
$blacklistedFks = array();

foreach ($classes as $class) {
if ($this->processingNotRequired($class, $processedClasses)) {
continue;
Expand All @@ -150,7 +154,7 @@ public function getSchemaFromMetadata(array $classes)

if ($class->isInheritanceTypeSingleTable()) {
$columns = $this->_gatherColumns($class, $table);
$this->_gatherRelationsSql($class, $table, $schema);
$this->_gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);

// Add the discriminator column
$this->addDiscriminatorColumnDefinition($class, $table);
Expand All @@ -164,7 +168,7 @@ public function getSchemaFromMetadata(array $classes)
foreach ($class->subClasses as $subClassName) {
$subClass = $this->em->getClassMetadata($subClassName);
$this->_gatherColumns($subClass, $table);
$this->_gatherRelationsSql($subClass, $table, $schema);
$this->_gatherRelationsSql($subClass, $table, $schema, $addedFks, $blacklistedFks);
$processedClasses[$subClassName] = true;
}
} else if ($class->isInheritanceTypeJoined()) {
Expand All @@ -181,7 +185,7 @@ public function getSchemaFromMetadata(array $classes)
}
}

$this->_gatherRelationsSql($class, $table, $schema);
$this->_gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);

// Add the discriminator column only to the root table
if ($class->name == $class->rootEntityName) {
Expand Down Expand Up @@ -210,7 +214,7 @@ public function getSchemaFromMetadata(array $classes)
throw ORMException::notSupported();
} else {
$this->_gatherColumns($class, $table);
$this->_gatherRelationsSql($class, $table, $schema);
$this->_gatherRelationsSql($class, $table, $schema, $addedFks, $blacklistedFks);
}

$pkColumns = array();
Expand Down Expand Up @@ -415,9 +419,11 @@ private function _gatherColumn($class, array $mapping, $table)
* @param ClassMetadata $class
* @param \Doctrine\DBAL\Schema\Table $table
* @param \Doctrine\DBAL\Schema\Schema $schema
* @param array $addedFks
* @param array $blacklistedFks
* @return void
*/
private function _gatherRelationsSql($class, $table, $schema)
private function _gatherRelationsSql($class, $table, $schema, &$addedFks, &$blacklistedFks)
{
foreach ($class->associationMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
Expand All @@ -429,7 +435,7 @@ private function _gatherRelationsSql($class, $table, $schema)
if ($mapping['type'] & ClassMetadata::TO_ONE && $mapping['isOwningSide']) {
$primaryKeyColumns = $uniqueConstraints = array(); // PK is unnecessary for this relation-type

$this->_gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints);
$this->_gatherRelationJoinColumns($mapping['joinColumns'], $table, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints, $addedFks, $blacklistedFks);

foreach($uniqueConstraints as $indexName => $unique) {
$table->addUniqueIndex($unique['columns'], is_numeric($indexName) ? null : $indexName);
Expand All @@ -446,10 +452,10 @@ private function _gatherRelationsSql($class, $table, $schema)
$primaryKeyColumns = $uniqueConstraints = array();

// Build first FK constraint (relation table => source table)
$this->_gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $uniqueConstraints);
$this->_gatherRelationJoinColumns($joinTable['joinColumns'], $theJoinTable, $class, $mapping, $primaryKeyColumns, $uniqueConstraints, $addedFks, $blacklistedFks);

// Build second FK constraint (relation table => target table)
$this->_gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints);
$this->_gatherRelationJoinColumns($joinTable['inverseJoinColumns'], $theJoinTable, $foreignClass, $mapping, $primaryKeyColumns, $uniqueConstraints, $addedFks, $blacklistedFks);

$theJoinTable->setPrimaryKey($primaryKeyColumns);

Expand Down Expand Up @@ -503,8 +509,10 @@ private function getDefiningClass($class, $referencedColumnName)
* @param array $mapping
* @param array $primaryKeyColumns
* @param array $uniqueConstraints
* @param array $addedFks
* @param array $blacklistedFks
*/
private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class, $mapping, &$primaryKeyColumns, &$uniqueConstraints)
private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class, $mapping, &$primaryKeyColumns, &$uniqueConstraints, &$addedFks, &$blacklistedFks)
{
$localColumns = array();
$foreignColumns = array();
Expand Down Expand Up @@ -565,9 +573,27 @@ private function _gatherRelationJoinColumns($joinColumns, $theJoinTable, $class,
}
}

$theJoinTable->addUnnamedForeignKeyConstraint(
$foreignTableName, $localColumns, $foreignColumns, $fkOptions
);
$compositeName = $theJoinTable->getName().'.'.implode('', $localColumns);
if (isset($addedFks[$compositeName])
&& ($foreignTableName != $addedFks[$compositeName]['foreignTableName']
|| 0 < count(array_diff($foreignColumns, $addedFks[$compositeName]['foreignColumns'])))
) {
foreach ($theJoinTable->getForeignKeys() as $fkName => $key) {
if (0 === count(array_diff($key->getLocalColumns(), $localColumns))
&& (($key->getForeignTableName() != $foreignTableName)
|| 0 < count(array_diff($key->getForeignColumns(), $foreignColumns)))
) {
$theJoinTable->removeForeignKey($fkName);
break;
}
}
$blacklistedFks[$compositeName] = true;
} elseif (!isset($blacklistedFks[$compositeName])) {
$addedFks[$compositeName] = array('foreignTableName' => $foreignTableName, 'foreignColumns' => $foreignColumns);
$theJoinTable->addUnnamedForeignKeyConstraint(
$foreignTableName, $localColumns, $foreignColumns, $fkOptions
);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Doctrine\Tests\Models\SingleTableInheritanceType;

/**
* @Table(name="structures")
* @Entity
*/
class Structure
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @Column(type="string", length=32, nullable=true)
*/
protected $name;
}
124 changes: 124 additions & 0 deletions tests/Doctrine/Tests/Models/SingleTableInheritanceType/User.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<?php

namespace Doctrine\Tests\Models\SingleTableInheritanceType;

use Doctrine\Common\Collections\ArrayCollection;

/**
* @Table(name="users")
* @Entity
*/
class User
{
/**
* @Id
* @Column(type="integer")
* @GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* @Column(type="string", length=32, nullable=true)
*/
protected $name;

/**
* @var ArrayCollection $followedUsers
* @OneToMany(targetEntity="UserFollowedUser", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
*/
protected $followedUsers;

/**
* @var ArrayCollection $followedStructures
* @OneToMany(targetEntity="UserFollowedStructure", mappedBy="user", cascade={"persist"}, orphanRemoval=true)
*/
protected $followedStructures;

public function __construct()
{
$this->followedUsers = new ArrayCollection();
$this->followedStructures = new ArrayCollection();
}

/*
* Remove followers
*
* @param UserFollowedUser $followers
*/
private function removeFollower(UserFollowedUser $followers)
{
$this->followers->removeElement($followers);
}

/**
* Add followedUsers
*
* @param UserFollowedUser $followedUsers
* @return User
*/
public function addFollowedUser(UserFollowedUser $followedUsers)
{
$this->followedUsers[] = $followedUsers;

return $this;
}

/**
* Remove followedUsers
*
* @param UserFollowedUser $followedUsers
* @return User
*/
public function removeFollowedUser(UserFollowedUser $followedUsers)
{
$this->followedUsers->removeElement($followedUsers);

return $this;
}

/**
* Get followedUsers
*
* @return Doctrine\Common\Collections\Collection
*/
public function getFollowedUsers()
{
return $this->followedUsers;
}

/**
* Add followedStructures
*
* @param UserFollowedStructure $followedStructures
* @return User
*/
public function addFollowedStructure(UserFollowedStructure $followedStructures)
{
$this->followedStructures[] = $followedStructures;

return $this;
}

/**
* Remove followedStructures
*
* @param UserFollowedStructure $followedStructures
* @return User
*/
public function removeFollowedStructure(UserFollowedStructure $followedStructures)
{
$this->followedStructures->removeElement($followedStructures);

return $this;
}

/**
* Get followedStructures
*
* @return Doctrine\Common\Collections\Collection
*/
public function getFollowedStructures()
{
return $this->followedStructures;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Doctrine\Tests\Models\SingleTableInheritanceType;

/**
* @Entity
* @Table(name="users_followed_objects")
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="object_type", type="smallint")
* @DiscriminatorMap({4 = "UserFollowedUser", 3 = "UserFollowedStructure"})
*/
abstract class UserFollowedObject
{
/**
* @var integer $id
*
* @Column(name="id", type="integer")
* @Id
* @GeneratedValue(strategy="AUTO")
*/
protected $id;

/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Doctrine\Tests\Models\SingleTableInheritanceType;

/**
* @Entity
*/
class UserFollowedStructure extends UserFollowedObject
{
/**
* @ManyToOne(targetEntity="User", inversedBy="followedStructures")
* @JoinColumn(name="user_id", referencedColumnName="id", nullable=false)
* @var User $user
*/
protected $user;

/**
* @ManyToOne(targetEntity="Structure")
* @JoinColumn(name="object_id", referencedColumnName="id", nullable=false)
* @var Structure $followedStructure
*/
private $followedStructure;

/**
* Construct a UserFollowedStructure entity
*
* @param User $user
* @param Structure $followedStructure
*/
public function __construct(User $user, Structure $followedStructure)
{
$this->user = $user;
$this->followedStructure = $followedStructure;
}

/**
*
* @return User
*/
public function getUser()
{
return $this->user;
}

/**
* Gets followed structure
*
* @return Structure
*/
public function getFollowedStructure()
{
return $this->followedStructure;
}
}
Loading