Update a ManyToMany Relationship Through the Inverse Side in Doctrine2 - symfony

My recipe entity:
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="recipes")
*/
private $categories;
My Category entity:
/**
* #ORM\ManyToMany(targetEntity="Recipe", inversedBy="categories")
* #ORM\JoinTable(name="recipe_category")
*/
private $recipes;
Ok this is from http://www.youtube.com/watch?v=kPrgoe3Jrjw&feature=related.
With this two owning sides all works fine. But the cli gives the error: 'The table with name recipe_category already exists. Does anyone have any idea's how the best practice?

You have to update de other entity like :
class Recipe
{
public function addCategory($cat)
{
$car->addRecipe($this);
$this->categories->add($cat);
return $this;
}
public function removeCategory($cat)
{
$cat->removeRecipe($this);
$this->categories->removeElement($cat);
return $this;
}
}

Related

Symfony 4 when entity field change, change field in another entity

I have two entities for example:
class Dog
{
/**
* #var House
*
* #ORM\ManyToOne(targetEntity="House")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="house_id", referencedColumnName="id")
* })
*/
private $house;
}
class House
{
/**
* #var ArrayCollection|null
* #ORM\ManyToMany(targetEntity="Dog",cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="dog_id", referencedColumnName="id", nullable=true)
* })
*/
protected $dog;
}
I need to throw an event if field house in Entity Dog was update (set or remove) then add or remove field dog in Entity House.
Can anyone show me how do this ?
Doctrine will do this for you but depending on the cascade option. But your annotations are not correct. In the Dog entity you have annotation for a ManyToOne and in the House entity for a ManyToMany relation. But you should choose between
ManyToOne - OneToMany
ManyToMany - ManyToMany
Take a look into the Doctrine's association mapping to read about all the types of associations and how to define them.
If you are using Symfony (4 or 5) you should use the commandline make tool to add
properties and methods with all the annotations, even for relations.
bin/console make:entity Dog
Type relation when asked for the Field type and you will have to answer some additional questions.
You must call $dog->setHouse($this); from the addDog method. If you used the commandline then below class House would be generated for you.
class House
{
// ...
/**
* #ORM\OneToMany(targetEntity="App\Entity\Dog", mappedBy="house")
*/
private $dogs;
public function __construct()
{
$this->dogs = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #return Collection|Dog[]
*/
public function getDogs(): Collection
{
return $this->dogs;
}
public function addDog(Dog $dog): self
{
if (!$this->dogs->contains($dog)) {
$this->dogs[] = $dog;
$dog->setHouse($this); // <-- here you go
}
return $this;
}
public function removeDog(Dog $dog): self
{
if ($this->dogs->contains($dog)) {
$this->dogs->removeElement($dog);
// set the owning side to null (unless already changed)
if ($dog->getHouse() === $this) {
$dog->setHouse(null);
}
}
return $this;
}
}
Same thing counts for removeDog() method.

Symfony 4: remove collection from entity

I have a product entity and product image entity. I want to use soft delete on product entity only and make a delete on product image entity.
The soft delete works fine. When I delete the product, the deleted_at column is set to current time.
So I would like to delete product image when the deleted_at column is updated.
I was wondering if I can do it directly in entity class? and how?
Product entity where I try to make the collection delation in setDeletedAt function.
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ProductRepository")
* #ORM\Table(name="product")
*/
class Product
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="App\Entity\ProductImage", mappedBy="product", orphanRemoval=true, cascade={"persist"})
*/
private $productImages;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $deleted_at;
public function __construct()
{
$this->productImages = new ArrayCollection();
}
public function setDeletedAt(?\DateTimeInterface $deleted_at): self
{
// Here I try to remove images when deleted_at column is updated
$productImage = $this->getProductImages();
$this->removeProductImage($productImage);
$this->deleted_at = $deleted_at;
return $this;
}
/**
* #return Collection|ProductImage[]
*/
public function getProductImages(): Collection
{
return $this->productImages;
}
public function addProductImage(ProductImage $productImage): self
{
if (!$this->productImages->contains($productImage)) {
$this->productImages[] = $productImage;
$productImage->setProduct($this);
}
return $this;
}
public function removeProductImage(ProductImage $productImage): self
{
if ($this->productImages->contains($productImage)) {
$this->productImages->removeElement($productImage);
// set the owning side to null (unless already changed)
if ($productImage->getProduct() === $this) {
$productImage->setProduct(null);
}
}
return $this;
}
}
But when I make the soft delete, setDeletedAt() is called and the following error is returned:
Argument 1 passed to App\Entity\Product::removeProductImage() must be an instance of App\Entity\ProductImage, instance of Doctrine\ORM\PersistentCollection given, called in ...
Thanks for your help!
---- UPDATE ----
Solution provided by John works fine:
foreach ($this->getProductImages() as $pi) {
$this->removeProductImage($pi);
}
Thanks!
pretty self-explaining error:
at this point:
$productImage = $this->getProductImages();
$this->removeProductImage($productImage);
you are passing a collection instead a single ProductImage object.
to delete them all, just do:
foreach ($this->getProductImages() as $pi) {
$this->removeProductImage($pi);
}

