Skip to content

Commit

Permalink
Fixed #603
Browse files Browse the repository at this point in the history
  • Loading branch information
MArcJ committed Feb 15, 2013
1 parent 7dee9ea commit 288e91d
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 13 deletions.
37 changes: 26 additions & 11 deletions generator/lib/builder/om/PHP5ObjectBuilder.php
Expand Up @@ -3793,7 +3793,7 @@ public function get$relCol(\$criteria = null, PropelPDO \$con = null)
"; ";
} // addRefererGet() } // addRefererGet()


protected function addRefFKSet(&$script, $refFK) protected function addRefFKSet(&$script, ForeignKey $refFK)
{ {
$relatedName = $this->getRefFKPhpNameAffix($refFK, $plural = true); $relatedName = $this->getRefFKPhpNameAffix($refFK, $plural = true);
$relatedObjectClassName = $this->getRefFKPhpNameAffix($refFK, $plural = false); $relatedObjectClassName = $this->getRefFKPhpNameAffix($refFK, $plural = false);
Expand Down Expand Up @@ -3824,8 +3824,22 @@ public function set{$relatedName}(PropelCollection \${$inputCollection}, PropelP
{ {
\${$inputCollection}ToDelete = \$this->get{$relatedName}(new Criteria(), \$con)->diff(\${$inputCollection}); \${$inputCollection}ToDelete = \$this->get{$relatedName}(new Criteria(), \$con)->diff(\${$inputCollection});
\$this->{$inputCollection}ScheduledForDeletion = unserialize(serialize(\${$inputCollection}ToDelete)); ";

if ($refFK->isAtLeastOneLocalPrimaryKey()){
$script .= "
//since at least one column in the foreign key is at the same time a PK
//we can not just set a PK to NULL in the lines below. We have to store
//a backup of all values, so we are able to manipulate these items based on the onDelete value later.
\$this->{$inputCollection}ScheduledForDeletion = clone \${$inputCollection}ToDelete;
";
} else {
$script .= "
\$this->{$inputCollection}ScheduledForDeletion = \${$inputCollection}ToDelete;
";
}


$script .= "
foreach (\${$inputCollection}ToDelete as \${$inputCollectionEntry}Removed) { foreach (\${$inputCollection}ToDelete as \${$inputCollectionEntry}Removed) {
\${$inputCollectionEntry}Removed->set{$relCol}(null); \${$inputCollectionEntry}Removed->set{$relCol}(null);
} }
Expand Down Expand Up @@ -4076,7 +4090,7 @@ protected function addCrossFkScheduledForDeletion(&$script, $refFK, $crossFK)
"; ";
} }


protected function addRefFkScheduledForDeletion(&$script, $refFK) protected function addRefFkScheduledForDeletion(&$script, ForeignKey $refFK)
{ {
$relatedName = $this->getRefFKPhpNameAffix($refFK, $plural = true); $relatedName = $this->getRefFKPhpNameAffix($refFK, $plural = true);


Expand All @@ -4089,22 +4103,23 @@ protected function addRefFkScheduledForDeletion(&$script, $refFK)


$queryClassName = $this->getNewStubQueryBuilder($refFK->getTable())->getClassname(); $queryClassName = $this->getNewStubQueryBuilder($refFK->getTable())->getClassname();


$localColumn = $refFK->getLocalColumn();

$script .= " $script .= "
if (\$this->{$lowerRelatedName}ScheduledForDeletion !== null) { if (\$this->{$lowerRelatedName}ScheduledForDeletion !== null) {
if (!\$this->{$lowerRelatedName}ScheduledForDeletion->isEmpty()) {"; if (!\$this->{$lowerRelatedName}ScheduledForDeletion->isEmpty()) {";
if (!$refFK->isComposite() && !$localColumn->isNotNull()) {

if ($refFK->getOnDelete() == ForeignKey::CASCADE) {
$script .= "
//the foreign key is flagged as `CASCADE`, so we delete the items
$queryClassName::create()
->filterByPrimaryKeys(\$this->{$lowerRelatedName}ScheduledForDeletion->getPrimaryKeys(false))
->delete(\$con);";
} else {
$script .= " $script .= "
foreach (\$this->{$lowerRelatedName}ScheduledForDeletion as \${$lowerSingleRelatedName}) { foreach (\$this->{$lowerRelatedName}ScheduledForDeletion as \${$lowerSingleRelatedName}) {
// need to save related object because we set the relation to null // need to save related object because we set the relation to null
\${$lowerSingleRelatedName}->save(\$con); \${$lowerSingleRelatedName}->save(\$con);
}"; }";
} else {
$script .= "
$queryClassName::create()
->filterByPrimaryKeys(\$this->{$lowerRelatedName}ScheduledForDeletion->getPrimaryKeys(false))
->delete(\$con);";
} }
$script .= " $script .= "
\$this->{$lowerRelatedName}ScheduledForDeletion = null; \$this->{$lowerRelatedName}ScheduledForDeletion = null;
Expand Down
60 changes: 58 additions & 2 deletions generator/lib/model/ForeignKey.php
Expand Up @@ -529,7 +529,7 @@ public function isLocalColumnsRequired()
/** /**
* Whether this foreign key is also the primary key of the foreign table. * Whether this foreign key is also the primary key of the foreign table.
* *
* @return boolean * @return boolean Returns true if all columns inside this foreign key are primary keys of the foreign table
*/ */
public function isForeignPrimaryKey() public function isForeignPrimaryKey()
{ {
Expand All @@ -550,6 +550,44 @@ public function isForeignPrimaryKey()
!array_diff($foreignPKCols, $foreignCols)); !array_diff($foreignPKCols, $foreignCols));
} }


/**
* Whether at least one foreign column is also the primary key of the foreign table.
*
* @return boolean True if there is at least one column that is a primary key of the foreign table
*/
public function isAtLeastOneForeignPrimaryKey()
{
$cols = $this->getForeignPrimaryKeys();

return count($cols) !== 0;
}

/**
* Returns all foreign columns which are also a primary key of the foreign table.
*
* @return array Column[]
*/
public function getForeignPrimaryKeys()
{

$lfmap = $this->getLocalForeignMapping();
$foreignTable = $this->getForeignTable();

$foreignPKCols = array();
foreach ($foreignTable->getPrimaryKey() as $fPKCol) {
$foreignPKCols[$fPKCol->getName()] = true;
}

$foreignCols = array();
foreach ($this->getLocalColumns() as $colName) {
if ($foreignPKCols[$lfmap[$colName]]) {
$foreignCols[] = $foreignTable->getColumn($lfmap[$colName]);
}
}

return $foreignCols;
}

/** /**
* Whether this foreign key relies on more than one column binding * Whether this foreign key relies on more than one column binding
* *
Expand All @@ -563,7 +601,7 @@ public function isComposite()
/** /**
* Whether this foreign key is also the primary key of the local table. * Whether this foreign key is also the primary key of the local table.
* *
* @return boolean * @return boolean True if all local columns are at the same time a primary key
*/ */
public function isLocalPrimaryKey() public function isLocalPrimaryKey()
{ {
Expand All @@ -580,6 +618,24 @@ public function isLocalPrimaryKey()
!array_diff($localPKCols, $localCols)); !array_diff($localPKCols, $localCols));
} }


/**
* Whether at least one local column is also a primary key.
*
* @return boolean True if there is at least one column that is a primary key
*/
public function isAtLeastOneLocalPrimaryKey()
{
$localCols = $this->getLocalColumnObjects();

foreach ($localCols as $localCol){
if ($this->getTable()->getColumn($localCol->getName())->isPrimaryKey()){
return true;
}
}

return false;
}

/** /**
* Set whether this foreign key should have its creation sql generated. * Set whether this foreign key should have its creation sql generated.
* @param boolean $v Value to assign to skipSql. * @param boolean $v Value to assign to skipSql.
Expand Down
10 changes: 10 additions & 0 deletions runtime/lib/collection/PropelCollection.php
Expand Up @@ -576,6 +576,16 @@ public function __toString()
return (string) $this->exportTo(constant($this->getPeerClass() . '::DEFAULT_STRING_FORMAT')); return (string) $this->exportTo(constant($this->getPeerClass() . '::DEFAULT_STRING_FORMAT'));
} }


/**
* Creates clones of the containing data.
*/
public function __clone()
{
foreach ($this as $key => $obj) {
$this[$key] = clone $obj;
}
}

/** /**
* Get an array representation of the collection * Get an array representation of the collection
* Each object is turned into an array and the result is returned * Each object is turned into an array and the result is returned
Expand Down
@@ -0,0 +1,215 @@
<?php

/*
* $Id$
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/

/**
* Tests for More relations
*
* @author MArc J. Schmidt
* @version $Revision$
* @package generator.builder.om
*/
class GeneratedObjectMoreRelationTest extends PHPUnit_Framework_TestCase
{

/**
* Setup schema und some default data
*/
public function setUp()
{
parent::setUp();

if (!class_exists('MoreRelationTest\Page')) {
$schema = <<<EOF
<database name="more_relation_test" namespace="MoreRelationTest">
<table name="more_relation_test_page" phpName="Page">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" size="100" primaryString="true" />
</table>
<table name="more_relation_test_content" phpName="Content">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" size="100" />
<column name="content" type="LONGVARCHAR" required="false" />
<column name="page_id" type="INTEGER" required="false" />
<foreign-key foreignTable="more_relation_test_page" onDelete="cascade">
<reference local="page_id" foreign="id"/>
</foreign-key>
</table>
<table name="more_relation_test_comment" phpName="Comment">
<column name="user_id" required="true" primaryKey="true" type="INTEGER" />
<column name="page_id" required="true" primaryKey="true" type="INTEGER" />
<column name="comment" type="VARCHAR" size="100" />
<foreign-key foreignTable="more_relation_test_page" onDelete="cascade">
<reference local="page_id" foreign="id"/>
</foreign-key>
</table>
<table name="more_relation_test_content_comment" phpName="ContentComment">
<column name="id" required="true" autoIncrement="true" primaryKey="true" type="INTEGER" />
<column name="content_id" type="INTEGER" />
<column name="comment" type="VARCHAR" size="100" />
<foreign-key foreignTable="more_relation_test_content" onDelete="setnull">
<reference local="content_id" foreign="id"/>
</foreign-key>
</table>
</database>
EOF;

$builder = new PropelQuickBuilder();
$builder->setSchema($schema);
$builder->build();
}

\MoreRelationTest\ContentCommentPeer::doDeleteAll();
\MoreRelationTest\ContentPeer::doDeleteAll();
\MoreRelationTest\CommentPeer::doDeleteAll();
\MoreRelationTest\PagePeer::doDeleteAll();

for($i=1;$i<=2;$i++){

$page = new \MoreRelationTest\Page();

$page->setTitle('Page '.$i);
for($j=1;$j<=3;$j++){

$content = new \MoreRelationTest\Content();
$content->setTitle('Content '.$j);
$content->setContent(str_repeat('Content', $j));
$page->addContent($content);

$comment = new \MoreRelationTest\Comment();
$comment->setUserId($j);
$comment->setComment(str_repeat('Comment', $j));
$page->addComment($comment);

$comment = new \MoreRelationTest\ContentComment();
$comment->setContentId($i*$j);
$comment->setComment(str_repeat('Comment-'.$j.', ', $j));
$content->addContentComment($comment);

}

$page->save();
}

}

/**
* Composite PK deletion of a 1-to-n relation through set<RelationName>() and remove<RelationName>()
* where the PK is at the same time a FK.
*/
public function testCommentsDeletion(){

$commentCollection = new PropelObjectCollection();
$commentCollection->setModel('MoreRelationTest\\Comment');

$comment = new \MoreRelationTest\Comment();
$comment->setComment('I should be alone :-(');
$comment->setUserId(123);

$commentCollection[] = $comment;

$page = \MoreRelationTest\PageQuery::create()->findOne();
$id = $page->getId();

$count = \MoreRelationTest\CommentQuery::create()->filterByPageId($id)->count();
$this->assertEquals(3, $count, 'We created for each page 3 comments.');

$page->setComments($commentCollection);
$page->save();

$count = \MoreRelationTest\CommentQuery::create()->filterByPageId($id)->count();
$this->assertEquals(1, $count, 'We assigned a collection of only one item.');

$count = \MoreRelationTest\CommentQuery::create()->filterByPageId(NULL)->count();
$this->assertEquals(0, $count, 'There should be no unassigned comment.');

$page->removeComment($comment);
$page->save();

$count = \MoreRelationTest\CommentQuery::create()->filterByPageId($id)->count();
$this->assertEquals(0, $count, 'We assigned a collection of only one item.');

$count = \MoreRelationTest\CommentQuery::create()->filterByPageId(NULL)->count();
$this->assertEquals(0, $count, 'There should be no unassigned comment.');

}

/**
* Deletion of a 1-to-n relation through set<RelationName>()
* with onDelete=setnull
*/
public function testContentCommentDeletion(){

$commentCollection = new PropelObjectCollection();
$commentCollection->setModel('MoreRelationTest\\ContentComment');

$comment = new \MoreRelationTest\ContentComment();
$comment->setComment('I\'m Mario');
$commentCollection[] = $comment;

$comment2 = new \MoreRelationTest\ContentComment();
$comment2->setComment('I\'m Mario\'s friend');
$commentCollection[] = $comment2;

$content = \MoreRelationTest\ContentQuery::create()->findOne();
$id = $content->getId();

$count = \MoreRelationTest\ContentCommentQuery::create()->filterByContentId($id)->count();
$this->assertEquals(1, $count, 'We created for each page 1 comments.');

$content->setContentComments($commentCollection);
$content->save();

unset($content);

$count = \MoreRelationTest\ContentCommentQuery::create()->filterByContentId($id)->count();
$this->assertEquals(2, $count, 'We assigned a collection of two items.');

$count = \MoreRelationTest\ContentCommentQuery::create()->filterByContentId(NULL)->count();
$this->assertEquals(1, $count, 'There should be one unassigned contentComment.');

}

/**
* Basic deletion of a 1-to-n relation through set<RelationName>().
*
*/
public function testContentsDeletion(){

$contentCollection = new PropelObjectCollection();
$contentCollection->setModel('MoreRelationTest\\Content');

$content = new \MoreRelationTest\Content();
$content->setTitle('I should be alone :-(');

$contentCollection[] = $content;

$page = \MoreRelationTest\PageQuery::create()->findOne();
$id = $page->getId();

$count = \MoreRelationTest\ContentQuery::create()->filterByPageId($id)->count();
$this->assertEquals(3, $count, 'We created for each page 3 contents.');

$page->setContents($contentCollection);
$page->save();

unset($page);

$count = \MoreRelationTest\ContentQuery::create()->filterByPageId($id)->count();
$this->assertEquals(1, $count, 'We assigned a collection of only one item.');

}

}

0 comments on commit 288e91d

Please sign in to comment.