How to save One To Many relations in Sonata? - forms

I'm facing a problem in Symfony4 and Sonata Admin.
I have 3 entities : Orders, Product and Orders Product.
Here they are :
Orders :
class Orders
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* #ORM\Column(type="date")
*/
private $deliveryDate;
/**
* #ORM\Column(type="string", length=255)
*/
private $internalReference;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryContactName;
/**
* #ORM\Column(type="string", length=15)
*/
private $deliveryContactPhone;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryAddress1;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryAddress2;
/**
* #ORM\Column(type="string", length=10)
*/
private $deliveryPostalCode;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryCountry;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryCompany;
/**
* #ORM\Column(type="integer")
*/
private $status;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $comment;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryCity;
/**
* #ORM\OneToMany(targetEntity="App\Entity\OrdersProduct", mappedBy="orders")
*/
private $product;
public function __construct()
{
$this->product = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getDeliveryDate(): ?\DateTimeInterface
{
return $this->deliveryDate;
}
public function setDeliveryDate(\DateTimeInterface $deliveryDate): self
{
$this->deliveryDate = $deliveryDate;
return $this;
}
public function getInternalReference(): ?string
{
return $this->internalReference;
}
public function setInternalReference(?string $internalReference): self
{
$this->internalReference = $internalReference;
return $this;
}
public function getDeliveryContactName(): ?string
{
return $this->deliveryContactName;
}
public function setDeliveryContactName(string $deliveryContactName): self
{
$this->deliveryContactName = $deliveryContactName;
return $this;
}
public function getDeliveryContactPhone(): ?string
{
return $this->deliveryContactPhone;
}
public function setDeliveryContactPhone(string $deliveryContactPhone): self
{
$this->deliveryContactPhone = $deliveryContactPhone;
return $this;
}
public function getDeliveryAddress1(): ?string
{
return $this->deliveryAddress1;
}
public function setDeliveryAddress1(string $deliveryAddress1): self
{
$this->deliveryAddress1 = $deliveryAddress1;
return $this;
}
public function getDeliveryAddress2(): ?string
{
return $this->deliveryAddress2;
}
public function setDeliveryAddress2(?string $deliveryAddress2): self
{
$this->deliveryAddress2 = $deliveryAddress2;
return $this;
}
public function getDeliveryPostalCode(): ?string
{
return $this->deliveryPostalCode;
}
public function setDeliveryPostalCode(string $deliveryPostalCode): self
{
$this->deliveryPostalCode = $deliveryPostalCode;
return $this;
}
public function getDeliveryCountry(): ?string
{
return $this->deliveryCountry;
}
public function setDeliveryCountry(string $deliveryCountry): self
{
$this->deliveryCountry = $deliveryCountry;
return $this;
}
public function getDeliveryCompany(): ?string
{
return $this->deliveryCompany;
}
public function setDeliveryCompany(?string $deliveryCompany): self
{
$this->deliveryCompany = $deliveryCompany;
return $this;
}
public function getStatus(): ?int
{
return $this->status;
}
public function setStatus(int $status): self
{
$this->status = $status;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getDeliveryCity(): ?string
{
return $this->deliveryCity;
}
public function setDeliveryCity(string $deliveryCity): self
{
$this->deliveryCity = $deliveryCity;
return $this;
}
public function __toString()
{
if ($this->id)
return $this->id." -".$this->internalReference;
else
return "";
}
/**
* #return Collection|OrdersProduct[]
*/
public function getProduct(): Collection
{
return $this->product;
}
public function addProduct(OrdersProduct $product): self
{
if (!$this->product->contains($product)) {
$this->product[] = $product;
$product->setOrders($this);
}
return $this;
}
public function removeProduct(OrdersProduct $product): self
{
if ($this->product->contains($product)) {
$this->product->removeElement($product);
// set the owning side to null (unless already changed)
if ($product->getOrders() === $this) {
$product->setOrders(null);
}
}
return $this;
}
}
Product :
class Product
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="float")
*/
private $priceWT;
/**
* #ORM\Column(type="float")
*/
private $vat;
/**
* #ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
* #ORM\JoinColumn(nullable=false)
*/
private $category;
/**
* #ORM\Column(type="boolean")
*/
private $isDeleted;
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 getPriceWT(): ?float
{
return $this->priceWT;
}
public function setPriceWT(float $priceWT): self
{
$this->priceWT = $priceWT;
return $this;
}
public function getVat(): ?float
{
return $this->vat;
}
public function setVat(float $vat): self
{
$this->vat = $vat;
return $this;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
public function getIsDeleted(): ?bool
{
return $this->isDeleted;
}
public function setIsDeleted(bool $isDeleted): self
{
$this->isDeleted = $isDeleted;
return $this;
}
public function __toString()
{
if ($this->name)
return $this->name;
else
return "Nouveau Produit";
}
public function calculatePriceTI()
{
return $this->priceWT * (1 + $this->vat);
}
}
OrdersProduct :
class OrdersProduct
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Orders", inversedBy="product")
* #ORM\JoinColumn(nullable=false)
*/
private $orders;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Product")
* #ORM\JoinColumn(nullable=false)
*/
private $product;
/**
* #ORM\Column(type="integer")
*/
private $quantity;
/**
* #ORM\Column(type="float")
*/
private $priceWT;
public function getId(): ?int
{
return $this->id;
}
public function getOrders(): ?Orders
{
return $this->orders;
}
public function setOrders(?Orders $orders): self
{
$this->orders = $orders;
return $this;
}
public function getProduct(): ?Product
{
return $this->product;
}
public function setProduct(?Product $product): self
{
$this->product = $product;
return $this;
}
public function getQuantity(): ?int
{
return $this->quantity;
}
public function setQuantity(int $quantity): self
{
$this->quantity = $quantity;
return $this;
}
public function getPriceWT(): ?float
{
return $this->priceWT;
}
public function setPriceWT(float $priceWT): self
{
$this->priceWT = $priceWT;
return $this;
}
public function __toString()
{
if($this->id)
return $this->getOrders()->getId()." - ".$this->getProduct()->getName();
else
return "";
}
}
And here is the Orders Admin :
class OrdersAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->with('label.orders.group1', [
'class' => 'col-md-6'
])
->add('internalReference', TextType::class, [
'label' => 'label.orders.internalReference',
'required' => true
])
->add('deliveryDate', DateType::class, [
'label' => 'label.orders.deliveryDate'
])
->add('comment', TextareaType::class, [
'label' => 'label.orders.comment',
'required' => false
])
->add('deliveryContactName', TextType::class, [
'label' => 'label.orders.deliveryContactName'
])
->add('deliveryContactPhone', TextType::class, [
'label' => 'label.orders.deliveryContactPhone'
])
->add('status', ChoiceType::class, [
'label' => 'label.orders.status',
'choices' => array(
'label.orders.statuses.pending' => 1,
'label.orders.statuses.confirmed' => 2,
'label.orders.statuses.sent' => 3,
'label.orders.statuses.cancel' => 4,
)
])
->end();
$formMapper->with('label.orders.group2', [
'class' => 'col-md-6'
])
->add('deliveryCompany', TextType::class, [
'label' => 'label.orders.deliveryCompany',
'required' => false
])
->add('deliveryAddress1', TextType::class, [
'label' => 'label.orders.deliveryAddress1'
])
->add('deliveryAddress2', TextType::class, [
'label' => 'label.orders.deliveryAddress2',
'required' => false
])
->add('deliveryPostalCode', TextType::class, [
'label' => 'label.orders.deliveryPostalCode'
])
->add('deliveryCity', TextType::class, [
'label' => 'label.orders.deliveryCity'
])
->add('deliveryCountry', TextType::class, [
'label' => 'label.orders.deliveryCountry'
])
->end();
if ($this->isCurrentRoute('edit', 'admin.orders'))
$formMapper->add('product', OrdersProductType::class, array(
'order' => $this->getSubject(),
)
);
}
protected function configureDatagridFilters(DatagridMapper $filter)
{
$filter->add('internalReference')
->add('deliveryCompany');
}
protected function configureListFields(ListMapper $list)
{
$list->addIdentifier('id');
$list->add('dateAdd', 'date', [
'label' => 'label.orders.dateAdd'
]);
}
public function prePersist($orders)
{
$orders->setdateAdd(new \DateTime());
$orders->setDateUpd(new \DateTime());
}
public function preUpdate($orders)
{
$orders->setDateUpd(new \DateTime());
}
}
And the OrdersProductType :
class OrdersProductType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('product', EntityType::class, array(
'class' => Product::class,
'multiple' => false,
'expanded' => false,
))
->add('quantity')
->add('priceWT')
->add('orders', HiddenType::class, array(
'data' => $options['order']
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(array('order'));
}
}
I tried to use a CollectionType::class with a OrdersProductAdmin, but It is impossible to save the OrdersProduct as I don't know how to pass the Orders id to the embedded form. So, I made a custom form type, but :
When I submit the form, I get the error :
Expected value of type "App\Entity\OrdersProduct" for association field "App\Entity\Orders#$product", got "Proxies\__CG__\App\Entity\Product" instead.
If I dump the $orders var in the preupdate function, I have :
OrdersAdmin.php on line 121:
OrdersProduct {#1405 ▶}
OrdersAdmin.php on line 121:
OrdersProduct {#1419 ▶}
OrdersAdmin.php on line 121:
Product {#1420 ▶}
OrdersAdmin.php on line 121:
"33"
OrdersAdmin.php on line 121:
"12"
OrdersAdmin.php on line 121:
"1 -SG-000251 wonder"
The first 2 OrdersProduct are correct (they are in my DB). But the last 4 items are just not correct ! It should be OrdersProduct, with a Product, a quantity, a price and an order.
Thanks for your help.
Best

I found the (partial, as I have a form issue now !) solution !
Here are the code :
Orders Class :
/**
* #ORM\Entity(repositoryClass="App\Repository\OrdersRepository")
*/
class Orders
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="datetime")
*/
private $dateAdd;
/**
* #ORM\Column(type="datetime")
*/
private $dateUpd;
/**
* #ORM\Column(type="date")
*/
private $deliveryDate;
/**
* #ORM\Column(type="string", length=255)
*/
private $internalReference;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryContactName;
/**
* #ORM\Column(type="string", length=15)
*/
private $deliveryContactPhone;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryAddress1;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryAddress2;
/**
* #ORM\Column(type="string", length=10)
*/
private $deliveryPostalCode;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryCountry;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $deliveryCompany;
/**
* #ORM\Column(type="integer")
*/
private $status;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $comment;
/**
* #ORM\Column(type="string", length=255)
*/
private $deliveryCity;
/**
* #ORM\OneToMany(targetEntity="App\Entity\OrdersProduct", cascade={"persist"}, mappedBy="orders")
*/
private $product;
public function __construct()
{
$this->product = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getDateAdd(): ?\DateTimeInterface
{
return $this->dateAdd;
}
public function setDateAdd(\DateTimeInterface $dateAdd): self
{
$this->dateAdd = $dateAdd;
return $this;
}
public function getDateUpd(): ?\DateTimeInterface
{
return $this->dateUpd;
}
public function setDateUpd(\DateTimeInterface $dateUpd): self
{
$this->dateUpd = $dateUpd;
return $this;
}
public function getDeliveryDate(): ?\DateTimeInterface
{
return $this->deliveryDate;
}
public function setDeliveryDate(\DateTimeInterface $deliveryDate): self
{
$this->deliveryDate = $deliveryDate;
return $this;
}
public function getInternalReference(): ?string
{
return $this->internalReference;
}
public function setInternalReference(?string $internalReference): self
{
$this->internalReference = $internalReference;
return $this;
}
public function getDeliveryContactName(): ?string
{
return $this->deliveryContactName;
}
public function setDeliveryContactName(string $deliveryContactName): self
{
$this->deliveryContactName = $deliveryContactName;
return $this;
}
public function getDeliveryContactPhone(): ?string
{
return $this->deliveryContactPhone;
}
public function setDeliveryContactPhone(string $deliveryContactPhone): self
{
$this->deliveryContactPhone = $deliveryContactPhone;
return $this;
}
public function getDeliveryAddress1(): ?string
{
return $this->deliveryAddress1;
}
public function setDeliveryAddress1(string $deliveryAddress1): self
{
$this->deliveryAddress1 = $deliveryAddress1;
return $this;
}
public function getDeliveryAddress2(): ?string
{
return $this->deliveryAddress2;
}
public function setDeliveryAddress2(?string $deliveryAddress2): self
{
$this->deliveryAddress2 = $deliveryAddress2;
return $this;
}
public function getDeliveryPostalCode(): ?string
{
return $this->deliveryPostalCode;
}
public function setDeliveryPostalCode(string $deliveryPostalCode): self
{
$this->deliveryPostalCode = $deliveryPostalCode;
return $this;
}
public function getDeliveryCountry(): ?string
{
return $this->deliveryCountry;
}
public function setDeliveryCountry(string $deliveryCountry): self
{
$this->deliveryCountry = $deliveryCountry;
return $this;
}
public function getDeliveryCompany(): ?string
{
return $this->deliveryCompany;
}
public function setDeliveryCompany(?string $deliveryCompany): self
{
$this->deliveryCompany = $deliveryCompany;
return $this;
}
public function getStatus(): ?int
{
return $this->status;
}
public function setStatus(int $status): self
{
$this->status = $status;
return $this;
}
public function getComment(): ?string
{
return $this->comment;
}
public function setComment(?string $comment): self
{
$this->comment = $comment;
return $this;
}
public function getDeliveryCity(): ?string
{
return $this->deliveryCity;
}
public function setDeliveryCity(string $deliveryCity): self
{
$this->deliveryCity = $deliveryCity;
return $this;
}
public function __toString()
{
if ($this->id)
return $this->id." -".$this->internalReference;
else
return "";
}
/**
* #return Collection|OrdersProduct[]
*/
public function getProduct(): Collection
{
return $this->product;
}
public function addProduct(OrdersProduct $product): self
{
if (!$this->product->contains($product)) {
$this->product[] = $product;
$product->setOrders($this);
}
return $this;
}
public function removeProduct(OrdersProduct $product): self
{
if ($this->product->contains($product)) {
$this->product->removeElement($product);
// set the owning side to null (unless already changed)
if ($product->getOrders() === $this) {
$product->setOrders(null);
}
}
return $this;
}
public function setProduct($products)
{
$this->product = $products;
foreach ($products as $product)
{
$product->setOrders($this);
}
}
}
OrdersProduct Class :
/**
* #ORM\Entity(repositoryClass="App\Repository\OrdersProductRepository")
*/
class OrdersProduct
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Orders", inversedBy="product")
* #ORM\JoinColumn(nullable=false)
*/
private $orders;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Product")
* #ORM\JoinColumn(nullable=false)
*/
private $product;
/**
* #ORM\Column(type="integer")
*/
private $quantity;
/**
* #ORM\Column(type="float")
*/
private $priceWT;
public function getId(): ?int
{
return $this->id;
}
public function getOrders(): ?Orders
{
return $this->orders;
}
public function setOrders(?Orders $orders): self
{
$this->orders = $orders;
return $this;
}
public function getProduct(): ?Product
{
return $this->product;
}
public function setProduct(?Product $product): self
{
$this->product = $product;
return $this;
}
public function getQuantity(): ?int
{
return $this->quantity;
}
public function setQuantity(int $quantity): self
{
$this->quantity = $quantity;
return $this;
}
public function getPriceWT(): ?float
{
return $this->priceWT;
}
public function setPriceWT(float $priceWT): self
{
$this->priceWT = $priceWT;
return $this;
}
public function __toString()
{
if($this->id)
return $this->getOrders()->getId()." - ".$this->getProduct()->getName();
else
return "";
}
}
OrdersAdmin :
class OrdersAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->with('label.orders.group1', [
'class' => 'col-md-6'
])
->add('internalReference', TextType::class, [
'label' => 'label.orders.internalReference',
'required' => true
])
->add('deliveryDate', DateType::class, [
'label' => 'label.orders.deliveryDate'
])
->add('comment', TextareaType::class, [
'label' => 'label.orders.comment',
'required' => false
])
->add('deliveryContactName', TextType::class, [
'label' => 'label.orders.deliveryContactName'
])
->add('deliveryContactPhone', TextType::class, [
'label' => 'label.orders.deliveryContactPhone'
])
->add('status', ChoiceType::class, [
'label' => 'label.orders.status',
'choices' => array(
'label.orders.statuses.pending' => 1,
'label.orders.statuses.confirmed' => 2,
'label.orders.statuses.sent' => 3,
'label.orders.statuses.cancel' => 4,
)
])
->end();
$formMapper->with('label.orders.group2', [
'class' => 'col-md-6'
])
->add('deliveryCompany', TextType::class, [
'label' => 'label.orders.deliveryCompany',
'required' => false
])
->add('deliveryAddress1', TextType::class, [
'label' => 'label.orders.deliveryAddress1'
])
->add('deliveryAddress2', TextType::class, [
'label' => 'label.orders.deliveryAddress2',
'required' => false
])
->add('deliveryPostalCode', TextType::class, [
'label' => 'label.orders.deliveryPostalCode'
])
->add('deliveryCity', TextType::class, [
'label' => 'label.orders.deliveryCity'
])
->add('deliveryCountry', TextType::class, [
'label' => 'label.orders.deliveryCountry'
])
->end();
if ($this->isCurrentRoute('edit', 'admin.orders'))
$formMapper->add('product', CollectionType::class, array(
'by_reference' => false,
),
array(
'edit' => 'inline',
'inline' => 'inline'
));
}
protected function configureDatagridFilters(DatagridMapper $filter)
{
$filter->add('internalReference')
->add('deliveryCompany');
}
protected function configureListFields(ListMapper $list)
{
$list->addIdentifier('id');
$list->add('dateAdd', 'date', [
'label' => 'label.orders.dateAdd'
]);
}
public function prePersist($orders)
{
$orders->setdateAdd(new \DateTime());
$orders->setDateUpd(new \DateTime());
}
public function preUpdate($orders)
{
$orders->setDateUpd(new \DateTime());
$orders->setProduct($orders->getProduct());
}
}
OrdersProductAdmin :
class OrdersProductAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->add('product', EntityType::class, [
'class'=> 'App\Entity\Product',
'choice_label' => 'name'
])
->add('quantity')
->add('priceWT')
->add('orders', EntityType::class, [
'class' => Orders::class,
'data' => $this->getRoot()->getSubject()
]);
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
}
protected function configureListFields(ListMapper $listMapper)
{
}
public function prePersist($objects)
{
//$objects->setOrders($this->getRoot()->getSubject());
//dd($objects);
}
The OrdersProduct form is well displayed (embedded in the other form). I can get the Orders->id in the OrdersProduct Form.
Now, I have another issue : the form doesn't refresh throwing an error 500 !

