Symfony / Doctrine - Get rows from related entity in entity - php

I'm trying to create cart in doctrine. Now I'm stuck with "quantity".
I'm trying to achieve that if product is already in cart, update quantity(quantity + 1).
Here are my entities:
Cart.php
class Cart
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="UUID")
* #ORM\Column(type="guid")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="Order", inversedBy="cart", cascade={"persist"})
* #ORM\JoinColumn()
*/
private $order;
/**
* #ORM\OneToMany(targetEntity="CartItem", mappedBy="cart", cascade={"persist"})
*/
private $cartItems;
public function __construct()
{
$this->cartItems = new ArrayCollection();
}
...
public function getItems()
{
return $this->cartItems;
}
public function addItem(CartItem $cartItem, Product $product, int $quantity = 1)
{
if ($this->cartItems->contains($cartItem))
return;
$cartItem->setProduct($product);
$cartItem->setQuantity($quantity);
$cartItem->setBoughtPrice($product->getBoughtPrice());
$cartItem->setPrice($product->getPrice());
$this->cartItems[] = $cartItem;
// set the *owning* side!
$cartItem->setCart($this);
}
public function removeItem(CartItem $cartItem)
{
$this->cartItems->removeElement($cartItem);
// set the owning side to null
$cartItem->setCart(null);
}
}
CartItem.php
class CartItem
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="UUID")
* #ORM\Column(type="guid")
*/
private $id;
...
/**
* #ORM\ManyToOne(targetEntity="Cart", inversedBy="cartItems")
* #ORM\JoinColumn(name="cart_id", referencedColumnName="id")
*/
private $cart;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Product\Product", inversedBy="cartItems")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
public function getId()
{
return $this->id;
}
...
public function getCart()
{
return $this->cart;
}
public function setCart(Cart $cart)
{
$this->cart = $cart;
}
public function getProduct()
{
return $this->product;
}
public function setProduct(Product $product)
{
$this->product = $product;
}
...
}
I think most important method is addItem() in Cart.php.
Is it possible to access all rows from related entity and compare if product already exist?
Or should I do it in the controller?

Try with the following code:
public function addItem(CartItem $cartItem, Product $product, int $quantity = 1)
{
if ($this->cartItems->contains($cartItem))
return;
// Looking for an item with the same product
foreach ($this->cartItems as $item) {
// Suppose the product are equals comparing it by id
if ($item->getProduct()->getId() === $product->getId()) {
// We find an existing cart item for the product
// Update the cart item info:
$cartItem->setQuantity( $cartItem->getQuantity() + $quantity );
// NB: should we take care of the quantity ?
$cartItem->setBoughtPrice($cartItem->getBoughtPrice() + $product->getBoughtPrice());
// NB: should we take care of the quantity ?
$cartItem->setPrice($cartItem->getPrice() + $product->getPrice());
return;
}
}
$cartItem->setProduct($product);
$cartItem->setQuantity($quantity);
$cartItem->setBoughtPrice($product->getBoughtPrice());
$cartItem->setPrice($product->getPrice());
$this->cartItems[] = $cartItem;
// set the *owning* side!
$cartItem->setCart($this);
}
Hope this help

Related

