Entity Relationships/Associations
Creating the Category entity. Let Doctrine create the class for you.
$ php app/console doctrine:generate:entity \
--entity="AppBundle:Category" \
--fields="name:string(255)"
--entity="AppBundle:Category" \
--fields="name:string(255)"
Relationship Mapping Metadata
To relate the Category and Product entities, start by creating a products property on the Category class.
# src/AppBundle/Resources/config/doctrine/Category.orm.yml
AppBundle\Entity\Category: type: entity # ... oneToMany: products: targetEntity: Product mappedBy: category # don't forget to init the collection in the Category::__construct() method
# $this->products = new ArrayCollection();
# of the entity |
First,
since a Category object will relate to many Product objects, a products
array property is added to hold those Product objects. This
isn't done because Doctrine needs it, but because it makes sense
in the application for each Category to hold an array of Product
objects.
// src/AppBundle/Entity/Category.php
use Doctrine\Common\Collections\ArrayCollection;
class Category
{
// ...
/**
* @ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
protected $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
}
Next,
since each Product class can relate to exactly one Category object,
you'll want to add a $category property to the Product class:
// src/AppBundle/Entity/Product.php
class Product
{
// ...
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
protected $category;
}
Finally, tell Doctrine to generate the missing getter and setter methods of the added new property in both the Category and Product
classes:
$ php app/console doctrine:generate:entities AppBundle
Before
you continue, be sure to tell Doctrine to add the new category table,
and product.category_id column, and new foreign key:
$ php app/console doctrine:schema:update --forceSaving Related Entities
use AppBundle\Entity\Category;
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
public function createProductAction()
{
$category = new Category();
//set category data
use AppBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Response;
class DefaultController extends Controller
{
public function createProductAction()
{
$category = new Category();
//set category data
$product = new Product();
// Set product data
// Set product data
// relate this product to the category
$product->setCategory($category);
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->persist($product);
$em->flush();
return new Response(
'Created product id: '.$product->getId()
.' and category id: '.$category->getId()
);
}
}
$product->setCategory($category);
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->persist($product);
$em->flush();
return new Response(
'Created product id: '.$product->getId()
.' and category id: '.$category->getId()
);
}
}
Now, a single row is added to both the category and product tables. The product.category_id column for the new product is set to whatever the id is of the new category. Doctrine manages the persistence of this relationship for you.
Fetching Related Objects
public function showAction($id)
{
$product = $this->getDoctrine()
->getRepository('AppBundle:Product')
->find($id);
$categoryName = $product->getCategory()->getName();
// ...
}
When you call $product->getCategory()->getName(), Doctrine silently makes a second query to find the Category that's related to this Product. It prepares the $category object and returns it to you.
You can also query in the other direction:
public function showProductsAction($id)
{
$category = $this->getDoctrine()
->getRepository('AppBundle:Category')
->find($id);
$products = $category->getProducts();
// ...
}
{
$category = $this->getDoctrine()
->getRepository('AppBundle:Category')
->find($id);
$products = $category->getProducts();
// ...
}
Joining Related Records
You can avoid the second query by issuing a join in the original query. Add the following method to the ProductRepository class:
// src/AppBundle/Entity/ProductRepository.php
public function findOneByIdJoinedToCategory($id)
{
$query = $this->getEntityManager()
->createQuery(
'SELECT p, c FROM AppBundle:Product p
JOIN p.category c
WHERE p.id = :id'
)->setParameter('id', $id);
try {
return $query->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
return null;
}
}
Lifecycle Callbacks
Sometimes, you need to perform an action right before or after an entity is inserted, updated, or deleted. These types of actions are known as "lifecycle" callbacks.
# src/AppBundle/Resources/config/doctrine/Product.orm.yml
AppBundle\Entity\Product:
type: entity
# ...
lifecycleCallbacks:
prePersist: [setCreatedAtValue]
====================================
// src/AppBundle/Entity/Product.php
/**
* @ORM\PrePersist
*/
public function setCreatedAtValue()
{
$this->createdAt = new \DateTime();
}
No comments:
Post a Comment