From 1b9b6c68e0101665dc35408bbf653b9ad4b4616d Mon Sep 17 00:00:00 2001 From: piccoloprincipe Date: Thu, 2 Jul 2009 09:37:59 +0000 Subject: [PATCH] [2.0] added many-to-many uni and bi directional tests (affects #2276) --- .../Tests/Models/ECommerce/ECommerceCart.php | 4 + .../Models/ECommerce/ECommerceCategory.php | 72 ++++++++++++ .../Models/ECommerce/ECommerceProduct.php | 35 +++++- .../AbstractManyToManyAssociationTestCase.php | 50 ++++++++ .../Tests/ORM/Functional/AllTests.php | 2 + ...ManyToManyBidirectionalAssociationTest.php | 111 ++++++++++++++++++ ...anyToManyUnidirectionalAssociationTest.php | 94 +++++++++++++++ .../Doctrine/Tests/OrmFunctionalTestCase.php | 4 +- 8 files changed, 366 insertions(+), 6 deletions(-) create mode 100644 tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php diff --git a/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php b/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php index fb1ef6a37..997a94fe6 100644 --- a/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php +++ b/tests/Doctrine/Tests/Models/ECommerce/ECommerceCart.php @@ -82,4 +82,8 @@ class ECommerceCart public function addProduct(ECommerceProduct $product) { $this->products[] = $product; } + + public function removeProduct(ECommerceProduct $product) { + return $this->products->removeElement($product); + } } diff --git a/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php b/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php new file mode 100644 index 000000000..b7c7b4a68 --- /dev/null +++ b/tests/Doctrine/Tests/Models/ECommerce/ECommerceCategory.php @@ -0,0 +1,72 @@ +products = new \Doctrine\Common\Collections\Collection(); + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + $this->name = $name; + } + + public function addProduct(ECommerceProduct $product) + { + if (!$this->products->contains($product)) { + $this->products[] = $product; + $product->addCategory($this); + } + } + + public function removeProduct(ECommerceProduct $product) + { + if ($this->products->contains($product)) { + $this->products->removeElement($product); + $product->removeCategory($this); + } + } + + public function getProducts() + { + return $this->products; + } +} diff --git a/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php b/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php index a7e8e5031..2a457ce52 100644 --- a/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php +++ b/tests/Doctrine/Tests/Models/ECommerce/ECommerceProduct.php @@ -20,7 +20,7 @@ class ECommerceProduct private $id; /** - * @Column(type="string", length=50) + * @Column(type="string", length=50, nullable="true") */ private $name; @@ -40,12 +40,13 @@ class ECommerceProduct * @JoinTable(name="ecommerce_products_categories", joinColumns={{"name"="product_id", "referencedColumnName"="id"}}, inverseJoinColumns={{"name"="category_id", "referencedColumnName"="id"}}) - private $categories; */ + private $categories; public function __construct() { $this->features = new \Doctrine\Common\Collections\Collection; + $this->categories = new \Doctrine\Common\Collections\Collection; } public function getId() @@ -83,17 +84,20 @@ class ECommerceProduct return $this->features; } - public function addFeature(ECommerceFeature $feature) { + public function addFeature(ECommerceFeature $feature) + { $this->features[] = $feature; $feature->setProduct($this); } /** does not set the owning side */ - public function brokenAddFeature(ECommerceFeature $feature) { + public function brokenAddFeature(ECommerceFeature $feature) + { $this->features[] = $feature; } - public function removeFeature(ECommerceFeature $feature) { + public function removeFeature(ECommerceFeature $feature) + { if ($this->features->contains($feature)) { $removed = $this->features->removeElement($feature); if ($removed) { @@ -103,4 +107,25 @@ class ECommerceProduct } return false; } + + public function addCategory(ECommerceCategory $category) + { + if (!$this->categories->contains($category)) { + $this->categories[] = $category; + $category->addProduct($this); + } + } + + public function removeCategory(ECommerceCategory $category) + { + if ($this->categories->contains($category)) { + $this->categories->removeElement($category); + $category->removeProduct($this); + } + } + + public function getCategories() + { + return $this->categories; + } } diff --git a/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php b/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php new file mode 100644 index 000000000..8a175e50f --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/AbstractManyToManyAssociationTestCase.php @@ -0,0 +1,50 @@ +assertEquals(1, $this->_countForeignKeys($firstId, $secondId)); + } + + public function assertForeignKeysNotContain($firstId, $secondId) + { + $this->assertEquals(0, $this->_countForeignKeys($firstId, $secondId)); + } + + protected function _countForeignKeys($firstId, $secondId) + { + return count($this->_em->getConnection() + ->execute("SELECT {$this->_firstField} + FROM {$this->_table} + WHERE {$this->_firstField}=? + AND {$this->_secondField}=?", + array($firstId, $secondId))); + } + + public function assertCollectionEquals(Collection $first, Collection $second) + { + if (count($first) != count($second)) { + return false; + } + foreach ($first as $element) { + if (!$second->contains($element)) { + return false; + } + } + return true; + } +} diff --git a/tests/Doctrine/Tests/ORM/Functional/AllTests.php b/tests/Doctrine/Tests/ORM/Functional/AllTests.php index a8b87e221..7178fad2f 100644 --- a/tests/Doctrine/Tests/ORM/Functional/AllTests.php +++ b/tests/Doctrine/Tests/ORM/Functional/AllTests.php @@ -29,6 +29,8 @@ class AllTests $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToOneUnidirectionalAssociationTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToOneBidirectionalAssociationTest'); $suite->addTestSuite('Doctrine\Tests\ORM\Functional\OneToManyBidirectionalAssociationTest'); + $suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManyUnidirectionalAssociationTest'); + $suite->addTestSuite('Doctrine\Tests\ORM\Functional\ManyToManyBidirectionalAssociationTest'); return $suite; } diff --git a/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php b/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php new file mode 100644 index 000000000..0ac35af1a --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ManyToManyBidirectionalAssociationTest.php @@ -0,0 +1,111 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->firstProduct = new ECommerceProduct(); + $this->secondProduct = new ECommerceProduct(); + $this->firstCategory = new ECommerceCategory(); + $this->firstCategory->setName("Business"); + $this->secondCategory = new ECommerceCategory(); + $this->secondCategory->setName("Home"); + } + + public function testSavesAManyToManyAssociationWithCascadeSaveSet() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->_em->save($this->firstProduct); + $this->_em->flush(); + + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->firstCategory->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->secondCategory->getId()); + } + + public function testRemovesAManyToManyAssociation() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->_em->save($this->firstProduct); + $this->firstProduct->removeCategory($this->firstCategory); + + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstProduct->getId(), + $this->firstCategory->getId()); + $this->assertForeignKeysContain($this->firstProduct->getId(), + $this->secondCategory->getId()); + } + + public function testEagerLoadsInverseSide() + { + $this->_createLoadingFixture(); + list ($firstProduct, $secondProduct) = $this->_findProducts(); + $categories = $firstProduct->getCategories(); + + $this->assertTrue($categories[0] instanceof ECommerceCategory); + $this->assertTrue($categories[1] instanceof ECommerceCategory); + $this->assertCollectionEquals($categories, $secondProduct->getCategories()); + } + + public function testEagerLoadsOwningSide() + { + $this->_createLoadingFixture(); + list ($firstProduct, $secondProduct) = $this->_findProducts(); + $categories = $firstProduct->getCategories(); + $products = $categories[0]->getProducts(); + + $this->assertTrue($products[0] instanceof ECommerceProduct); + $this->assertTrue($products[1] instanceof ECommerceProduct); + $this->assertCollectionEquals($products, $categories[1]->getProducts()); + } + + protected function _createLoadingFixture() + { + $this->firstProduct->addCategory($this->firstCategory); + $this->firstProduct->addCategory($this->secondCategory); + $this->secondProduct->addCategory($this->firstCategory); + $this->secondProduct->addCategory($this->secondCategory); + $this->_em->save($this->firstProduct); + $this->_em->save($this->secondProduct); + + $this->_em->flush(); + $this->_em->clear(); + } + + protected function _findProducts() + { + $query = $this->_em->createQuery('SELECT p, c FROM Doctrine\Tests\Models\ECommerce\ECommerceProduct p LEFT JOIN p.categories c ORDER BY p.id, c.id'); + return $query->getResultList(); + } + + /* TODO: not yet implemented + public function testLazyLoad() { + + }*/ +} diff --git a/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php b/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php new file mode 100644 index 000000000..cd2cf7f9c --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Functional/ManyToManyUnidirectionalAssociationTest.php @@ -0,0 +1,94 @@ +useModelSet('ecommerce'); + parent::setUp(); + $this->firstProduct = new ECommerceProduct(); + $this->firstProduct->setName('Doctrine 1.x Manual'); + $this->secondProduct = new ECommerceProduct(); + $this->secondProduct->setName('Doctrine 2.x Manual'); + $this->firstCart = new ECommerceCart(); + $this->secondCart = new ECommerceCart(); + } + + public function testSavesAManyToManyAssociationWithCascadeSaveSet() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->_em->save($this->firstCart); + $this->_em->flush(); + + $this->assertForeignKeysContain($this->firstCart->getId(), + $this->firstProduct->getId()); + $this->assertForeignKeysContain($this->firstCart->getId(), + $this->secondProduct->getId()); + } + + public function testRemovesAManyToManyAssociation() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->_em->save($this->firstCart); + $this->firstCart->removeProduct($this->firstProduct); + + $this->_em->flush(); + + $this->assertForeignKeysNotContain($this->firstCart->getId(), + $this->firstProduct->getId()); + $this->assertForeignKeysContain($this->firstCart->getId(), + $this->secondProduct->getId()); + } + + public function testEagerLoad() + { + $this->firstCart->addProduct($this->firstProduct); + $this->firstCart->addProduct($this->secondProduct); + $this->secondCart->addProduct($this->firstProduct); + $this->secondCart->addProduct($this->secondProduct); + $this->_em->save($this->firstCart); + $this->_em->save($this->secondCart); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('SELECT c, p FROM Doctrine\Tests\Models\ECommerce\ECommerceCart c LEFT JOIN c.products p ORDER BY c.id, p.id'); + $result = $query->getResultList(); + $firstCart = $result[0]; + $products = $firstCart->getProducts(); + $secondCart = $result[1]; + + $this->assertTrue($products[0] instanceof ECommerceProduct); + $this->assertTrue($products[1] instanceof ECommerceProduct); + $this->assertCollectionEquals($products, $secondCart->getProducts()); + //$this->assertEquals("Doctrine 1.x Manual", $products[0]->getName()); + //$this->assertEquals("Doctrine 2.x Manual", $products[1]->getName()); + } + + /* TODO: not yet implemented + public function testLazyLoad() { + + }*/ +} diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 17f033693..9357c978c 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -49,7 +49,8 @@ class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\ECommerce\ECommerceCustomer', 'Doctrine\Tests\Models\ECommerce\ECommerceProduct', 'Doctrine\Tests\Models\ECommerce\ECommerceShipping', - 'Doctrine\Tests\Models\ECommerce\ECommerceFeature' + 'Doctrine\Tests\Models\ECommerce\ECommerceFeature', + 'Doctrine\Tests\Models\ECommerce\ECommerceCategory' ), 'generic' => array( 'Doctrine\Tests\Models\Generic\DateTimeModel' @@ -81,6 +82,7 @@ class OrmFunctionalTestCase extends OrmTestCase $conn->exec('DELETE FROM ecommerce_products'); $conn->exec('DELETE FROM ecommerce_shippings'); $conn->exec('DELETE FROM ecommerce_features'); + $conn->exec('DELETE FROM ecommerce_categories'); } if (isset($this->_usedModelSets['company'])) { $conn->exec('DELETE FROM company_persons_friends');