Related

Problem with my entity and type Symfony 6

first of all, soory for my English, I'm French.
So, I try to create a form that use many entities. Here they are :
Controller :
class SaisieController extends AbstractController
{
#[Route('/user/saisie', name: 'app_usersaisie')]
public function add(Request $request, ManagerRegistry $doctrine, EntityManagerInterface $entityManager,): Response
{
$session = new ChasseurAnimauxSession();
$form = $this->createForm(SaisieFormType::class, $session);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {//
$em = $entityManager;
$em->persist($form->getData());
$em->flush();
return $this->render('user/informationsUser.html.twig', [
'form_index' => $form->createView(),
]);
}
return $this->render('user/informationsUser.html.twig', [
'form_index' => $form->createView(),
]);
}
}
First Entity ChasseurAniamauxSession :
namespace App\Entity;
use App\Repository\ChasseurAnimauxSessionRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ChasseurAnimauxSessionRepository::class)]
class ChasseurAnimauxSession
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 10, nullable: true)]
private ?string $sexe = null;
#[ORM\Column(nullable: true)]
private ?int $poids = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: SessionChasse::class)]
#[ORM\Column(nullable: true)]
private ?int $session_chasse_id = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: Animaux::class)]
#[ORM\Column(nullable: true)]
private ?int $animaux_id = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: User::class)]
#[ORM\Column(nullable: true)]
private ?int $chasseur_id = null;
#[ORM\Column(nullable: true)]
private ?int $number_bague = null;
public function getId(): ?int
{
return $this->id;
}
public function getSexe(): ?string
{
return $this->sexe;
}
public function setSexe(?string $sexe): self
{
$this->sexe = $sexe;
return $this;
}
public function getPoids(): ?int
{
return $this->poids;
}
public function setPoids(?int $poids): self
{
$this->poids = $poids;
return $this;
}
/**
* #return int|null
*/
public function getSessionChasseId(): ?int
{
return $this->session_chasse_id;
}
/**
* #param int|null $session_chasse_id
* #return ChasseurAnimauxSession
*/
public function setSessionChasseId(?int $session_chasse_id): ChasseurAnimauxSession
{
$this->session_chasse_id = $session_chasse_id;
return $this;
}
/**
* #return int|null
*/
public function getAnimauxId(): ?int
{
return $this->animaux_id;
}
/**
* #param int|null $animaux_id
* #return ChasseurAnimauxSession
*/
public function setAnimauxId(?int $animaux_id): ChasseurAnimauxSession
{
$this->animaux_id = $animaux_id;
return $this;
}
/**
* #return int|null
*/
public function getChasseurId(): ?int
{
return $this->chasseur_id;
}
/**
* #param int|null $chasseur_id
* #return ChasseurAnimauxSession
*/
public function setChasseurId(?int $chasseur_id): ChasseurAnimauxSession
{
$this->chasseur_id = $chasseur_id;
return $this;
}
public function getNumberBague(): ?int
{
return $this->number_bague;
}
public function setNumberBague(?int $number_bague): self
{
$this->number_bague = $number_bague;
return $this;
}
}
Another Entity Animaux :
namespace App\Entity;
use App\Repository\AnimauxRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: AnimauxRepository::class)]
class Animaux
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $espece = null;
public function getId(): ?int
{
return $this->id;
}
public function getEspece(): ?string
{
return $this->espece;
}
public function setEspece(?string $espece): self
{
$this->espece = $espece;
return $this;
}
}
The type :
<?php
namespace App\Form\user;
use App\Entity\Animaux;
use App\Entity\SessionChasse;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
class SaisieFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('animaux_id', EntityType::class,
['class' => Animaux::class,
'choice_label' => 'id'])
->add('session_chasse_id', EntityType::class,
['class' => SessionChasse::class,])
->add('number_bague', IntegerType::class,
['label' => 'Numéro de bague'])
->add('sexe', TextType::class,)
->add('poids', IntegerType::class,)
->add('save', SubmitType::class,
['label' => 'Enregistrer']);
}
}
I don't give you the another entity because I think if the answer for this one will help to solve the problem with the others. If you need more informations, tell me.
The error that I have is this one :
Expected argument of type "?int", "App\Entity\Animaux" given at property path "animaux_id".
I think it's basic error, but I spend hours on the symfony doc and forums and I don't make any progress.
Thank you for you help.
edit: I add the OneToMany that I forgot at the beginning.
It looks like you do it in the MERISE way, a french method (IMO a good method). As far as I understood, a SessionChasseurAnimaux is connected to one Animal as you were linking to one integer, not a collection. So it's more a OneToOne relation, isn'it? (If not explain us in comment)
You shouldn't link the primary key (animaux_id) but the entity Animal, because Doctrine does the job for you. It will follow the primary key, will hydrate the Animal object then it will associate it to your SessionChasseurAnimaux entity. In other words, SessionChasseurAnimaux->getAnimaux() will return the hydrated animal object, not an id of the animal. So you should replace :
#[ORM\OneToOne(mappedBy: 'id', targetEntity: Animaux::class)]
#[ORM\Column(nullable: true)]
private ?int $animaux = null;
by
#[ORM\OneToOne(mappedBy: 'id', targetEntity: Animaux::class)]
#[ORM\Column(name: "animaux_id", referencedColumnName: "id", nullable: true)]
private ?int $animaux = null;
Then, don't forget to alter the getter and the setter.
public function getAnimaux(): ?Animaux
{
return $this->animaux;
}
public function setAnimaux(?Animaux $animaux_): ChasseurAnimauxSession
{
$this->animaux = $animaux;
return $this;
}
You should have a look on the symfony/maker-bundle. This bundle will help you to create your entities. It generates all the code! If your entities aren't well described, your forms will be very difficult to build. IMO, this tutorial is very good.
First of all, thank you very much for your answer ! I appreciate
I found a solution and I post you the code that work ( But I don't think it's a good way to do the things )
Controller :
class SaisieFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('animaux_id', EntityType::class,
['class' => Animaux::class,
'choice_label' => 'espece'])
->add('session_chasse_id', EntityType::class,
['class' => SessionChasse::class,
'choice_label' => 'date'])
->add('number_bague', IntegerType::class,
['label' => 'Numéro de bague'])
->add('sexe', TextType::class,)
->add('poids', IntegerType::class,)
->add('save', SubmitType::class,
['label' => 'Enregistrer']);
}
}
First Entity ChasseurAniamauxSession :
namespace App\Entity;
use App\Repository\ChasseurAnimauxSessionRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: ChasseurAnimauxSessionRepository::class)]
class ChasseurAnimauxSession
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 10, nullable: true)]
private ?string $sexe = null;
#[ORM\Column(nullable: true)]
private ?int $poids = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: SessionChasse::class)]
#[ORM\Column(nullable: true)]
private ?SessionChasse $session_chasse_id = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: Animaux::class)]
#[ORM\Column(nullable: true)]
private Animaux|null $animaux_id = null;
#[ORM\OneToMany(mappedBy: 'id', targetEntity: User::class)]
#[ORM\Column(nullable: true)]
private ?int $chasseur_id = null;
#[ORM\Column(nullable: true)]
private ?int $number_bague = null;
public function getId(): ?int
{
return $this->id;
}
public function getSexe(): ?string
{
return $this->sexe;
}
public function setSexe(?string $sexe): self
{
$this->sexe = $sexe;
return $this;
}
public function getPoids(): ?int
{
return $this->poids;
}
public function setPoids(?int $poids): self
{
$this->poids = $poids;
return $this;
}
/**
* #return SessionChasse|null
*/
public function getSessionChasseId(): ?SessionChasse
{
return $this->session_chasse_id;
}
/**
* #param SessionChasse|null $session_chasse_id
* #return ChasseurAnimauxSession
*/
public function setSessionChasseId(?SessionChasse $session_chasse_id): ChasseurAnimauxSession
{
$this->session_chasse_id = $session_chasse_id;
return $this;
}
/**
* #return Animaux|null
*/
public function getAnimauxId(): ?Animaux
{
return $this->animaux_id;
}
/**
* #param Animaux $animaux_id
* #return ChasseurAnimauxSession
*/
public function setAnimauxId(Animaux $animaux_id): ChasseurAnimauxSession
{
$this->animaux_id = $animaux_id;
return $this;
}
/**
* #return int|null
*/
public function getChasseurId(): ?int
{
return $this->chasseur_id;
}
/**
* #param int|null $chasseur_id
* #return ChasseurAnimauxSession
*/
public function setChasseurId(?int $chasseur_id): ChasseurAnimauxSession
{
$this->chasseur_id = $chasseur_id;
return $this;
}
public function getNumberBague(): ?int
{
return $this->number_bague;
}
public function setNumberBague(?int $number_bague): self
{
$this->number_bague = $number_bague;
return $this;
}
}
Another Entity Animaux :
namespace App\Entity;
use App\Repository\AnimauxRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: AnimauxRepository::class)]
class Animaux
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $espece = null;
public function __toString(): string
{
return $this->getId();
}
public function getId(): ?int
{
return $this->id;
}
public function getEspece(): ?string
{
return $this->espece;
}
public function setEspece(?string $espece): self
{
$this->espece = $espece;
return $this;
}
}
The type :
class SaisieFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('animaux_id', EntityType::class,
['class' => Animaux::class,
'choice_label' => 'espece'])
->add('session_chasse_id', EntityType::class,
['class' => SessionChasse::class,
'choice_label' => 'date'])
->add('number_bague', IntegerType::class,
['label' => 'Numéro de bague'])
->add('sexe', TextType::class,)
->add('poids', IntegerType::class,)
->add('save', SubmitType::class,
['label' => 'Enregistrer']);
}
}
I'm going to study the links and the answer that Alexandra gave me, it looks really better than what I've done.
If I do something better, I'll post it here
Alexendre, in effet, we learn the Merise way in course ;)
For finish, a ChasseurAnimauxSession can have a lot of animals. I explain :
In this entity, I want to stock for each day of hunt the animals that have been killed by hunters. So I put in this entity the user ( The hunter who killed the animal ), the animal, and the SessionChasse ( Correspond to the day of hunt, a data ) and some informations like the sexe or the weight.

