Skip to content

Instantly share code, notes, and snippets.

@NickSun
Forked from ferodss/Product.php
Created October 5, 2020 12:22
Show Gist options
  • Save NickSun/0eb453010572262804d6a8dd235725ad to your computer and use it in GitHub Desktop.
Save NickSun/0eb453010572262804d6a8dd235725ad to your computer and use it in GitHub Desktop.
Doctrine 2 ManyToMany with Extra fields
<?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";
<?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(),
);
}
}
<?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;
}
}
<?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