Symfony2 (beta5) 1:M/M:1 in forms - php

I have entity "Creative" and Entity "Question"... When I had a ManyToMany relation from Creative to Question, I could easily do $builder->add('questions'), and it would grab all the questions and put them in a multiselect and insert into creative_question. Well I need to have a new field (position) to creative_question, so I had to create a OneToMany / ManyToOne relation. But when I add the field ($builder->add('creativeQuestions')), the multi-select is blank and it seems to be trying to query creative_question to populate it.. which is wrong. I need to populate with Questions and insert those into creative_question.
Anyhow, here's my code:
## Creative.php
[...]
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Offer", cascade={"persist"})
*/
protected $offer;
/**
* #ORM\OneToMany(targetEntity="CreativeQuestion", mappedBy="creative", cascade={"persist"})
*/
protected $creativeQuestions;
[...]
## CreativeQuestion.php
[...]
/**
* #ORM\Column(type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Creative", cascade={"persist"})
*/
protected $creative;
/**
* #ORM\ManyToOne(targetEntity="Question", cascade={"persist"})
*/
protected $question;
/**
* #ORM\Column(type="integer")
*/
protected $pos;
[...]
## CreativeType.php
[...]
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name')
->add('title')
->add('description')
->add('body')
->add('script')
->add('creativeQuestions') // how do i populate list with "Questions" then insert into creative_question?
->add('active');
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'JStout\MainBundle\Entity\Creative'
);
}
[...]
## In My Controller:
/**
* #Extra\Route("/offer/{offerId}/creative", name="admin_offer_creative")
* #Extra\Route("/offer/{offerId}/creative/{creativeId}", name="admin_offer_creative_edit")
* #Extra\Template()
*/
public function creativeAction($offerId = null, $creativeId = null)
{
// Get Offer
$offer = $this->_getObject('Offer', $offerId);
if (null === $offer->getId()) throw new NotFoundHttpException('The page you requested does not exist!');
// Get Creative
$creative = $this->_getObject('Creative', $creativeId);
// Set offer to creative
$creative->setOffer($offer);
// Get form and handler
$form = $this->get('form.factory')->create(new Form\CreativeType(), $creative);
$formHandler = $this->get('form.handler')->create(new Form\CreativeHandler(), $form);
[...]
}
protected function _getObject($entityName, $id = null)
{
// Find object
if (null !== $id) {
if (!$object = $this->get('doctrine')->getEntityManager()->find('ZGOffersMainBundle:' . $entityName, $id)) {
throw new NotFoundHttpException('The page you requested does not exist!');
}
return $object;
}
// Initialize new object
$entityName = 'JStout\MainBundle\Entity\\' . $entityName;
if (class_exists($entityName)) {
return new $entityName();
}
throw new NotFoundHttpException('The page you requested does not exist!');
}
[...]
Again, what I need works when I remove CreativeQuestion and just do Question with a ManyToMany relation:
But, ideally I'd like to have the ability to (with jquery) add questions by selecting from a dropdown box, then drag/drop for positioning of the questions. The jquery positioning is easy, I just don't know how to go about adding the questions how I want to. If I can at least get the multiselect to work, then I can move forward, but I'm kind of stuck right now!
Anyone get this far yet with Symfony2 (beta5)?

Related

symfony entities many to many, i add new fields

