how to insert into junction table when many to many with doctrine? - symfony

I am trying to insert into a junction table called post_post_category which is based on Post and PostCategory tables [many to many], i manage to execute the insert but the problem is that when i add a new post it creates a new category.
Post Entity:
class Post
{
...
/**
* #ORM\ManyToMany(targetEntity="PostCategory", cascade={"persist"})
* #ORM\JoinTable(name="post_post_category",
* joinColumns={#ORM\JoinColumn(name="post_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="post_category_id", referencedColumnName="id")}
* )
*/
private $categories;
public function __construct() {
$this->categories = new ArrayCollection();
}
...
public function getCategories(): ?PostCategory
{
return $this->categories;
}
public function addCategory(PostCategory $category): self
{
$this->categories->add($category);
return $this;
}
}
Category Entity:
class PostCategory
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=60)
*/
private $category_description;
public function getId()
{
return $this->id;
}
public function getCategoryDescription(): ?string
{
return $this->category_description;
}
public function setCategoryDescription(string $category_description): self
{
$this->category_description = $category_description;
return $this;
}
}
Controller:
...
$category->setCategoryDescription('New category');
$post->addCategory($category);
$database_manager->persist($post);
$database_manager->flush();
How do i insert an existing category in junction table?

to add an existing category to a Post you will have to retrieve the category from the database
$category = $em->getRepository('AppBundle:PostCategory')->find($categoryId);
$post->addCategory($category);

Related

How to fetch data from many to many relation ship third table in symfony doctrine

I have an intermediate table that acts as a pivot between two others: user, punto_suministro and table pivot user_punto_suministro:
How to fetch data from table user to table punto_suministro?
Entity User:
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
*/
class User implements UserInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
.....
/**
* #ORM\OneToMany(targetEntity=UserPuntoSuministro::class, mappedBy="user")
*/
private $userPuntoSuministros;
/**
* #throws \Exception
*/
public function __construct()
{
$this->puntoSuministros = new ArrayCollection();
$this->userPuntoSuministros = new ArrayCollection();
}
/**
* #return Collection|UserPuntoSuministro[]
*/
public function getUserPuntoSuministros(): Collection
{
return $this->userPuntoSuministros;
}
public function addUserPuntoSuministro(UserPuntoSuministro $userPuntoSuministro): self
{
if (!$this->userPuntoSuministros->contains($userPuntoSuministro)) {
$this->userPuntoSuministros[] = $userPuntoSuministro;
$userPuntoSuministro->setUser($this);
}
return $this;
}
public function removeUserPuntoSuministro(UserPuntoSuministro $userPuntoSuministro): self
{
if ($this->userPuntoSuministros->contains($userPuntoSuministro)) {
$this->userPuntoSuministros->removeElement($userPuntoSuministro);
// set the owning side to null (unless already changed)
if ($userPuntoSuministro->getUser() === $this) {
$userPuntoSuministro->setUser(null);
}
}
return $this;
}
Entity PuntoSuministro:
/**
* #ORM\Entity(repositoryClass=PuntoSuministroRepository::class)
*/
class PuntoSuministro
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
...
/**
* #ORM\OneToMany(targetEntity=UserPuntoSuministro::class, mappedBy="punto_suministro")
*/
private $userPuntoSuministros;
public function __construct()
{
$this->userPuntoSuministros = new ArrayCollection();
}
/**
* #return Collection|UserPuntoSuministro[]
*/
public function getUserPuntoSuministros(): Collection
{
return $this->userPuntoSuministros;
}
public function addUserPuntoSuministro(UserPuntoSuministro $userPuntoSuministro): self
{
if (!$this->userPuntoSuministros->contains($userPuntoSuministro)) {
$this->userPuntoSuministros[] = $userPuntoSuministro;
$userPuntoSuministro->setPuntoSuministro($this);
}
return $this;
}
public function removeUserPuntoSuministro(UserPuntoSuministro $userPuntoSuministro): self
{
if ($this->userPuntoSuministros->contains($userPuntoSuministro)) {
$this->userPuntoSuministros->removeElement($userPuntoSuministro);
// set the owning side to null (unless already changed)
if ($userPuntoSuministro->getPuntoSuministro() === $this) {
$userPuntoSuministro->setPuntoSuministro(null);
}
}
return $this;
}
Entity UserPuntoSuministro (table pivot):
/**
* #ORM\Entity(repositoryClass=UserPuntoSuministroRepository::class)
*/
class UserPuntoSuministro
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=User::class, inversedBy="userPuntoSuministros")
*/
private $user;
/**
* #ORM\ManyToOne(targetEntity=PuntoSuministro::class, inversedBy="userPuntoSuministros")
*/
private $punto_suministro;
public function getId(): ?int
{
return $this->id;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): self
{
$this->user = $user;
return $this;
}
public function getPuntoSuministro(): ?PuntoSuministro
{
return $this->punto_suministro;
}
public function setPuntoSuministro(?PuntoSuministro $punto_suministro): self
{
$this->punto_suministro = $punto_suministro;
return $this;
}
I try and access as follows:
$user = $userRepository->find($this->security->getUser());
$pivote = $user->getUserPuntoSuministros();
but from here I don't know how to recover the punto_suministro of a user to show it on twig.
Thanks in advance.
In simple case you could iterate over $user->getUserPuntoSuministros() and fetch concrete punto_suministro's
$user = $userRepository->find($this->security->getUser());
$puntoSuministros = []; // contains PuntoSuministro's of User
foreach ($user->getUserPuntoSuministros() as $userPuntoSuministro) {
$puntoSuministros[] = $userPuntoSuministro->getPuntoSuministro();
}

showing only current user's relations

I have 2 entities, User and courses, each student can have many courses and each course can have many students. Anyway, I'm trying to make it so that when a user connects to his account, it shows him all the courses he's related to. I know I have to do it from my controller but how do I get only the ones he's related to.
my entities
<?php
/**
* #ORM\Entity
*/
class User implements UserInterface
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
public function getId()
{
return $this->id;
}
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Courses", mappedBy="Users")
*/
private $courses;
public function __construct()
{
$this->courses = new ArrayCollection();
}
/**
* #return Collection|course[]
*/
public function getCourses(): Collection
{
return $this->courses;
}
public function addCourse(Course $course): self
{
if (!$this->courses->contains($course)) {
$this->courses[] = $course;
$course->addUser($this);
return $this;
}
return $this;
}
public function removeCourse(Course $course): self
{
if ($this->courses->contains($course)) {
$this->courses->removeElement($course);
$course->removeUser($this);
}
return $this;
}
}
<?php
/**
* #ORM\Entity(repositoryClass="App\Repository\CourseRepository")
*/
class Course
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=55)
*/
private $name;
/**
* #ORM\ManyToMany(targetEntity="App\Entity\user", inversedBy="courses")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getname(): ?string
{
return $this->name;
}
public function setname(string $name): self
{
$this->name = $name;
return $this;
}
/**
* #return Collection|user[]
*/
public function getUser(): Collection
{
return $this->user;
}
public function addUser(user $user): self
{
if (!$this->users->contains($user)) {
$this->users[] = $user;
}
return $this;
}
public function removeUser(user $user): self
{
if ($this->users->contains($user)) {
$this->users->removeElement($user);
}
return $this;
}
}
Well, because you apparently have a bi-directional relationship (inversedBy and mappedBy) you dont need to do anything special. Doctrine has already done this. Just grab the user in the controller:
// Once you have a protected controller route,
// you can use $this->getUser() from inside the
// controller action to access the current authenticated user.
$user = $this->getUser();
And iterate as you'd like through their related courses:
foreach ($user->getCourses() as $course) {
}
Because getCourses also returns a Collection instance, you can also use the ->map and ->filter functions that ship with the Collection class...

Symfony4 - Undefined index: on entity join

I'm getting an
undefined index: order
error even though from what I can tell using this documentation I'm doing everything right. Any ideas?
OrdersRepository
public function findByDateAndEmployee(\DateTime $date, int $employeeId)
{
return $this->createQueryBuilder('o')
->select('o')
->join('o.employees' ,'e')
->where('e.id = :id')
->setParameter('id',$employeeId)
->getQuery()->getSql();
}
Orders Entity
class Orders
{
...
/**
* One Order has Many Employees.
* #ORM\OneToMany(targetEntity="Employee", mappedBy="order", cascade={"persist", "remove"}, orphanRemoval=TRUE)
*/
private $employees;
I know if I change the variable in "mappedBy" it will change the error message to whatever the variable name is, however when you see below "order" should be the mappedBy variable (at least, I think).
OrderEmployees Entity
class OrderEmployees
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $orderId;
/**
* #ORM\Column(type="smallint")
*/
private $employeeId;
/**
* #ORM\ManyToOne(targetEntity="Orders", inversedBy="employees")
* #ORM\JoinColumn(name="order_id", referencedColumnName="id")
*/
private $order;
public function getId(): ?int
{
return $this->id;
}
public function getOrderId(): ?int
{
return $this->orderId;
}
public function setOrderId(int $orderId): self
{
$this->orderId = $orderId;
return $this;
}
public function getEmployeeId(): ?int
{
return $this->employeeId;
}
public function setEmployeeId(int $employeeId): self
{
$this->employeeId = $employeeId;
return $this;
}
public function getOrder(): Orders
{
return $this->order;
}
public function setOrder(Orders $order): self
{
$this->order = $order;
return $this;
}
}
Changing targetEntity="Employee" to targetEntity="OrderEmployees" in your Orders entity should help.
From the docs:
targetEntity: FQCN of the referenced target entity. Can be the
unqualified class name if both classes are in the same namespace.

Many-To-Many relationship, Bidirectional, but I can't edit Categories for Task

I'm training with Entities and generating CRUD controller for my Entities. I did Task and Category Entities:
Category Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #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;
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="categories")
*/
private $tasks;
public function __construct() {
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
public function getTasks()
{
return $this->tasks;
}
public function setTasks(Task $task)
{
$this->tasks = $task;
}
public function __toString() {
return $this->name;
}
}
?>
Task Entity
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Task
*
* #ORM\Table(name="task")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TaskRepository")
*/
class Task
{
/**
* #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 \DateTime
*
* #ORM\Column(name="datetime", type="datetime")
*/
private $datetime;
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="categories_tasks")
*/
private $categories;
public function __construct() {
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set datetime
*
* #param \DateTime $datetime
*
* #return Task
*/
public function setDatetime($datetime)
{
$this->datetime = $datetime;
return $this;
}
/**
* Get datetime
*
* #return \DateTime
*/
public function getDatetime()
{
return $this->datetime;
}
public function getCategories()
{
return $this->categories;
}
public function setCategories(Category $categories)
{
$this->categories = $categories;
}
public function __toString() {
return $this->name;
}
}
?>
I generated CRUD controllers for that Entities and it works almost fine - I can edit categories for Task. When I add new Task I also can choose 0, 1 or more categories. But it's not working in second way. When I add new category or edit existed I can choose 0, 1 or more categories from select list, I "save" and it goes further without exceptions but when I check in database or simply editing this category chosen tasks are not matched. I see category in database but #ORM\JoinTable(name="categories_tasks") has no new row. I think it has relation with #ORM\JoinTable(name="categories_tasks") because when I moved that part of code to Category Entity then I had inverse situation.
Task entity here is the relationship owner(it has the inversedBy annotation in the class), that is why adding categories to tasks then saving saves the categories to the relationship. For the categories to set the relationships you need to iterate through the tasks and have them set the id of the category, then save the tasks.
Not sure if there is a better solution. But I am confident of my diagnosis of the problem.
I think you need to setup your addCategory, removeCategory and also addTask , removeTask methods properly:
Task.php
public function addCategory(Category $category)
{
if (!$this->categories->contains($category)) {
$this->categories->add($category);
$category->addTask($this);
}
}
public function removeCategory(Category $category)
{
if ($this->categories->contains($category)) {
$this->categories->remove($category);
$category->removeTask($this);
}
}
Same for Category.php
public function addTask(Task $task)
{
if (!$this->tasks->contains($task)) {
$this->tasks->add($task);
$task->addCategory($this);
}
}
public function removeTask (Task $task)
{
if ($this->tasks->contains($task)) {
$this->tasks->remove($task);
$task->removeCategory($this);
}
}

Symfony, oneToMany relationship Invalid argument supplied for foreach()

I'm adding oneToMany relationship to database, and its working but when i want to view array i get this error :
Warning: Invalid argument supplied for foreach()
this is my User.php
class User implements AdvancedUserInterface, \Serializable
{
// ...
/**
* #ORM\OneToMany(targetEntity="Acme\CityBundle\Entity\City", mappedBy="user")
**/
private $cities;
public function __construct()
{
$this->cities = new ArrayCollection();
}
/**
* #inheritDoc
*/
public function getCities()
{
$c = array();
foreach ($this->cities as $city) {
$c[] = $city->getCity();
}
return $c;
}
/**
* Add cities
*
* #param \Acme\CityBundle\Entity\City $cities
* #return User
*/
public function addCity(\Acme\CityBundle\Entity\City $city)
{
$city->setUser($this);
$this->cities->add($city);
return $this->cities;
}
and City.php
<?php
namespace Acme\CityBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* City
*/
class City
{
/**
* #var integer
*/
private $id;
/**
* #var string
*/
private $name;
/**
* #ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="cities")
* #JoinColumn(name="id", referencedColumnName="id")
**/
private $user;
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return City
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getCity()
{
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
}
Controller
$city=new City();
$em = $this->getDoctrine()->getManager();
$city->setName('Miasto');
$user->addCity($city);
$em->persist($city);
$em->persist($user);
$em->flush();
index controller
public function indexAction()
{
$cities=$this->get('security.context')->getToken()->getUser()->getCities();
return $this->render(
'AcmeUserBundle:User:index.html.twig',array( 'cities'=>$cities));
}
and when i try to show array (cities) in view i get error
Warning: Invalid argument supplied for foreach()
in User.php
foreach ($this->cities as $city)
my table city look (id,name)
Thanks for any help.
EDIT : SOLVED
I have to update my CityBundle\Resources\config\doctrine\City.orm.yml file
In your City class, shouldn't be the relationship something like :
/**
* #ManyToOne(targetEntity="Acme\UserBundle\Entity\User", inversedBy="cities")
* #JoinColumn(name="cityId", referencedColumnName="id")
**/
private $user;
The join column shouldn't be the id of user's table.
And then, of course:
public function getCities()
{
return $this->cities;
}

Resources