How to return entity object type from EntityType class in form?

Every time I try to send data from form and use doctrine manager I have an error:
As you can see, this problem is according to user_type. I have another entity UserType in which I have this attribute and I want to use it in register form.
I have controller and I want to add all form input into database and then error occurs.
I would like to point out that I don't want to get and set each attribute manually via for instance:
$name = $form['name']->getData();
$userDetails->setName($name);
Because I think that by using entity manager it is supposed to do automatically like this:
UserController.php:
public function register(Request $request){
$user = new User();
$userType = new UserType();
$userDetails = new UserDetails();
$form = $this->createForm(RegisterFormType::class, $user);
$form->handleRequest($request);
if($form->isSubmitted()){
$userDetails = $form->getData();
$em=$this->getDoctrine()->getManager();
$em->persist($userDetails);
$em->flush();
dd($form->getData());
My form in RegisterFormType.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
-> add('name',TextType::class,[
'data_class' => UserDetails::class,
'attr' => [
"placeholder" => 'Name'
],
])
-> add('surname',TextType::class,[
'data_class' => UserDetails::class,
'attr' => [
"placeholder" => 'Surname'
],
])
->add('email',TextType::class,[
'attr' => [
"placeholder" => 'Email'
]
])
->add('password',PasswordType::class,[
'attr' => [
"placeholder" => 'Password'
]
])
->add('confirmPassword',PasswordType::class,[
'attr' => [
"placeholder" => 'Confirm Password'
]
])
/* ->add('user_type',ChoiceType::class, [
'help' => 'Do you want to perform? Choose Artist account type. Do you want to employ artist? Choose Firm.',
'label' => "Account type",
'choices' => [
'None' => 0,
'firm' => 1,
'artist' => 2
],
'attr' => [
"class" => 'choice'
]
])*/
->add('user_type',EntityType::class, [
'class' => UserType::class,
'choice_label'=>'type',
/*'choice_label'=>'type',
'choice_value' => function ($entity) {
return $entity ? $entity->getId() : '';
},*/
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
After submitting input in form I get this data:
The problem is user_type sends as a string I suppose, but should as an object. Am I right?
In User.php
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=UserRepository::class)
* #ORM\Table(name="`user`")
*/
class User extends UserDetails
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $email;
/**
* #ORM\Column(type="string", length=255)
*/
private $password;
private $confirmPassword;
/**
* #ORM\OneToOne(targetEntity=UserType::class, cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $user_type;
/**
* #ORM\OneToOne(targetEntity=UserDetails::class, cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $user_details;
/**
* #ORM\OneToMany(targetEntity=UserToOffert::class, mappedBy="user_", orphanRemoval=true)
*/
private $user_to_offert;
/**
* #ORM\OneToMany(targetEntity=Skill::class, mappedBy="user_", orphanRemoval=true)
*/
private $skill;
/**
* #ORM\OneToMany(targetEntity=Requirement::class, mappedBy="user_id", orphanRemoval=true)
*/
private $requirement;
public function __construct()
{
$this->user_to_offert = new ArrayCollection();
$this->skill = new ArrayCollection();
$this->requirement = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(string $email): self
{
$this->email = $email;
return $this;
}
public function getPassword(): ?string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
public function getUserType(): ?string
{
return $this->user_type;
}
public function setUserType(string $user_type): self
{
$this->user_type = $user_type;
return $this;
}
public function getUserDetails(): ?UserDetails
{
return $this->user_details;
}
public function setUserDetails(UserDetails $user_details): self
{
$this->user_details = $user_details;
return $this;
}
/**
* #return mixed
*/
public function getConfirmPassword()
{
return $this->confirmPassword;
}
/**
* #param mixed $confirmPassword
*/
public function setConfirmPassword($confirmPassword): void
{
$this->confirmPassword = $confirmPassword;
}
/**
* #return Collection|UserToOffert[]
*/
public function getUserToOffert(): Collection
{
return $this->user_to_offert;
}
public function addUserToOffert(UserToOffert $userToOffert): self
{
if (!$this->user_to_offert->contains($userToOffert)) {
$this->user_to_offert[] = $userToOffert;
$userToOffert->setUser($this);
}
return $this;
}
public function removeUserToOffert(UserToOffert $userToOffert): self
{
if ($this->user_to_offert->removeElement($userToOffert)) {
// set the owning side to null (unless already changed)
if ($userToOffert->getUser() === $this) {
$userToOffert->setUser(null);
}
}
return $this;
}
/**
* #return Collection|Skill[]
*/
public function getSkill(): Collection
{
return $this->skill;
}
public function addSkill(Skill $skill): self
{
if (!$this->skill->contains($skill)) {
$this->skill[] = $skill;
$skill->setUser($this);
}
return $this;
}
public function removeSkill(Skill $skill): self
{
if ($this->skill->removeElement($skill)) {
// set the owning side to null (unless already changed)
if ($skill->getUser() === $this) {
$skill->setUser(null);
}
}
return $this;
}
/**
* #return Collection|Requirement[]
*/
public function getRequirement(): Collection
{
return $this->requirement;
}
public function addRequirement(Requirement $requirement): self
{
if (!$this->requirement->contains($requirement)) {
$this->requirement[] = $requirement;
$requirement->setUser($this);
}
return $this;
}
public function removeRequirement(Requirement $requirement): self
{
if ($this->requirement->removeElement($requirement)) {
// set the owning side to null (unless already changed)
if ($requirement->getUser() === $this) {
$requirement->setUser(null);
}
}
return $this;
}
}
UserDetails.php:
<?php
namespace App\Entity;
use App\Repository\UserDetailsRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=UserDetailsRepository::class)
*/
class UserDetails
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="string", length=255)
*/
private $surname;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $description;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $photo;
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 getSurname(): ?string
{
return $this->surname;
}
public function setSurname(string $surname): self
{
$this->surname = $surname;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getPhoto(): ?string
{
return $this->photo;
}
public function setPhoto(?string $photo): self
{
$this->photo = $photo;
return $this;
}
public function __toString() {
return $this->name;
}
}
In UserType.php:
<?php
namespace App\Entity;
/**
* #ORM\Entity(repositoryClass=UserTypeRepository::class)
*/
class UserType
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=100)
*/
private $type;
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): self
{
$this->type = $type;
return $this;
}
public function __toString() {
return $this->type;
}
}
If I remove __toString method I get an error:
Any ideas what am I doing wrong? Thank you for your time in advance. Have a nice day!