I try this code: Symfony: ManyToMany table extra columns
This new field is because the user have a diferent role for diferent events.
In the fist time i can add add the new fields on table user.evento, but now i cant. And i dont find the problem.
I get this fail:
An exception occurred while executing 'INSERT INTO user_evento (user_id, evento_id) VALUES (?, ?)' with params [3, 18]: SQLSTATE[HY000]: General error: 1364 Field 'tipoinvitado' doesn't have a default value
why not detecting the other 2 fields ?
capture of my sql update with the new fields
my entity UserHasEvento:
/**
* #ORM\Entity
* #ORM\Table(name="user_evento")
*/
class UserHasEvento
{
/**
* #ORM\Id
* #ORM\Column(name="id", type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Evento", cascade={"persist"}, fetch="LAZY")
* #ORM\JoinColumn(name="evento_id", referencedColumnName="id")
*/
private $eventos;
/**
* #ORM\ManyToOne(targetEntity="User", cascade={"persist","remove"}, fetch="LAZY" )
* #ORM\JoinColumn(name="user_id", referencedColumnName="id",nullable=true)
*/
private $users;
/**
* #ORM\Column(name="tipoinvitado", type="string", length=255, nullable=true)
*/
private $tipoinvitado;
/**
* #var \DateTime|null
*
* #ORM\Column(name="fechainscripcion", type="datetime", nullable=true)
*/
private $fechainscripcion;
public function setTipoinvitado(string $tipoinvitado): self
{
$this->tipoinvitado = $tipoinvitado;
return $this;
}
public function getTipoinvitado(): string
{
return $this->tipoinvitado;
}
public function getFechainscripcion()
{
return $this->fechainscripcion;
}
public function setFechainscripcion($fechainscripcion): self
{
$this->fechainscripcion = $fechainscripcion;
return $this;
}
public function __construct()
{
$this->createdAt= new \DateTime('now');
}
}
My controller update.
public function asignarUsuario(Request $request, Evento $evento, Userhasevento $userhasevento){
$user_repo = $this->getDoctrine()->getRepository(User::class);
$users = $user_repo->findAll();
$evento = $this->getDoctrine()->getRepository(Evento::class)->findOneById($evento);
$form = $this->createForm(AsignarEventoFormType::class, $evento);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$users = $evento->GetUsers();
foreach($users as $user){
$user->addEvento($evento);
$evento->addUser($user);
$userhasevento->SetTipoinvitado('normal');
$userhasevento->setFechainscripcion(new \DateTime('now'));
$em = $this->getDoctrine()->getManager();
$em->persist($evento);
$em->persist($userhasevento);
$em->flush();
}
return $this->redirect($this->generateUrl('evento_detalle', ['id' => $evento->getId()]));
}
return $this->render('evento/AsignarEvento.html.twig',[
'form' => $form->createView()
]);
}
Is your field $tipoinvitado disappear?
You might have changed your relation and the null boolean of $tipoinvitado at some point. You made your migration after changing any relation?
This can happen when you change your relations and had already data stored in you DB in a field that disappear because of you relation change.
I might be able to help you, don't hesitate giving more info
You have the answer in the error, the $tipoinvitado field has the annotation nullable=false which is a not null constraint (prevent storing null value), so it should absolutely have a value.
So you either give it a default value, give a value or change it to nullable=true.

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;
}

Exclude entity field from update in ZF2 Doctrine2