Type error with ArrayCollection / OneToMany relationship in Symfony 3.4

For the past couple of days I have been trying to create a bidirectionnal ManyToOne-OneToMany relationship in Symfony 3.4
I have two entities. One is Contribution and the other is Source. A Contribution can have several sources. So the relationship should be
Contribution – ManyToOne – Source – OneToMany – Contribution
But I keep getting the following error during $em→flush(); in my controller:
Type error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given, called in /var/www/html/Edebate/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php on line 605
I do not have any set method related to the Array Collection in my Entity Contribution as I could see in other posts here:
Type error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given
Symfony-Catchable Fatal Error: Argument 1 passed to Doctrine\Common\Collections\ArrayCollection::__construct() must be of the type array, object given
And the annotations are ok as mentionned here:
Doctrine OneToMany relationship error
Any help would be appreciate ! :)
Here is my Entity Contribution
use Doctrine\Common\Collections\ArrayCollection;
//annotations
abstract class Contribution
{
/**
* #ORM\OneToMany(targetEntity="Shaker\DebateBundle\Entity\Source", mappedBy="parent")
*/
protected $sources;
//Other attributes and methods
public function __construct() {
$this->sources = new ArrayCollection();
}
/**
* Add source
*
* #param \Shaker\DebateBundle\Entity\Source $source
*
* #return Contribution
*/
public function addSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources[] = $source;
return $this;
}
/**
* Remove source
*
* #param \Shaker\DebateBundle\Entity\Source $source
*/
public function removeSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources->removeElement($source);
}
/**
* Get sources
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getSources()
{
return $this->sources;
}
}
And this is in my Entity Source:
/**
* #ORM\ManyToOne(targetEntity="Shaker\DebateBundle\Entity\Contribution", inversedBy="sources")
*/
protected $parent;
/**
* Set parent
*
* #param \Shaker\DebateBundle\Entity\Contribution $parent
*
* #return Contribution
*/
public function setParent(\Shaker\DebateBundle\Entity\Contribution $parent = null)
{
$this->parent = $parent;
$parent->addSource($this);
return $this;
}
/**
* Get parent
*
* #return \Shaker\JRQBundle\Entity\Contribution
*/
public function getParent()
{
return $this->parent;
}
And in my Controller, the problem arises with flush:
$formsourcebook->handleRequest($request);
$contributionid=$formsourcebook->get('ContributionId')->getData();
if ($formsourcebook->isValid()) {
$topicargtarget=$this->getContribution($contributionid);
$sourcebook->setUser($user);
$sourcebook->setContribution($topicargtarget);
$em->persist($sourcebook);
$em->flush();
}
I don't know your question very well. However, did you try with this syntax in the Source entity?
private $parent;
// ...
public function __construct() {
$this->parent = new ArrayCollection();
// or new \Doctrine\Common\Collections\ArrayCollection();
}
I think you're forgetting the constructor in the class.
I think you "switched" some logic when working with collections. Here's how I think your "add" method should look like:
public function addSource(\Shaker\DebateBundle\Entity\Source $source)
{
$this->sources[] = $source;
$source->setParent($this);
return $this;
}
And in the other entity:
public function setParent(\Shaker\DebateBundle\Entity\Contribution $parent = null)
{
$this->parent = $parent;
return $this;
}
There are missing variables in your controller snippet, together with the form fields definitions, so you shouldn't work that much after submitting the form. Try to directly map as many fields as you can (even via autoguessing), and even if it looks ugly, but works, but then you can beautify later. Just my two cents with several months of delay.