Passing parent entity Id into child form

Good day,
I got entity ScheduledCommand into relation OneToMany to ScheduledCommandLimitRange
/**
* #ORM\MappedSuperclass (repositoryClass="Synolia\SyliusSchedulerCommandPlugin\Repository\ScheduledCommandRepository")
* #ORM\Table("scheduled_command")
*/
class ScheduledCommand implements ScheduledCommandInterface
{
/**
* #var int|null
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var string
* #ORM\Column(type="string")
*/
private $name = '';
/**
* #var string
* #ORM\Column(type="string")
*/
private $command = '';
/**
* #var int
* #ORM\Column(type="integer")
*/
private $priority = 0;
/**
* #ORM\OneToMany(targetEntity="ScheduledCommandLimitRange", mappedBy="scheduledCommand", orphanRemoval=true, cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
*/
private $commandLimitRanges;
public function getId(): ?int
{
return $this->id;
}
public function getName(): string
{
return $this->name;
}
public function setName(string $name): ScheduledCommandInterface
{
$this->name = $name;
return $this;
}
public function getCommand(): string
{
return $this->command;
}
public function setCommand(string $command): ScheduledCommandInterface
{
$this->command = $command;
return $this;
}
public function getPriority(): int
{
return $this->priority;
}
public function setPriority(int $priority): ScheduledCommandInterface
{
$this->priority = $priority;
return $this;
}
public function getCommandLimitRanges(): ?Collection
{
return $this->commandLimitRanges;
}
public function setCommandLimitRanges(Collection $commandLimitRange): ?Collection
{
$this->commandLimitRanges = $commandLimitRange;
return $this->commandLimitRanges;
}
}
This is my ManyToOne class:
/**
* #ORM\Entity(repositoryClass="Synolia\SyliusSchedulerCommandPlugin\Repository\ScheduledCommandLimitRangeRepository")
* #ORM\Table(name="scheduled_command_limit_range")
*/
class ScheduledCommandLimitRange implements ScheduledCommandLimitRangeInterface
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #var \DateTime|null
* #ORM\Column(type="datetime", nullable=true)
*/
private $timeFrom;
/**
* #var \DateTime|null
* #ORM\Column(type="datetime", nullable=true)
*/
private $timeTo;
/**
* #ORM\ManyToOne(targetEntity="ScheduledCommand", inversedBy="commandLimitRanges")
*/
private $scheduledCommand;
public function getId(): ?int
{
return $this->id;
}
public function getTimeFrom(): ?\DateTime
{
return $this->timeFrom;
}
public function setTimeFrom(?\DateTime $timeFrom): ScheduledCommandLimitRangeInterface
{
$this->timeFrom = $timeFrom;
return $this;
}
public function getTimeTo(): ?\DateTime
{
return $this->timeTo;
}
public function setTimeTo(?\DateTime $timeTo): ScheduledCommandLimitRangeInterface
{
$this->timeTo = $timeTo;
return $this;
}
public function getScheduledCommand(): ?ScheduledCommand
{
return $this->scheduledCommand;
}
public function setScheduledCommand(ScheduledCommand $scheduledCommand): ?ScheduledCommand
{
$this->scheduledCommand = $scheduledCommand;
return $this;
}
I got ScheduledCommandType that is has CollectionType in one field, that has entry_type of CommandLimitType.
final class ScheduledCommandType extends AbstractType
{
/**
* #SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('name')
->add('command', CommandChoiceType::class)
->add('arguments')
->add('cronExpression')
->add('commandLimitRanges', CollectionType::class, [
'label' => 'sylius.ui.scheduled_command_limit',
'entry_type' => CommandLimitType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'inherit_data' => true,
'entry_options' => array(
'scheduledCommand' => 'id'),
])
->add('logFile')
->add('priority')
->add('executeImmediately')
->add('enabled')
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ScheduledCommand::class,
]);
}
}
This is my entry Type:
class CommandLimitType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('timeTo', DateTimeType::class, [
'widget' => 'single_text',
])
->add('timeFrom', DateTimeType::class, [
'widget' => 'single_text'
])
->add('scheduledCommand', HiddenType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setRequired(['scheduledCommand']);
$resolver->setDefaults([
'data_class' => ScheduledCommandLimitRange::class,
]);
}
}
I had a problem, that when I want to submit this form value CommandLimitRange parentId was null, so i tried to pass into child form parent Id as hidden field. But still got after submit there is stil error:
Cannot read index "0" from object of type "Synolia\SyliusSchedulerCommandPlugin\Entity\ScheduledCommand" because it doesn't implement \ArrayAccess.
What is correct way to pass parent entity Id into entry so that after submit correct parentId is linked to row in db?
Thank you very much
I have found my solution. Okay, so here is few problems, that I did not clearly understand before.
First and foremost - I had only basic setter, instead add / remove method.
public function addCommandLimitRange(ScheduledCommandLimitRange $commandLimitRange): self
{
if (!$this->commandLimitRanges->contains($commandLimitRange)) {
$this->commandLimitRanges[] = $commandLimitRange;
$commandLimitRange->setScheduledCommand($this);
}
return $this;
}
public function removeCommandLimitRange(ScheduledCommandLimitRange $commandLimitRange): self
{
if ($this->commandLimitRanges->removeElement($commandLimitRange)) {
// set the owning side to null (unless already changed)
if ($commandLimitRange->getScheduledCommand() === $this) {
$commandLimitRange->setScheduledCommand(null);
}
}
return $this;
}
Next I needed to make my property an ArrayCollection object in constructor:
public function __construct()
{
$this->commandLimitRanges = new ArrayCollection();
}
And last to get proper delete instead running update with null on parentId I needed to ad orphan_removal option into annotation.
/**
* #ORM\OneToMany(targetEntity="ScheduledCommandLimitRange", mappedBy="scheduledCommand", cascade={"persist"}, orphanRemoval=true)
*/
private $commandLimitRanges;

Symfony how to insert into a form a type Array | IteratorAggregate?

In symfony I have a ManyToOne relation :
Each Article has One Category.
Each Category may have Many Article.
Here are my two entities :
Article
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $content;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="string", nullable=true)
*/
private $image;
/**
* #ORM\Column(type="datetime", nullable=true)
*/
private $editedAt;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category")
*/
private $category;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getImage(): ?string
{
return $this->image;
}
public function setImage(?string $image): self
{
$this->image = $image;
return $this;
}
public function getEditedAt(): ?\DateTimeInterface
{
return $this->editedAt;
}
public function setEditedAt(?\DateTimeInterface $editedAt): self
{
$this->editedAt = $editedAt;
return $this;
}
public function getCategory(): ?Category
{
return $this->category;
}
public function setCategory(?Category $category): self
{
$this->category = $category;
return $this;
}
Category
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
* #Assert\Unique(message="Cette catégorie existe déjà")
*/
private $name;
/**
* #return mixed
*/
public function getId()
{
return $this->id;
}
/**
* #return mixed
*/
public function getName()
{
return $this->name;
}
/**
* #param $name
* #return mixed
*/
public function setName($name)
{
return $this->name = $name;
}
I have a basic form to add new category :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('submit', SubmitType::class, [
'label' => 'Add a new category'
])
;
}
The controller that handle the request :
public function addCategory(Request $request)
{
$category = new Category();
$form = $this->createForm(CategoryType::class, $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$category->setName($request->request->get('category_add')['name']);
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
}
return $this->render('admin/category.html.twig', [
'form' => $form->createView(),
]);
}
The problem is that when I try to submit the form with any value in the Name input it returns : This value should be of type array|IteratorAggregate.
Replace this
/**
* #ORM\Column(type="string", length=255)
* #Assert\Unique(message="Cette catégorie existe déjà")
*/
private $name;
with
/**
* #UniqueEntity("name")
/
class Category{
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
The Unique Assert : This constraint can be applied to any property of type array or \Traversable.
Edit: Forgot to remove the Assert\Unique

Symfony 4 - choice_value FormType not working

This is the method in my controller:
public function parentCat($parentId,$manOrWomen,Request $request){
$pr=new Product();
$products=$this->getDoctrine()->getRepository(Product::class)->listProductsParentCategory($parentId,$manOrWomen);
$form=$this->createForm(SearchProductType::class,$pr,['parentId'=>$parentId,'manOrWomen'=>$manOrWomen]);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
$price=$request->request->get('search_product','price');
$name=$request->request->get('search_product','name');
$products=$this->getDoctrine()->getRepository(Product::class)->listSearchedProd($parentId,$manOrWomen,$price['price']
,$name['name']);
//$products=$this->getDoctrine()->getRepository(Product::class)->listSearchedProd($productPrice);
return $this->render('list_products/index.html.twig',['controller_name' => 'ListProductsController',
'form1'=>$form->createView(),'products'=>$products]);
}
else{
return $this->render('list_products/index.html.twig',['controller_name' => 'ListProductsController','form1'=>$form->createView()
,'products'=>$products]);
}
}
This is my Product class(Pruduct Entity):
class Product
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
*
* #ORM\Column(type="string", length=255)
* #Assert\Image(mimeTypes={"image/jpeg","image/png"})
*/
private $image;
/**
* #ORM\Column(type="integer")
*/
private $price;
/**
* #var Category[] | ArrayCollection
* #ORM\ManyToOne(targetEntity="App\Entity\Category")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #var ManOrWomen[] | ArrayCollection
* #ORM\ManyToOne(targetEntity="App\Entity\ManOrWomen")
* #ORM\JoinColumn(name="manorwomen_id", referencedColumnName="id")
*/
private $manorwomen;
/**
* #param \DateTime $createdDate
*
* #ORM\Column(name="createdDate", type="datetime")
*/
private $createdDate;
/**
* Product constructor.
*/
public function __construct()
{
$this->createdDate=new \DateTime('now');
$this->category = new ArrayCollection();
$this->manorwomen=new ArrayCollection();
$this->undercategory=new ArrayCollection();
$this->parentCategory=new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function setName($name): self
{
$this->name = $name;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
public function getImage(): ?string
{
return $this->image;
}
public function setImage(string $image): self
{
$this->image = $image;
return $this;
}
public function getPrice()
{
return $this->price;
}
public function setPrice($price): self
{
$this->price = $price;
return $this;
}
/**
* #return Category[]|ArrayCollection
*/
public function getCategory()
{
return $this->category;
}
/**
* #param Category[]|ArrayCollection $category
*/
public function setCategory($category): void
{
$this->category = $category;
}
/**
* #return ManOrWomen[]|ArrayCollection
*/
public function getManorwomen()
{
return $this->manorwomen;
}
/**
* #param ManOrWomen[]|ArrayCollection $manorwomen
*/
public function setManorwomen($manorwomen): void
{
$this->manorwomen = $manorwomen;
}
/**
* #return DateTime
*/
public function getCreatedDate(): DateTime
{
return $this->createdDate;
}
/**
* #param DateTime $createdDate
*/
public function setCreatedDate(DateTime $createdDate): void
{
$this->createdDate = $createdDate;
}
This is my FormType for class Product:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$parentId = $options['parentId'];
$manOrWomen=$options['manOrWomen'];
$builder
->add('price',EntityType::class,[
'class'=>Product::class,
'choice_label'=>'price',
'choice_value' => 'price',
'placeholder'=>'Default',
'query_builder' => function (EntityRepository $er) use ($parentId,$manOrWomen) {
return $er->createQueryBuilder('product')
->innerJoin('product.category','c')
->addSelect('c')
->innerJoin('product.manorwomen','m')
->addSelect('m')
->where('c.parent_id=:parentId')
->andWhere('m.id=:manOrWomen')
->setParameters(['parentId'=>$parentId,'manOrWomen'=>$manOrWomen]);
},
'expanded'=>false,
'multiple'=>false
])
->add('name',EntityType::class,[
'class'=>Product::class,
'choice_label'=>'name',
'choice_value' => 'name',
'placeholder'=>'Default',
'query_builder' => function (EntityRepository $er) use ($parentId,$manOrWomen) {
return $er->createQueryBuilder('product')
->innerJoin('product.category','c')
->addSelect('c')
->innerJoin('product.manorwomen','m')
->addSelect('m')
->where('c.parent_id=:parentId')
->andWhere('m.id=:manOrWomen')
->setParameters(['parentId'=>$parentId,'manOrWomen'=>$manOrWomen]);
},
'expanded'=>false,
'multiple'=>false
])
->add('submit',SubmitType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Product::class
]);
$resolver->setRequired(
['parentId','manOrWomen']
);
}
I have problem with the request:
"price" => "44" (This is the price for the current item.This is okay.)
"name" => "44" (This must be the name of current item.)
I have 'choice_value'=>'name' but I get the price instead name.
If I change first choice_value with another value,the second choice_value becomes equal to her.Why?
When I remove addSelect from first EntityType works fine,but if I add more one EntityType,then I have the same problem - thirth EntityType value becomes equal to second value ('name').
I would say your entity is returning the price in the getter of the name or the setter of the price is setting the value of name.