I'm in a situation that need to update a Doctrine2 Entity and exclude some fields.
With ZF2 i have an action to handle update using Zend\Form and validation filter. In particular Dish Entity have a blob column called photo that is required. During an update i want to replace the photo only if a new file is provided.
Here there are the source code for the entity and the controller action that update dish.
Dishes\Entity\Dish.php
<?php
namespace Dishes\Entity;
use Doctrine\ORM\Mapping as ORM;
/** #ORM\Entity **/
class Dish
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
**/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\Column(type="text")
*/
protected $description;
/**
* #ORM\Column(type="integer")
*/
protected $time;
/**
* #ORM\Column(type="integer")
*/
protected $complexity;
/**
* #ORM\Column(type="blob")
*/
protected $photo;
/**
* Magic getter to expose protected properties.
*
* #param string $property
* #return mixed
*/
public function __get($property)
{
return $this->$property;
}
/**
* Magic setter to save protected properties.
*
* #param string $property
* #param mixed $value
*/
public function __set($property, $value)
{
$this->$property = $value;
}
}
Dishes\Controller\AdminController.php
public function editDishAction()
{
//Params from url
$id = (int) $this->params()->fromRoute('id', 0);
$objectManager = $this->objectManager;
$hydrator = new DoctrineObject($objectManager, false);
$form = new DishForm();
$existingDish = $objectManager->find('Dishes\Entity\Dish', $id);
if ($existingDish === NULL)
$this->notFoundAction();
$request = $this->getRequest();
if ($request->isPost())
{
$filter = new DishFilter();
$filter->get('photo')->setRequired(false);
$form->setHydrator($hydrator)
->setObject($existingDish)
->setInputFilter($filter);
$post = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
//Backup photo stream
$imageData = $existingDish->photo;
$form->setData($post);
if ($form->isValid())
{
//If user upload a new image read it.
if(!empty($existingDish->photo['tmp_name']))
$imageData = file_get_contents($existingDish->photo['tmp_name']);
$existingDish->photo = $imageData;
$objectManager->flush();
$this->redirect()->toRoute('zfcadmin/dishes');
}
}
else
{
$data = $hydrator->extract($existingDish);
unset($data['photo']);
$form->setData($data);
}
return new ViewModel(array('form' => $form));
}
Actually i set $dish->photo property to NULL but this violate DB NOT NULL constraint.
How can I tell Doctrine to exclude a particular entity field from update at runtime?
Doctrine maps every column's nullable property in database level to false by default since you don't set any nullable flag in your annotation:
/**
* #ORM\Column(type="blob")
*/
protected $photo;
This means, "Photo is required, you can't insert or update row's photo column with a null value".
If you want to have null values in your database, use the following annotation:
/**
* #ORM\Column(type="blob", nullable=true)
*/
protected $photo;
and in it's setter don't forget the null default argument value:
public function setPhoto($photo = null)
{
$this->photo = $photo;
}
For the question; seems like you're setting a new Dish object on every edit operation in the action:
$form->setHydrator($hydrator)
->setObject(new Dish)
->setInputFilter($filter);
This is correct when creating new Dish objects. When editing, you have to set an already persisted Dish instance to the form:
// I'm just writing to explain the flow.
// Accessing the object repository in action level is not a good practice.
// Use a DishService for example.
$id = 32; // Grab it from route or elsewhere
$repo = $entityManager->getRepository('Dishes\Entity\Dish');
$existingDish = $repo->findOne((int) $id);
$form->setHydrator($hydrator)
->setObject($existingDish)
->setInputFilter($filter);
I'm assuming this is edit action for an existing Dish.
So, the hydrator will correctly handle both changed and untouched fields on next call since you give an already populated Dish instance via the form.
I also recommend fetching the DishFilter from the InputFilterManager instead of creating it manually in action level:
// $filter = new DishFilter();
$filter = $serviceLocator->get('InputFilterManager')->get(DishFilter::class);
// Exclude the photo on validation:
$filter->setValidationGroup('name', 'description', 'time', 'complexity');
Hope it helps.

Generate symfony2 form with one-to-many-to-one entity