Doctrine2 - No foreign key inserted in the table with relation OneToMany(

I have a problem with doctrine2 with a simple relationship between the two models
Below I have prepared a simple example
/**
* #Entity(repositoryClass="PlayerRepository") #Table(name="players")
*/
class Player {
/**
* #Id #Column(type="integer") #GeneratedValue
*/
protected $id;
/**
* #OneToMany(targetEntity="Wallet", mappedBy="player", cascade={"persist"})
* #var Wallet[]
*/
private $wallets;
public function __construct() {
$this->wallets = new ArrayCollection();
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getWallets() {
return $this->wallets;
}
public function addWallets($wallets) {
$this->wallets[] = $wallets;
}
}
And second class
/**
* #Entity(repositoryClass="WalletRepository") #Table(name="wallets")
*/
class Wallet
{
/**
* #Id #Column(type="integer") #GeneratedValue
*/
protected $id;
/**
* #ManyToOne(targetEntity="Player", inversedBy="wallets")
*/
private $player;
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getPlayer() {
return $this->player;
}
public function setPlayer($player) {
$this->player = $player;
}
}
For the following code execution, I am not able to add Player object relations to Wallet:
player = new Player();
$player->addWallets(new Wallet);
$player->addWallets(new Wallet);
$entityManager->persist($player);
$entityManager->flush();
Maybe it will be better seen in the attached picture:
As far as I know you have to set this on the owning site, in this case Wallet, give it a try:
$player = new Player();
$wallet = new Wallet();
$wallet->setPlayer($player);
$entityManager->persist($player);
$entityManager->persist($wallet);
$entityManager->flush();

Delete a 3-entity (one-to-many-to-one) association with Symfony 3 using Doctrine

This is my very first question!
I have two entities that I want to relate: Product and Category. A product may have multiple categories and a category may correspond to many products. I've decided to implement this relationship as a 3-class association, having an intermediate ProductCategory entity, as shown in the image below. This give me flexibility to add properties to the association in the future.
Representation of my tree-class association
I want to assign existing categories to existing products. I want to establish the relationship from within the entities themselves. I am able to do that within the Product entity, using a setter method that receives an array of Category entities, and creates a new ProductCategory entity for each category passed. The procedure is as follows:
//Product.php
/**
* #param \Doctrine\Common\Collections\ArrayCollection $categories
* #return \TestBundle\Entity\Product
*/
public function setCategories($categories) {
$productCategoryReplacement = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($categories as $category) {
$newProductCategory = new ProductCategory();
$newProductCategory->setProduct($this);
$newProductCategory->setCategory($category);
$productCategoryReplacement[] = $newProductCategory;
}
$this->productCategory = $productCategoryReplacement;
return $this;
}
Note that I clear the ProductCategory collection before adding new ones; in this way only those categories selected in the form are saved to the database.
My problem is that Doctrine doesn't delete the records from the database before inserting the new ones. This is fine when no categories were assigned to the product but I get an Integrity constraint violation: 1062 Duplicate entry '1-1' for key 'PRIMARY' when trying to update the association. I've checked the Symfony debug panel, in the Doctrine section, and no DELETE statement is ever executed prior to the INSERTs.
Is it possible to delete related entities from within an entity? If not, then why is it possible to add new ones? Thanks in advance.
My entities are as follows:
Product.php:
namespace TestBundle\Entity;
/**
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="TestBundle\Repository\ProductRepository")
*/
class Product {
/**
* #var int
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="ProductCategory", mappedBy="product", cascade={"persist"})
*/
private $productCategory;
/**
* Constructor
*/
public function __construct() {
$this->productCategory = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* #param \TestBundle\Entity\ProductCategory $productCategory
* #return Product
*/
public function addProductCategory(\TestBundle\Entity\ProductCategory $productCategory) {
$this->productCategory[] = $productCategory;
return $this;
}
/**
* #param \TestBundle\Entity\ProductCategory $productCategory
*/
public function removeProductCategory(\TestBundle\Entity\ProductCategory $productCategory) {
$this->productCategory->removeElement($productCategory);
}
/**
* #return \Doctrine\Common\Collections\Collection
*/
public function getProductCategory() {
return $this->productCategory;
}
/**
* #param \Doctrine\Common\Collections\ArrayCollection $categories
* #return \TestBundle\Entity\Product
*/
public function setCategories($categories) {
$productCategoryReplacement = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($categories as $category) {
$newProductCategory = new ProductCategory();
$newProductCategory->setProduct($this);
$newProductCategory->setCategory($category);
$productCategoryReplacement[] = $newProductCategory;
}
$this->productCategory = $productCategoryReplacement;
return $this;
}
/**
* #return \Doctrine\Common\Collections\ArrayCollection
*/
public function getCategories() {
$categories = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($this->getProductCategory() as $pc) {
$categories[] = $pc->getCategory();
}
return $categories;
}
}
Category.php:
namespace TestBundle\Entity;
/**
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="TestBundle\Repository\CategoryRepository")
*/
class Category {
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var \Doctrine\Common\Collections\ArrayCollection
* #ORM\OneToMany(targetEntity="ProductCategory", mappedBy="category", cascade={"persist"})
*/
private $productCategory;
}
ProductCategory.php
namespace TestBundle\Entity;
/**
* #ORM\Table(name="product_category")
* #ORM\Entity(repositoryClass="TestBundle\Repository\ProductCategoryRepository")
*/
class ProductCategory {
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Product", inversedBy="productCategory")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
/**
* #ORM\Id
* #ORM\ManyToOne(targetEntity="Category", inversedBy="productCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
}
My Product form is generated as follows:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name')
->add('categories', EntityType::class, array(
'class' => 'TestBundle:Category',
'choice_label' => 'name',
'expanded' => true,
'multiple' => true,
));
}
Note that I use a categories field name that will be populated with categories taken from Category entity. The form returns an array of Category objects that I use to generate ProductCategory entities in the setCategories() method within Product.php.
/**
* #param \Doctrine\Common\Collections\ArrayCollection $categories
* #return \TestBundle\Entity\Product
*/
public function setCategories($categories) {
$productCategoryReplacement = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($categories as $category) {
$newProductCategory = new ProductCategory();
$newProductCategory->setProduct($this);
$newProductCategory->setCategory($category);
$productCategoryReplacement[] = $newProductCategory;
}
$this->productCategory = $productCategoryReplacement;
return $this;
}
EDIT 1:
I don't have a categories field in Product, I only have a getCategories() and setCategories() methods. As shown in my form type code, I add an EntityType field of class Categories, that maps to the categories property (that doesn't actually exist). In this way I'm able to show existing categories as checkboxes an the product's categories are checked correctly.
EDIT 2: POSSIBLE SOLUTION
I ended up following Sam Jenses's suggestion. I created a service as follows:
File: src/TestBundle/Service/CategoryCleaner.php
namespace TestBundle\Service;
use Doctrine\ORM\EntityManagerInterface;
use TestBundle\Entity\Product;
use Symfony\Component\HttpFoundation\Request;
class CategoryCleaner {
/**
*
* #var EntityManagerInterface
*/
private $em;
public function __construct(EntityManagerInterface $em) {
$this->em = $em;
}
public function cleanCategories(Product $product, Request $request) {
if ($this->em == null) {
throw new Exception('Entity manager parameter must not be null');
}
if ($request == null) {
throw new Exception('Request parameter must not be null');
}
if ($request->getMethod() == 'POST') {
$categories = $this->em->getRepository('TestBundle:ProductCategory')->findByProduct($product);
foreach ($categories as $category) {
$this->em->remove($category);
}
$this->em->flush();
}
}
}
In the cleanCategories method, which receives the current Product and Request as parameters, all entries of ProductCategory which correspond to Product are removed, only in case of a POST request.
The service is registered as follows:
File app/config/services.yml
services:
app.category_cleaner:
class: TestBundle\Service\CategoryCleaner
arguments: ['#doctrine.orm.entity_manager']
The service must be called from the controller before handleRequest($request), that is, before the new categories are added. If not, we get a duplicate entry exception.
Edit method from file TestBundle/Controller/ProductController.php
public function editAction(Request $request, Product $product) {
$deleteForm = $this->createDeleteForm($product);
$editForm = $this->createForm('TestBundle\Form\ProductType', $product);
$this->container->get('app.category_cleaner')->cleanCategories($product, $request);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('product_edit', array('id' => $product->getId()));
}
return $this->render('product/edit.html.twig', array(
'product' => $product,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
Please validate my approach.
create an intermediate service, in which you can also use doctrine to remove the existing entities
I suppose that you have inside your entity some methods like:
addCategory
removeCategory
getCategory
and also
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
So inside your function you can do:
public function setCategories($categories) {
$productCategoryReplacement = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($this->categories as $category) {
$this->removeCategory($category);
}
foreach ($categories as $category) {
$newProductCategory = new ProductCategory();
$newProductCategory->setProduct($this);
$newProductCategory->setCategory($category);
$productCategoryReplacement[] = $newProductCategory;
}
$this->productCategory = $productCategoryReplacement;
return $this;
}

Symfony2 - CalendarBundle - How to fetch user informations from database to render on calendar

So, i am new to Symfony and i'm trying to create a functional calendar based application with events rendered from the database using calendar-bundle.
Passing with the documentation i was able to make a relationship between users and events rendered on the calendar but i'm stuck passing particular data, more exactly the user name.
Below is it shown the EventEntity which is responsible for calendar event's details.
<?php
namespace ADesigns\CalendarBundle\Entity;
/**
* Class for holding a calendar event's details.
*
* #author Mike Yudin <mikeyudin#gmail.com>
*/
class EventEntity
{
/**
* #var mixed Unique identifier of this event (optional).
*/
protected $id;
/**
* #var string Title/label of the calendar event.
*/
protected $title;
/**
* #var string URL Relative to current path.
*/
protected $url;
/**
* #var string HTML color code for the bg color of the event label.
*/
protected $bgColor;
/**
* #var string HTML color code for the foregorund color of the event label.
*/
protected $fgColor;
/**
* #var string css class for the event label
*/
protected $cssClass;
/**
* #var \DateTime DateTime object of the event start date/time.
*/
protected $startDatetime;
/**
* #var \DateTime DateTime object of the event end date/time.
*/
protected $endDatetime;
/**
* #var boolean Is this an all day event?
*/
protected $allDay = false;
/**
* #var array Non-standard fields
*/
protected $otherFields = array();
public function __construct($title, \DateTime $startDatetime, \DateTime $endDatetime = null, $allDay = false)
{
$this->title = $title;
$this->startDatetime = $startDatetime;
$this->setAllDay($allDay);
if ($endDatetime === null && $this->allDay === false) {
throw new \InvalidArgumentException("Must specify an event End DateTime if not an all day event.");
}
$this->endDatetime = $endDatetime;
}
/**
* Convert calendar event details to an array
*
* #return array $event
*/
public function toArray()
{
$event = array();
if ($this->id !== null) {
$event['id'] = $this->id;
}
$event['title'] = $this->title;
$event['start'] = $this->startDatetime->format("Y-m-d\TH:i:sP");
if ($this->url !== null) {
$event['url'] = $this->url;
}
if ($this->bgColor !== null) {
$event['backgroundColor'] = $this->bgColor;
$event['borderColor'] = $this->bgColor;
}
if ($this->fgColor !== null) {
$event['textColor'] = $this->fgColor;
}
if ($this->cssClass !== null) {
$event['className'] = $this->cssClass;
}
if ($this->endDatetime !== null) {
$event['end'] = $this->endDatetime->format("Y-m-d\TH:i:sP");
}
$event['allDay'] = $this->allDay;
foreach ($this->otherFields as $field => $value) {
$event[$field] = $value;
}
return $event;
}
public function setId($id)
{
$this->id = $id;
}
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setUrl($url)
{
$this->url = $url;
}
public function getUrl()
{
return $this->url;
}
public function setBgColor($color)
{
$this->bgColor = $color;
}
public function getBgColor()
{
return $this->bgColor;
}
public function setFgColor($color)
{
$this->fgColor = $color;
}
public function getFgColor()
{
return $this->fgColor;
}
public function setCssClass($class)
{
$this->cssClass = $class;
}
public function getCssClass()
{
return $this->cssClass;
}
public function setStartDatetime(\DateTime $start)
{
$this->startDatetime = $start;
}
public function getStartDatetime()
{
return $this->startDatetime;
}
public function setEndDatetime(\DateTime $end)
{
$this->endDatetime = $end;
}
public function getEndDatetime()
{
return $this->endDatetime;
}
public function setAllDay($allDay = false)
{
$this->allDay = (boolean) $allDay;
}
public function getAllDay()
{
return $this->allDay;
}
/**
* #param string $name
* #param string $value
*/
public function addField($name, $value)
{
$this->otherFields[$name] = $value;
}
/**
* #param string $name
*/
public function removeField($name)
{
if (!array_key_exists($name, $this->otherFields)) {
return;
}
unset($this->otherFields[$name]);
}
}
Besides this i have the CalendarEventListener.php which is responsible for data sent to render on the calendar:
<?php
namespace AppBundle\EventListener;
use ADesigns\CalendarBundle\Event\CalendarEvent;
use ADesigns\CalendarBundle\Entity\EventEntity;
use Doctrine\ORM\EntityManager;
class CalendarEventListener
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function loadEvents(CalendarEvent $calendarEvent)
{
$startDate = $calendarEvent->getStartEventDate();
$endDate = $calendarEvent->getEndEventDate();
// The original request so you can get filters from the calendar
// Use the filter in your query for example
$request = $calendarEvent->getRequest();
$filter = $request->get('filter');
// load events using your custom logic here,
// for instance, retrieving events from a repository
$companyEvents = $this->entityManager->getRepository('AppBundle:companyEvents')
->createQueryBuilder('companyEvents')
->where('companyEvents.startEventDate BETWEEN :startEventDate and :endEventDate')
->setParameter('startEventDate', $startDate->format('Y-m-d H:i:s'))
->setParameter('endEventDate', $endDate->format('Y-m-d H:i:s'))
->getQuery()->getResult();
// $companyEvents and $companyEvent in this example
// represent entities from your database, NOT instances of EventEntity
// within this bundle.
//
// Create EventEntity instances and populate it's properties with data
// from your own entities/database values.
foreach($companyEvents as $companyEvent) {
$eventEntity = new EventEntity($companyEvent->getEventName(),
//
$companyEvent->getStartEventDate(),
$companyEvent->getEndEventDate()
,null, true);
//optional calendar event settings
$eventEntity->setAllDay(true); // default is false, set to true if this is an all day event
$eventEntity->setBgColor('#3366ff'); //set the background color of the event's label
$eventEntity->setFgColor('#FFFFFF'); //set the foreground color of the event's label
$eventEntity->setUrl('http://www.google.com'); // url to send user to when event label is clicked
$eventEntity->setCssClass('my-custom-class'); // a custom class you may want to apply to event labels
//finally, add the event to the CalendarEvent for displaying on the calendar
$calendarEvent->addEvent($eventEntity);
}
}
}
And the companyEvents entity for structuring events:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="companyEvents")
*/
class companyEvents
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* events are created by users
* #ORM\ManyToOne(targetEntity="User", inversedBy="events")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\Column(name="event_name")
*/
private $eventName;
/**
* #ORM\Column(name="event_date", type="datetime")
*/
private $eventDate;
/**
* #ORM\Column(name="startEventDate", type="datetime")
*/
private $startEventDate;
/**
* #ORM\Column(name="endEventDate", type="datetime")
*/
private $endEventDate;
/**
* Set eventName
*
* #param string $eventName
*
* #return companyEvents
*/
public function setEventName($eventName)
{
$this->eventName = $eventName;
return $this;
}
/**
* Get eventName
*
* #return string
*/
public function getEventName()
{
return $this->eventName;
}
/**
* Set eventDate
*
* #param string $eventDate
*
* #return CompanyEvents
*/
public function setEventDate($eventDate)
{
$this->eventDate = $eventDate;
return $this;
}
/**
* Get eventDate
*
* #return string
*/
public function getEventDate()
{
return $this->eventDate;
}
/**
* Set start event date
* #param string $startEventDate
*
* #return companyEvents
*/
public function setStartEventDate($startEventDate)
{
$this->startEventDate = $startEventDate;
return $this;
}
/**
*Get start event date
* #return string
*/
public function getStartEventDate()
{
return $this->startEventDate;
}
/**
* Set start event date
* #param string $endEventDate
*
* #return companyEvents
*/
public function setEndEventDate($endEventDate)
{
$this->endEventDate = $endEventDate;
return $this;
}
/**
*Get start event date
* #return string
*/
public function getEndEventDate()
{
return $this->endEventDate;
}
/**
* set user relationship
* #param string $user_id
*
* #return companyEvents
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* #return string
*/
public function getUser()
{
return $this->user;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
So, my problem is that instead of getEventName passed here:
$eventEntity = new EventEntity($companyEvent->getEventName(),
$companyEvent->getStartEventDate(),
$companyEvent->getEndEventDate()
,null, true);
i want to pass the particular user name which belongs to the specific event but when i change the getEventName() (WHICH RENDERS THE TITLE OF THE EVENT) with any other function (i have tried to even pass just the user_id from the entity), nothing else is shown in the calendar without dumping any error.
Any hints on resolving this problem will be hardly appreciated :) !
If you want to render the username in the event's title you can change the getEventName method to return the user name:
public function getEventName()
{
return $this->user->getUsername();
}
This way you won't have to change the CalendarEventListener code.
Remember to remove the eventName property and it's setter method from the companyEventsentity. You should also name the entity CamelCased and in the singular, like this CompanyEvent.

Doctrine parent, child relationship hydration

I am having a problem and I am afraid I am missing something stupid. But I am struggling with searching for a similar problem to see what I am missing.
Anyway, I have a product entity:
<?php
class Product {
private $productid;
private $name;
/**
* #ORM\ManyToOne(targetEntity="MyNamespace\CategoryBundle\Entity\Category")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="categoryid", referencedColumnName="categoryid")
* })
*/
private $category;
public function getCategoryPath()
{
$category = $this->category;
$items = array($category);
var_dump($category->getParent());
while (null !== $category->getParent()) {
$category = $category->getParent();
$items[] = $category;
}
return $items;
}
}
class Category {
private $categoryid;
private $name;
/**
* #var \Category
*
* #ORM\ManyToOne(targetEntity="MyNamespace\CategoryBundle\Entity\Category")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="parentid", referencedColumnName="categoryid")
* })
*/
private $parent;
public function getParent()
{
return $this->parent;
}
}
?>
And I try:
<?php
$product = $entityManager->find('MyNamespaceProductBundle:Product', 10);
$categories = $product->getCategoryPath();
?>
The problem is, that the categories array only contains the directly linked category. It doesn't seem that doctrine fetches the parent ones so $category->getParent() will always return null and if I look to the mysql-general log I don't see a query raised for the parent category.
What am I doing wrong?
My guess is that you should call the getCategoryPath() method inside the Category class like getCategoryid() and just return the categoryid value. Then:
<?php
$product = $entityManager->find( 'MyNamespaceProductBundle:Product', 10 );
$category = $product->getCategoryid();
$categoryProducts = $entityManager->find( 'MyNamespaceCategoryBundle:Product',array( 'categoryid' => '$category' ) );
?>

Symfony2 & Doctrine2 : removeElement doesn't work

I'm have a small project in Symfony2 and doctrine, and I'm trying to update 2 related entities:
Members & cars
$carMembers = $car->getMembers();
echo count($carMembers); // --> show 2
echo get_class(carMembers[0]); // --> show MyCars\WSBundle\Entity\Member
$car->removeMember($member);
$em->persist($car);
$em->flush();
$carMembers= $car->getMembers();
echo count($carMembers); // --> show 1
echo get_class(carMembers[0]); // --> show MyCars\WSBundle\CarsController !!!
there is my Entities:
Car
/**
* #ORM\ManyToMany(targetEntity="Member", mappedBy="cars")
*/
private $members;
/**
* Remove Member
*
* #param MyCars\WSBundle\Entity\Member $member
*/
public function removeMember(\MyCars\WSBundle\Entity\Member $member)
{
$this->members->removeElement($member);
$member->removeCar($this);
}
Member
/**
* #ORM\ManyToMany(targetEntity="Car", cascade={"persist"})
* #ORM\JoinTable(name="cars_membres",
* joinColumns={#ORM\JoinColumn(name="member_id", referencedColumnName="member_id")},
* inverseJoinColumns={#ORM\JoinColumn(name="car_id", referencedColumnName="car_id")}
* )
*/
private $cars;
I think what you're looking for is orphanRemoval relation option.
#ORM\ManyToMany(targetEntity="Car", cascade={"persist"}, orphanRemoval=true)
So when you remove item from collection and flush entity manager it will remove relation record from database...
Make sure to initialise the ArrayCollection in the class constructor, if you want to use the functions add, contains or removeElement
<?php
// ...
use Doctrine\Common\Collections\ArrayCollection;
class Car
{
/**
* #MongoDB\Id
*/
protected $members;
/**
* General constructor
*/
public function __construct()
{
$this->members = new ArrayCollection();
}
/**
* #param Member $member
* #return $this
*/
public function addMember(Member $member)
{
if (!$this->hasMember($member)) {
$this->members->add($member);
}
return $this;
}
/**
* #param Member $member
* #return $this
*/
public function removeMember(Member $member)
{
if ($this->hasMember($member)) {
$this->members->removeElement($member);
}
return $this;
}
/**
* #return mixed
*/
public function getMembers()
{
return $this->tags;
}
/**
* #param Member $member
* #return mixed
*/
public function hasTag(Member $member)
{
return $this->members->contains($member);
}
}
Which Collection do you use? Do you use \Doctrine\ArrayCollecion?
Are you sure that you are removing the same member object instance?
removeElement() method removes an object from the collection only if it is the same instance.
here is the method (note the last parameter (true) in the array_search method:
public function removeElement($element)
{
$key = array_search($element, $this->_elements, true);
if ($key !== false) {
unset($this->_elements[$key]);
return true;
}
return false;
}

Categories