Getters and setters using Doctrine 2

I have an Entity i.e Users. I want to make getters and setters of this entity in Doctrine, so that Doctrine can read it.
How can I do it, can someone provide me basic example? I am a beginner
How to insert data in this database table?
Here is my Users entity
<?php
/**
* #Entity
* #Table(name="users")
* Total Number of Columns : 32
*/
class Users{
/* Attributes of Users */
/**
* #Id
* #Column(type="integer")
* #GeneratedValue
* #dummy
* #Assert\NotEmpty
*/
private $id;
/**
* #Column(type="string")
* #Assert\NotEmpty
*/
private $name;
/**
* #Column(type="string")
* #Assert\NotEmpty
*/
private $email;
}
?>
Try with this command:
php app/console doctrine:generate:entities YourBundle:YourEntity
For example, if you wanted to have a setter for your email property, you would do:
public function setEmail($email)
{
$this->email = $email;
return $this;
}
public function getEmail()
{
return $this->email;
}
The first is the setter (it sets the value of email on the object) and the second is the getter (it gets the value of email from the object). Hope that helps :)
You can use magic methods if you're lazy enough not to define your own methods for each property.
public function __get($property)
{
return $this->$property;
}
public function __set($property,$value)
{
$this->$property = $value;
}
It's better to create a method for each property though
public function getName()
{
return $this->name;
}
public function setName($name)
{
$this->name = $name;
}
Have a look at the answers here Doctrine 2 Whats the Recommended Way to Access Properties?

Symfony2, Doctrine, Empty entity in relationships

I have two entities one is main and second is additional, they joined as OneToOne. I won't show all, i think it's not necessary:
apiKey
/**
* #ORM\OneToOne(targetEntity="Eve\ApiBundle\Entity\Account\apiKeyInfo", inversedBy="apiKey_byKeyID")
* #ORM\JoinColumn(name="keyID", referencedColumnName="keyID")
*/
private $apiKeyInfo_byKeyID;
public function get_apiKeyInfo_byKeyID()
{
return $this->apiKeyInfo_byKeyID;
}
apiKeyInfo
/**
* #ORM\OneToOne(targetEntity="Eve\ProfileBundle\Entity\apiKey", mappedBy="apiKeyInfo_byKeyID")
*/
private $apiKey_byKeyID;
public function get_apiKey_byKeyID()
{
return $this->apiKey_byKeyID;
}
/**
* #ORM\Column(name="type", type="string", length=255)
*/
private $type;
/**
* #param string $type
* #return apiKeyInfo
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* #return string
*/
public function getType()
{
return $this->type;
}
Relation i call in twig (apiKey is goten in php part)
apiKey.get_apiKeyInfo_byKeyID.type
It works fine when db tables is full of data, but when "apiKeyInfo" table doesn't have same keyID it throw me exception:
Entity was not found.
I understand why, because it cannot find entries with same keyID ... But i don't know how to deal with it.
So question is...
How can i make result, of this relation, can be null?
Trouble was in incorrect descriptions of entity. Problem solved.

Resources