I'm struggling with a symfony2 form. Basically i would like to manage User's preference to receive (or not) an email for each type of action an User could do.
Here my schema :
User (extending FOSUB)
EmailUserPreference
class EmailUserPreference {
public function __construct(User $user, \Adibox\Bundle\ActionBundle\Entity\ActionType $actionType) {
$this->user = $user;
$this->actionType = $actionType;
$this->activated = true;
}
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Adibox\Bundle\UserBundle\Entity\User", inversedBy="id")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity="Adibox\Bundle\ActionBundle\Entity\ActionType", inversedBy="id")
*/
private $actionType;
/**
* #ORM\Column activated(type="boolean")
*/
private $activated;
/*getters / setters ... */
}
ActionType
class ActionType
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $value
*
* #ORM\Column(name="value", type="string", length=255)
*/
private $value;
/* and some others */
}
Here, i build my form EmailUserPreferenceType :
class EmailUserPreferenceType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('emailPreference', 'entity', array(
'class' => 'AdiboxActionBundle:ActionType',
'property' => 'value',
'expanded' => true,
'multiple' => true,
'query_builder' => function(\Adibox\Bundle\ActionBundle\Entity\ActionTypeRepository $er) {
return $er->getAllActionsWithPreferences();
}
));
}
public function getName() {
return 'emailUserPreference';
}
public function getDefaultOptions(array $options) {
return array('data_class' => 'Adibox\Bundle\UserBundle\Entity\EmailUserPreference');
}
}
And finally the ActionTypeRepository with the function called in the FormType :
class ActionTypeRepository extends EntityRepository {
public function getAllActionsWithPreferences() {
$arrayActionWithPreferences = array(
'share',
'refuse',
'validate',
'validatePayment',
'createPayment',
'estimateChangeState',
'comment',
'createRepetition',
'display',
'DAFLate',
);
$qb = $this->createQueryBuilder('a');
$qb->where($qb->expr()->in('a.value', $arrayActionWithPreferences));
return $qb;
}
}
At this point, I thought it was OK : i got a good rendering, with the right form. But in fact, each checkbox has the same form name than the other. In other words each time the form is submitted, it only send in post a $builderemailUserPreference[emailUserPreference][] data. Obviously, it does not work as i expected.
I show these posts
http://sf.khepin.com/2011/08/basic-usage-of-the-symfony2-collectiontype-form-field/
Here he's using a widget Collection. I'm not sure i should use it or entity (like i did). But what i can read from http://symfony.com/fr/doc/current/reference/forms/types/collection.html, it seems more like an embedding form than an entity.
And finally i saw this : symfony2 many-to-many form checkbox
This one is using (indeed) Collection and many-to-many relations. I read somewhere (can't find the link anymore) that i can't use it since i need to add some attributes to the relation (in this case bool activated). I'm pretty sure the solution is near the link above, but can't find the good way to reach it.
Thank you in advance.
Any advice on what i'm doing wrong or if i should use Collections instead of Entity would be appreciated.

Symfony 2.0 entity form field not saving

I am having issues saving the selections made in a entity form field with multiple=true.
The selections come through when $form->bindRequest($request) is called but don't persist in the database when flush is called.
Here is the relevant controller code:
$news_item = new News();
$form = $this->createFormBuilder($news_item)
->add('products', 'entity',
array('class' => 'AcmeDemoBundle:Product',
'multiple' => TRUE))
->getForm();
$request = $this->getRequest();
if($request->getMethod() == "POST") {
$form->bindRequest($request);
if($form->isValid()) {
$this->em->persist($news_item);
$this->em->flush();
}
}
I have checked the $news_item object after $form->isValid() and a count($news_item->getProducts()) returns the correct number of items. The $news_item itself is saved in the DB but the ManyToMany relationship isn't being saved.
Here are the entities for reference (clipped for brevity):
/**
* #ORM\Entity
* #ORM\Table(name="Product")
*/
class Product {
/*
* #ORM\Id #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="News", inversedBy="products")
*/
protected $news_items = null;
public function __construct() {
$this->news_items = new ArrayCollection();
}
}
/**
* #ORM\Entity
* #ORM\Table(name="News")
*/
class News {
/**
* #ORM\Id #ORM\Column(type="integer") #ORM\GeneratedValue
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="Product", mappedBy="news_items")
*/
protected $products = null;
public function __construct() {
$this->products = new ArrayCollection();
}
}
I think you are missing $product->addNewsItem($news_item) and $news_item->addProduct($product) in your code this because in bi-directional associations (seems your case) you have to update the fields on both sides.
To avoid this you can set the cascade option on both sides of the association:
#ORM\ManyToMany(targetEntity="Product", mappedBy="news_items",
cascade={"persist", "remove"})
This way your code will work. You can choose the appropriate cascade options looking at here.
I'm not having the same problem that you are having, but I needed to be able to load FixtureData using similar entities. I was referred to this documentation: http://www.doctrine-project.org/docs/orm/2.1/en/reference/working-with-associations.html and I believe it's going to solve my problem. I hope this works for you too.
JS

Categories