Last active
October 5, 2020 12:22
-
-
Save ferodss/7104374 to your computer and use it in GitHub Desktop.
Doctrine 2 ManyToMany with Extra fields
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// KIT | |
$product = new Product(); | |
$product->setName('KIT 01') | |
->setPrice(9.99); | |
// SUB PRODUCT | |
$subProduct = new Product(); | |
$subProduct->setName('SubProduct 02') | |
->setPrice(0.99); | |
// Persist first to get Id | |
$em->persist($product); | |
$em->persist($subProduct); | |
$em->flush(); | |
// Relationship | |
$relation = new ProductRelation(); | |
$relation->setAmount(5); | |
$product->addChildren($relation); | |
$subProduct->addParent($relation); | |
$em->flush(); | |
// Finding a product with subproducts | |
$repository = $em->getRepository('Entity\Product'); | |
$product = $repository->findWithChildrens(1); | |
$subProducts = $product->getChildrens(); | |
printf("Product: %d - %s", $product->getId(), $product->getName()); | |
echo "\nSub Products\n"; | |
echo "total: ", $subProducts->count(), "\n\n"; | |
foreach ( $subProducts as $r ) { | |
echo "SubProduct\n"; | |
printf('Id: %s - Name: %s - Price: %f - Amount: %d', | |
$r->getChildren()->getId(), | |
$r->getChildren()->getName(), | |
$r->getChildren()->getPrice(), | |
$r->getAmount() | |
); | |
echo "\n"; | |
} | |
echo "\n\n"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
use Doctrine\Common\Collections\ArrayCollection; | |
/** | |
* Product entity | |
* | |
* @ORM\Table(name="catalog_product") | |
* @ORM\Entity(repositoryClass="Repository\ProductRepository") | |
*/ | |
class Product | |
{ | |
/** | |
* @var integer | |
* | |
* @ORM\Column(name="id", type="integer", nullable=false) | |
* @ORM\Id | |
* @ORM\GeneratedValue(strategy="IDENTITY") | |
*/ | |
private $id; | |
/** | |
* @var string | |
* | |
* @ORM\Column(name="name", type="string", length=255, nullable=false) | |
*/ | |
private $name; | |
/** | |
* @var string | |
* | |
* @ORM\Column(name="price", type="decimal", precision=19, scale=2, nullable=false) | |
*/ | |
private $price; | |
/** | |
* @var Doctrine\Common\Collections\ArrayCollection|null | |
* | |
* @ORM\OneToMany( | |
* targetEntity="ProductRelation", | |
* mappedBy="parent", | |
* cascade={ "persist", "remove" }, | |
* orphanRemoval=TRUE, | |
* fetch="EXTRA_LAZY" | |
* ) | |
* //@ORM\OrderBy({"name" = "ASC"}) | |
*/ | |
private $parents; | |
/** | |
* @var Doctrine\Common\Collections\ArrayCollection | |
* | |
* @ORM\OneToMany( | |
* targetEntity="ProductRelation", | |
* mappedBy="children", | |
* cascade={ "persist", "remove" }, | |
* orphanRemoval=TRUE, | |
* fetch="EXTRA_LAZY" | |
* ) | |
* //@ORM\OrderBy({"name" = "ASC"}) | |
*/ | |
private $childrens; | |
/** | |
* Inicia um novo Produto | |
* | |
* Popula a entidade com os dados em $data | |
* | |
* @param array $data | |
*/ | |
public function __construct() | |
{ | |
$this->parents = new ArrayCollection(); | |
$this->childrens = new ArrayCollection(); | |
} | |
/** | |
* @return integer | |
*/ | |
public function getId() | |
{ | |
return $this->id; | |
} | |
/** | |
* @param integer $id | |
* @return Product | |
*/ | |
public function setId($id) | |
{ | |
$this->id = (int) $id; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getName() | |
{ | |
return $this->name; | |
} | |
/** | |
* @param string $name | |
* @return Product | |
*/ | |
public function setName($name) | |
{ | |
$this->name = (string) $name; | |
return $this; | |
} | |
public function setPrice($price) | |
{ | |
$this->price = $price; | |
return $this; | |
} | |
public function getPrice() | |
{ | |
return $this->price; | |
} | |
public function getParents() | |
{ | |
return $this->parents; | |
} | |
public function addParent(ProductRelation $relation) | |
{ | |
$this->parents->add($relation); | |
$relation->setChildren($this); | |
return $this; | |
} | |
public function getChildrens() | |
{ | |
return $this->childrens; | |
} | |
public function addChildren(ProductRelation $relation) | |
{ | |
$this->childrens->add($relation); | |
$relation->setParent($this); | |
return $this; | |
} | |
public function addChildrens(array $childrens) | |
{ | |
foreach ($childrens as $relation) { | |
if (! $relation instanceof ProductRelation) { | |
throw new \Exception('Subproduct should be instance of ProductRelation'); | |
} | |
$this->addChildren($relation); | |
} | |
return $this; | |
} | |
public function toArray() | |
{ | |
return array( | |
'id' => $this->getId(), | |
'name' => $this->getName(), | |
'price' => $this->getPrice(), | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
use Doctrine\Common\Collections\ArrayCollection; | |
/** | |
* Product Relation entity | |
* | |
* @ORM\Table(name="catalog_product_relation") | |
* @ORM\Entity | |
*/ | |
class ProductRelation | |
{ | |
/** | |
* @ORM\Id() | |
* @ORM\ManyToOne(targetEntity="Product", inversedBy="parents") | |
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=false) | |
*/ | |
protected $parent; | |
/** | |
* @ORM\Id() | |
* @ORM\ManyToOne(targetEntity="Product", inversedBy="childrens") | |
* @ORM\JoinColumn(name="child_id", referencedColumnName="id", nullable=false) | |
*/ | |
protected $children; | |
/** | |
* @ORM\Column(name="amount", type="integer", nullable=false, options={"default": 1}) | |
*/ | |
protected $amount; | |
public function setParent(Product $parent = null) | |
{ | |
$this->parent = $parent; | |
return $this; | |
} | |
public function getParent() | |
{ | |
return $this->parent; | |
} | |
public function setChildren(Product $children = null) | |
{ | |
$this->children = $children; | |
return $this; | |
} | |
public function getChildren() | |
{ | |
return $this->children; | |
} | |
public function setAmount($amount) | |
{ | |
$this->amount = (int) $amount; | |
return $this; | |
} | |
public function getAmount() | |
{ | |
return $this->amount; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Repository; | |
use Entity\Product, | |
Entity\ProductRelation; | |
use Doctrine\ORM\EntityRepository, | |
Doctrine\ORM\Query\ResultSetMapping; | |
class ProductRepository extends EntityRepository | |
{ | |
public function findWithChildrens($id) | |
{ | |
$product = parent::find($id); | |
$this->fetchChildrens($product); | |
return $product; | |
} | |
public function fetchChildrens(Product $product) | |
{ | |
$sql = ' | |
SELECT | |
pr.amount, | |
p.id, | |
p.name, | |
p.price | |
FROM | |
catalog_product_relation pr | |
INNER JOIN | |
catalog_product p ON pr.child_id = p.id | |
WHERE | |
pr.parent_id = :parent_id | |
'; | |
$stmt = $this->_em->getConnection()->query($sql); | |
$stmt->bindValue('parent_id', $product->getId()); | |
$stmt->execute(); | |
$result = $stmt->fetchAll(); | |
if (! empty($result)) { | |
$subProducts = array(); | |
foreach ($result as $row) { | |
$sub = new Product(); | |
$sub->setId($row['id']) | |
->setName($row['name']) | |
->setPrice($row['price']); | |
$relation = new ProductRelation(); | |
$relation->setAmount($row['amount']) | |
->setParent($product) | |
->setChildren($sub); | |
$subProducts[] = $relation; | |
} | |
$product->addChildrens($subProducts); | |
unset($sub, $relation, $subProducts); | |
} | |
return $product; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment