Bonjour.
Je développe à titre perso un blog de recettes de cuisine spécialisées pour les personnes allergique.
Ma table recette à une relation en oneToMany avec deux autres tables (ingrédients et étapes)
LA classe recette
<?php
namespace App\Entity;
use App\Repository\CookingReceipeRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass=CookingReceipeRepository::class)
* @UniqueEntity(fields={"name"}, message="Cette recette existe déjà")
*/
class CookingReceipe
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Length(
* min = 2,
* max = 200,
* minMessage = "Votre titre doit faire au moins {{ limit }} caratères",
* maxMessage = "Votre titre ne doit pas dépasser {{ limit }} caactères"
* )
*/
private $name;
/**
* @ORM\Column(type="string", length=255)
* @Gedmo\Slug(fields={"name"})
*/
private $slug;
/**
* @ORM\ManyToOne(targetEntity=Category::class, inversedBy="cookingReceipes")
*/
private $category;
/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="cookingReceipes")
*/
private $author;
/**
* @ORM\Column(type="string", length=250)
*/
private $cookingTime;
/**
* @ORM\Column(type="string", length=250)
*/
private $numberOfGuests;
/**
* @ORM\OneToMany(targetEntity=Favorite::class, mappedBy="cookingReceipe")
*/
private $favorites;
/**
* @ORM\OneToMany(targetEntity=Comment::class, mappedBy="cookingReceipe")
*/
private $comments;
/**
* @ORM\ManyToOne(targetEntity=Difficulty::class, inversedBy="cookingReceipe")
*/
private $difficulty;
/**
* @ORM\ManyToOne(targetEntity=Price::class, inversedBy="cookingReceipe")
*/
private $price;
/**
* @ORM\OneToMany(targetEntity=SetpsCooking::class, mappedBy="cookingReceipe")
*/
private $setpsCookings;
/**
* @ORM\OneToMany(targetEntity=ReceipeIngredients::class, mappedBy="cookingReceipe" , cascade={"persist"})
*/
private $receipeIngredients;
/**
* @ORM\Column(type="datetime")
* @Gedmo\Timestampable(on="create")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
* @Gedmo\Timestampable(on="update")
*/
private $updatedAt;
public function __construct()
{
$this->favorites = new ArrayCollection();
$this->comments = new ArrayCollection();
$this->setpsCookings = new ArrayCollection();
$this->receipeIngredients = 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;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getCookingTime(): ?string
{
return $this->cookingTime;
}
public function setCookingTime(string $cookingTime): self
{
$this->cookingTime = $cookingTime;
return $this;
}
public function getNumberOfGuests(): ?string
{
return $this->numberOfGuests;
}
public function setNumberOfGuests(string $numberOfGuests): self
{
$this->numberOfGuests = $numberOfGuests;
return $this;
}
/**
* @return Collection|Favorite[]
*/
public function getFavorites(): Collection
{
return $this->favorites;
}
public function addFavorite(Favorite $favorite): self
{
if (!$this->favorites->contains($favorite)) {
$this->favorites[] = $favorite;
$favorite->setCookingReceipe($this);
}
return $this;
}
public function removeFavorite(Favorite $favorite): self
{
if ($this->favorites->removeElement($favorite)) {
// set the owning side to null (unless already changed)
if ($favorite->getCookingReceipe() === $this) {
$favorite->setCookingReceipe(null);
}
}
return $this;
}
/**
* @return Collection|Comment[]
*/
public function getComments(): Collection
{
return $this->comments;
}
public function addComment(Comment $comment): self
{
if (!$this->comments->contains($comment)) {
$this->comments[] = $comment;
$comment->setCookingReceipe($this);
}
return $this;
}
public function removeComment(Comment $comment): self
{
if ($this->comments->removeElement($comment)) {
// set the owning side to null (unless already changed)
if ($comment->getCookingReceipe() === $this) {
$comment->setCookingReceipe(null);
}
}
return $this;
}
public function getDifficulty(): ?Difficulty
{
return $this->difficulty;
}
public function setDifficulty(?Difficulty $difficulty): self
{
$this->difficulty = $difficulty;
return $this;
}
public function getPrice(): ?Price
{
return $this->price;
}
public function setPrice(?Price $price): self
{
$this->price = $price;
return $this;
}
/**
* @return Collection|SetpsCooking[]
*/
public function getSetpsCookings(): Collection
{
return $this->setpsCookings;
}
public function addSetpsCooking(SetpsCooking $setpsCooking): self
{
if (!$this->setpsCookings->contains($setpsCooking)) {
$this->setpsCookings[] = $setpsCooking;
$setpsCooking->setCookingReceipe($this);
}
return $this;
}
public function removeSetpsCooking(SetpsCooking $setpsCooking): self
{
if ($this->setpsCookings->removeElement($setpsCooking)) {
// set the owning side to null (unless already changed)
if ($setpsCooking->getCookingReceipe() === $this) {
$setpsCooking->setCookingReceipe(null);
}
}
return $this;
}
/**
* @return Collection|ReceipeIngredients[]
*/
public function getReceipeIngredients(): Collection
{
return $this->receipeIngredients;
}
public function addReceipeIngredient(ReceipeIngredients $receipeIngredient): self
{
if (!$this->receipeIngredients->contains($receipeIngredient)) {
$this->receipeIngredients[] = $receipeIngredient;
$receipeIngredient->setCookingReceipe($this);
}
return $this;
}
public function removeReceipeIngredient(ReceipeIngredients $receipeIngredient): self
{
if ($this->receipeIngredients->removeElement($receipeIngredient)) {
// set the owning side to null (unless already changed)
if ($receipeIngredient->getCookingReceipe() === $this) {
$receipeIngredient->setCookingReceipe(null);
}
}
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
}
La classe ingrédient :
<?php
namespace App\Entity;
use App\Repository\ReceipeIngredientsRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ReceipeIngredientsRepository::class)
*/
class ReceipeIngredients
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $receipeIngredientsName;
/**
* @ORM\Column(type="string", length=255)
*/
private $quantity;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $measured;
/**
* @ORM\ManyToOne(targetEntity=CookingReceipe::class, inversedBy="receipeIngredients")
*/
private $cookingReceipe;
public function getId(): ?int
{
return $this->id;
}
public function getReceipeIngredientsName(): ?string
{
return $this->receipeIngredientsName;
}
public function setReceipeIngredientsName(string $receipeIngredientsName): self
{
$this->receipeIngredientsName = $receipeIngredientsName;
return $this;
}
public function getQuantity(): ?string
{
return $this->quantity;
}
public function setQuantity(string $quantity): self
{
$this->quantity = $quantity;
return $this;
}
public function getMeasured(): ?string
{
return $this->measured;
}
public function setMeasured(?string $measured): self
{
$this->measured = $measured;
return $this;
}
public function getCookingReceipe(): ?CookingReceipe
{
return $this->cookingReceipe;
}
public function setCookingReceipe(?CookingReceipe $cookingReceipe): self
{
$this->cookingReceipe = $cookingReceipe;
return $this;
}
}
Le form de la classe recette
<?php
namespace App\Form;
use App\Entity\Price;
use App\Entity\Category;
use App\Entity\Difficulty;
use App\Entity\CookingReceipe;
use App\Entity\ReceipeIngredients;
use App\Form\RecipeIngredientsType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class CookingReceipeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('cookingTime', TextType::class)
->add('numberOfGuests', TextType::class)
->add('category', EntityType::class, [
'class' => Category::class,
'multiple' => false,
'expanded' => false
])
->add('difficulty', EntityType::class, [
'class' => Difficulty::class,
'multiple' => false,
'expanded' => false
])
->add('price', EntityType::class, [
'class' => Price::class,
'multiple' => false,
'expanded' => false
])
->add('receipeIngredients', CollectionType::class, [
'entry_type' => RecipeIngredientsType::class,
'allow_add' => true, // true si tu veux que l'utilisateur puisse en ajouter
'allow_delete' => true, // true si tu veux que l'utilisateur puisse en supprimer
'label' => 'Les ingrédients',
'entry_options' => ['label' => false],
'prototype' => true, //prototype : On veut qu’un prototype soit défini afin de pouvoir gérer la collection en javascript côté client.
'by_reference' => false, //En passant cet attribut à false, on force Symfony à appeler le setter de l’entité.
])
//->add('setpsCookings', TextType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => CookingReceipe::class,
]);
}
}
Et celui de la table ingrédients
<?php
namespace App\Form;
use App\Entity\ReceipeIngredients;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class RecipeIngredientsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('receipeIngredientsName')
->add('quantity')
->add('measured');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ReceipeIngredients::class,
]);
}
}
Ce que je veux
J'ai bien cherché sur la doc symfony, mais pour l'instant je n'arrive pas à afficher une ligne contenant les items de la classe ingrédients. Sur symfony il me dit bien qu'il les attends en field
Ce que j'obtiens
Je n'ai pas d'erreurs mais bien uniquement le form de l'entité recette.
Je suis capable d'ajouter en JS de nouvelles lignes mais je n'arrive pas à en afficher une seule.
C'est un peu comme quand on s'incrit sur un site pour postuler à un emploi, qu'on a rempli son nom et son prénom, mais qu'il faut mettre ses diplomes (et donc on clique le le boutton + pour ajouter une nouvelle ligne)
D'avance merci.