Permalink
Browse files

Fixed #603

  • Loading branch information...
1 parent 7dee9ea commit 288e91d805192a5571bcd82e5aae44c8bc2aff73 @marcj marcj committed Feb 15, 2013
View
37 generator/lib/builder/om/PHP5ObjectBuilder.php
@@ -3793,7 +3793,7 @@ public function get$relCol(\$criteria = null, PropelPDO \$con = null)
";
} // addRefererGet()
- protected function addRefFKSet(&$script, $refFK)
+ protected function addRefFKSet(&$script, ForeignKey $refFK)
{
$relatedName = $this->getRefFKPhpNameAffix($refFK, $plural = true);
$relatedObjectClassName = $this->getRefFKPhpNameAffix($refFK, $plural = false);
@@ -3824,8 +3824,22 @@ public function set{$relatedName}(PropelCollection \${$inputCollection}, PropelP
{
\${$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) {
\${$inputCollectionEntry}Removed->set{$relCol}(null);
}
@@ -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);
@@ -4089,22 +4103,23 @@ protected function addRefFkScheduledForDeletion(&$script, $refFK)
$queryClassName = $this->getNewStubQueryBuilder($refFK->getTable())->getClassname();
- $localColumn = $refFK->getLocalColumn();
-
$script .= "
if (\$this->{$lowerRelatedName}ScheduledForDeletion !== null) {
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 .= "
foreach (\$this->{$lowerRelatedName}ScheduledForDeletion as \${$lowerSingleRelatedName}) {
// need to save related object because we set the relation to null
\${$lowerSingleRelatedName}->save(\$con);
}";
- } else {
- $script .= "
- $queryClassName::create()
- ->filterByPrimaryKeys(\$this->{$lowerRelatedName}ScheduledForDeletion->getPrimaryKeys(false))
- ->delete(\$con);";
}
$script .= "
\$this->{$lowerRelatedName}ScheduledForDeletion = null;
View
60 generator/lib/model/ForeignKey.php
@@ -529,7 +529,7 @@ public function isLocalColumnsRequired()
/**
* 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()
{
@@ -550,6 +550,44 @@ public function isForeignPrimaryKey()
!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
*
@@ -563,7 +601,7 @@ public function isComposite()
/**
* 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()
{
@@ -581,6 +619,24 @@ public function isLocalPrimaryKey()
}
/**
+ * 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.
* @param boolean $v Value to assign to skipSql.
*/
View
10 runtime/lib/collection/PropelCollection.php
@@ -577,6 +577,16 @@ public function __toString()
}
/**
+ * 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
* Each object is turned into an array and the result is returned
*
View
215 test/testsuite/generator/builder/om/GeneratedObjectMoreRelationTest.php
@@ -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.