Embedding a single object in form - php

I've manage to create a form embedded in another form but I think I'm not doing something right. Here's my code
Category
class Category
{
private $id;
private $name;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="category")
*/
private $subcategorues;
public function __construct()
{
$this->subcategorues = new \Doctrine\Common\Collections\ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function addSubcategorue(\AppBundle\Entity\Category $subcategorues)
{
$this->subcategorues[] = $subcategorues;
return $this;
}
public function removeSubcategorue(\AppBundle\Entity\Category $subcategorues)
{
$this->subcategorues->removeElement($subcategorues);
}
public function getSubcategorues()
{
return $this->subcategorues;
}
}
Subcategory
class Subcategory
{
private $id;
private $name;
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="subcategories")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
/**
* #return mixed
*/
public function getCategory()
{
return $this->category;
}
/**
* #param mixed $category
*/
public function setCategory($category)
{
$this->category = $category;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
}
CategoryType
.......
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'entity', [
'class' => 'AppBundle\Entity\Category',
'choice_label' => 'name'
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Category'
]);
}
......
SubcategoryType
$builder
->add('category', new CategoryType(), [
'label' => false
])
->add('name', 'text')
->add('save', 'submit')
;
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Subcategory'
]);
}
DefaultController
public function indexAction(Request $request)
{
$subcategory = new Subcategory();
$form = $this->createForm(new SubcategoryType(), $subcategory);
$form->handleRequest($request);
if($form->isValid()){
$em = $this->getDoctrine()->getManager();
$subcategory->setCategory($subcategory->getCategory()->getName());
$em->persist($subcategory);
$em->flush();
return new Response(sprintf('ID %d', $subcategory->getId()));
}
return $this->render('AppBundle::layout.html.twig', [
'form' => $form->createView(),
]);
}
Please notice this line of code $subcategory->setCategory($subcategory->getCategory()->getName());
I need that line in order to save the entity to the database otherwise I get an error. So my question is is there a way to skip this line of code and pass category object on the fly to subcategory->category property instead of doing that manually?
//EDIT
Here's the output of dump($form->getData());
DefaultController.php on line 33:
Subcategory {#467 ▼
-id: null
-name: "Uncharted"
-category: Category {#588 ▼
-id: null
-name: Category {#685 ▼
-id: 2
-name: "Games"
-subcategorues: PersistentCollection {#686 ▶}
}
-subcategorues: ArrayCollection {#660 ▶}
}
}

Your CategoryType is not correctly mapped compared to your Category entity. Actually, in your case, you don't need to have a sub-form CategoryType with a name field, since you have a category field in SubCategory which is a relationship towards Category.
Just replace:
->add('category', new CategoryType(), [
'label' => false
])
by:
->add('category', 'entity', [
'class' => 'AppBundle\Entity\Category',
'choice_label' => 'name'
]);

Could your try smth like this (for Category entity class):
public function addSubcategorue(\AppBundle\Entity\Category $subcategorues)
{
if ($this->subcategorues->contains($subcategorues)) {
$this->subcategorues->add($subcategorues);
$subcategorues->setCategory($this);
}
return $this;
}

Related

Argument 1 passed to Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue() must be an object or null, string given

BlogType
->add('category',EntityType::class,[
'class' => Category::class,
'choice_label' => function(Category $category) {
return $category->getName();
}
])
Category Entity
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
public function __toString() {
return $this->name;
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
Controller:
/**
* #Route("/edit-post/{id}", name="edit-post")
*/
public function editBlogPost(ManagerRegistry $manager, $id){
$post = $manager->getRepository(Blog::class)->find($id);
$form = $this->createForm(BlogType::class, $post);
$form->handleRequest($request);
dd($post);
}
Error:
Argument 1 passed to
Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader::getIdValue() must be
an object or null, string given
When I do dd in $post I get above error, Is there any soln to this?
I think that since you've implemented __toString() in the entity obj you don't need to define the choice_label in the BlogType.
But if you delete __toString() (and you should so you let Symfony deal with the form) you can simply write 'choice_label' => 'name'

ManytoMany ArrrayCollection In forms Symfony

I'm working on a Symfony project where an I have two types of User Client and EmployeSpie, both have their own entity.
When you create/edit a user you can link EmployeSpie to a CLient.
That's where is my problem, When I edit or create a user I can create a user but nothing is store inside my table which make the link between my table Client and EmployeSpie.
Here is what I've done:
my entity Client having this:
class Client extends User
{
/**
* #ORM\ManyToMany(targetEntity=EmployeSpie::class, mappedBy="clients", cascade={"persist"})
*/
private $employeSpies;
/**
* #return Collection|EmployeSpie[]
*/
public function getEmployeSpies(): Collection
{
return $this->employeSpies;
}
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
}
and my table EmployeSpie:
class EmployeSpie extends User
{
/**
* #ORM\ManyToMany(targetEntity=Client::class, inversedBy="employeSpies")
*/
private $clients;
/**
* #return Collection|Client[]
*/
public function getClients(): Collection
{
return $this->clients;
}
public function addClient(Client $client): self
{
if (!$this->clients->contains($client)) {
$this->clients[] = $client;
}
return $this;
}
public function removeClient(Client $client): self
{
if ($this->clients->contains($client)) {
$this->clients->removeElement($client);
}
return $this;
}
public function __toString()
{
return $this->getPrenom()." ".$this->getNom();
}
My forms are made with a Symfony form:
class ClientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email')
->add('password')
->add('nom')
->add('prenom')
->add('telephone')
->add('fax')
->add('is_active')
->add('client_fonction')
->add('site')
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'label' => 'Sélectionnez les emloyés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Client::class,
]);
}
}
and in my Controller I've made the following thing:
/**
* #Route("/admin/clients/create", name="admin.client.new")
* #param Request $request
* #return RedirectResponse|Response
*/
public function new(Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$client = new Client();
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$client->setRoles(array('ROLE_CUSTOMER'));
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
$this->em->persist($client);
$this->em->flush();
$this->addFlash('success', 'Nouveau client crée avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/create.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
/**
* #Route("/admin/clients/{id}", name="admin.client.edit", methods="GET|POST")
* #param Client $client
* #return Response
*/
public function edit(Client $client,Request $request, UserPasswordEncoderInterface $passwordEncoder)
{
$form = $this->createForm(ClientType::class, $client);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$clientEmploye = $request->request->get('client');
$clientEmploye = $clientEmploye['employeSpies'];
$client->setPassword(
$passwordEncoder->encodePassword(
$client,
$form->get('password')->getData()
)
);
foreach ($form->get('employeSpies')->getData() as $employe){
$client->addEmployeSpy($employe);
}
$client->setRoles(array('ROLE_CUSTOMER'));
$this->em->flush();
$this->addFlash('success', 'Nouveau client modifié avec succès');
$this->redirectToRoute('admin.clients.index');
}
return $this->render("admin/clients/edit.html.twig", [
'client' => $client,
'form' => $form->createView()
]);
}
Si my user is created or edited normally but I did not store the link for employeSpies in my form. Do you have any idea why?
I found the answer to my problem.
#Jakumi was right but few other cha ges were needed.
In my client Entity I has to change :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClientEmploye($this);
}
return $this;
}
to :
public function addEmployeSpy(EmployeSpie $employeSpy): self
{
if (!$this->employeSpies->contains($employeSpy)) {
$this->employeSpies[] = $employeSpy;
$employeSpy->addClient($this);
}
return $this;
}
Same thing for the remove.
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClientEmploye($this);
}
return $this;
}
to :
public function removeEmployeSpy(EmployeSpie $employeSpy): self
{
if ($this->employeSpies->contains($employeSpy)) {
$this->employeSpies->removeElement($employeSpy);
$employeSpy->removeClient($this);
}
return $this;
}
But after the other change in my ClientType :
->add('employeSpies', EntityType::class, array(
'class' => EmployeSpie::class ,
'by_reference' => false,
'label' => 'Sélectionnez les employés rattachés à ce client',
'expanded' => false,
'multiple' => true,
))
I need to add the 'by_reference' => false,to make it works.
Because of this Symfony will not try to find the "setClient" method but to find addClient method
Hope it could help later some other persons :)

symfony submitting to link table entity

I've been staring at this too long, and now I need another set of eyes.
I had previously set up my relationship between two entities, Dish and Ingredient as a many to many relationship, and had the form association working perfectly. However, I realized afterward that I needed another field on my link table to specify "amount" so as a result I created a new entity DishIngredient. It created the same table but instead of a many to many, it's now one table with two Many to One relationships to Dish and Ingredient.
So far so good. I have everything working until I attempt to associated ingredients with dishes. I'm able to successfully generate a form to display each of the Ingredients, however when I submit it, I run into problems. It's attempting to submit to Ingredient instead of DishIngredient.
Here is what I have so far:
My controller:
/**
* #Route("/recipe/ingredient/{id}", name="edit_ingredients")
*/
public function ingredientEdit(Request $request, Dish $dish, $id)
{
$user = $this->getUser();
$dish_id = $dish->getId();
$dish = $this->getDoctrine()->getRepository(Dish::class)->findOneBy(array('id' =>$dish_id ));
$dish_user = $dish->getUser();
//in case someone tries to manually hack into someone else's recipe
if($dish_user != $user) {
return $this->render('dishes/error.html.twig', array(
'dish' => $dish,
'user' => $user
)
);
}
else {
$form = $this->createForm(IngredientType::class, $dish);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$dish = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($dish);
$em->flush();
return $this->redirectToRoute('edit_ingredients', array('id' => $id));
}
return $this->render('dishes/ingredients.html.twig', array(
'form' => $form->createView(),
'dish' => $dish
)
);
}
}
Which then loads this form:
class IngredientType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options); // TODO: Change the autogenerated stub
$ingredient = new Ingredient();
$builder
->add('DishIngredients',EntityType::class, array(
'required' => false,
'attr' => array('class' => 'form-control'),
'class' => Ingredient::class,
'query_builder' => function(IngredientRepository $ir) {
return $ir->createQueryBuilder('s')
->orderBy('s.name', 'ASC');
},
'multiple' => true,
'expanded' => true,
))
->add('save', SubmitType::class, array(
'label' => 'Update',
'attr' => array('class' => 'btn btn-primary mt-3')
))
->getForm();
}
}
It displays fine in the twig with the following:
{{ form_start(form) }}
{% for i in form.DishIngredients %}
{{ form_widget(i) }} {{ form_label(i) }}<br>
{% endfor %}
{{ form_end(form) }}
However the problem is that when I attempt to submit it, I get this error:
Expected value of type "App\Entity\DishIngredient" for association
field "App\Entity\Dish#$dishIngredients", got "App\Entity\Ingredient"
instead.
If I change the form to call DishIngredient instead of Ingredient, it shows none of the ingredient; it just creates a text field looking for an input; not what I want or need at all.
Here's the DishIngredient Entity:
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\DishIngredientRepository")
*/
class DishIngredient
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Dish", inversedBy="dishIngredients")
*/
private $dish;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Ingredient", inversedBy="dishIngredients")
*/
private $ingredient;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $amount;
public function getId(): ?int
{
return $this->id;
}
public function getDish(): ?Dish
{
return $this->dish;
}
public function setDish(?Dish $dish): self
{
$this->dish = $dish;
return $this;
}
public function getIngredient(): ?Ingredient
{
return $this->ingredient;
}
public function setIngredient(?Ingredient $ingredient): self
{
$this->ingredient = $ingredient;
return $this;
}
public function getAmount(): ?string
{
return $this->amount;
}
public function setAmount(?string $amount): self
{
$this->amount = $amount;
return $this;
}
}
and here's the Ingredient entity for reference
/**
* #ORM\Entity(repositoryClass="App\Repository\IngredientRepository")
*/
class Ingredient
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $name;
/**
* #ORM\OneToMany(targetEntity="App\Entity\DishIngredient", mappedBy="ingredient")
*/
private $dishIngredients;
public function __toString(): ?string
{
// TODO: Implement __toString() method.
return $this->name;
}
public function __construct()
{
$this->dishes = new ArrayCollection();
$this->dishIngredients = 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|DishIngredient[]
*/
public function getDishIngredients(): Collection
{
return $this->dishIngredients;
}
public function addDishIngredient(DishIngredient $dishIngredient): self
{
if (!$this->dishIngredients->contains($dishIngredient)) {
$this->dishIngredients[] = $dishIngredient;
$dishIngredient->setIngredient($this);
}
return $this;
}
public function removeDishIngredient(DishIngredient $dishIngredient): self
{
if ($this->dishIngredients->contains($dishIngredient)) {
$this->dishIngredients->removeElement($dishIngredient);
// set the owning side to null (unless already changed)
if ($dishIngredient->getIngredient() === $this) {
$dishIngredient->setIngredient(null);
}
}
return $this;
}}
Anyone have any ideas here?
--
EDIT:
Okay, so I created a new form titled DishIngredientType, and moved the information from above into it, and then modified IngredientType to have following instead:
$builder
->add('DishIngredients',CollectionType::class, array(
'required' => false,
'attr' => array('class' => 'form-control'),
'entry_type' => DishIngredientType::class,
'entry_options' => ['label' => false],
))
but now I'm only getting a plan text field (no options at all).
This is how they look in DishIngredientType
->add('DishIngredients',EntityType::class, array(
'required' => false,
'attr' => array('class' => 'form-control'),
'class' => Ingredient::class,
'query_builder' => function(IngredientRepository $ir) {
return $ir->createQueryBuilder('s')
->orderBy('s.name', 'ASC');
},
'multiple' => true,
'expanded' => true,
))
I'm not sure what I'm missing here. I know this shouldn't be this difficult.

Symfony2 DataTransformer after handleRequest

I have an API and I am sending a reference of an entity, I'm using a DataTransformer to get my entity but the DataTransformer is always called before the $form->handleRequest($request) the value is always null and it could't works
My Controller
public function newAction(Request $request)
{
$orderNewFormType = $this->get('competitive_bo.api_bundle.form.type.order_new');
$card = new Card();
try {
$form = $this->createForm($orderNewFormType, $card);
$form->handleRequest($request);
} catch (TransformationFailedException $e) {
return $this->notFoundErrorResponse(
'Business not found'
);
}
if ($form->isValid()) {
return $this->okResponse(array());
}
$validatorErrorFormatter = $this->get('competitive_bo.api_bundle.formatter.validator_error');
$errors = $validatorErrorFormatter->formatFromFormError($form->getErrors(true));
return $this->badRequestErrorResponse(
'Invalid data',
$errors
);
}
The form type
class OrderNewFormType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('customer', 'entity', array(
'class' => 'CompetitiveBOBusinessBundle:Customer',
'property' => 'id'
))
->add('business', 'business', array(
'mapped' => false,
))
;
}
/**
* {#inheritdoc}
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
'data_class' => Card::class
));
}
public function getName()
{
return null;
}
}
The Business form type
class BusinessReferenceFormType extends AbstractType
{
/**
* #var ReferenceToBusinessTransformer
*/
private $referenceToBusinessTransformer;
public function __construct(ReferenceToBusinessTransformer $referenceToBusinessTransformer)
{
$this->referenceToBusinessTransformer = $referenceToBusinessTransformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addViewTransformer($this->referenceToBusinessTransformer);
}
public function getName()
{
return 'business';
}
public function getParent()
{
return 'text';
}
}
And the DataTransformer
/**
* Class ReferenceToBusinessTransformer
*/
class ReferenceToBusinessTransformer implements DataTransformerInterface
{
/**
* #var BusinessRepository
*/
private $businessRepository;
public function __construct(BusinessRepository $businessRepository)
{
$this->businessRepository = $businessRepository;
}
/**
* {#inheritdoc}
*/
public function transform($reference)
{
var_dump($reference);
$business = $this->businessRepository->findOneBy(array(
'reference' => $reference
));
if (null === $business) {
throw new TransformationFailedException;
}
return $business;
}
/**
* {#inheritdoc}
*/
public function reverseTransform($value)
{
if (!($value instanceof Business)) {
throw new TransformationFailedException;
}
return $value->getReference();
}
}
The var_dump($reference) is always null
And I have my test
public function testNewAction($getParams, $postParam, $responseCode)
{
$client = static::createClient();
$router = $client->getContainer()->get('router');
$route = $router->generate('competitivebo_api_order_new',$getParams);
$client->request('POST', $route, $postParam);
$response = $client->getResponse();
$this->assertJsonResponse($response, $responseCode);
}
With the post params
'customer' => 1,
'business' => LoadBusinessData::REFERENCE_1,
'name' => 'Test',
The exception TransformationFailedException is always thrown during the $this->createForm(...) so the request is not handled
According with the documentation,
When null is passed to the transform() method, your transformer should return an equivalent value of the type it is transforming to (e.g. an empty string, 0 for integers or 0.0 for floats).

Form edition for a N:M relationship with extra fields is not working

I'm working on a form that handle N:M relationship with an extra parameter (extra field/column). This is what I've done until now:
In OrdersType.php form:
class OrdersType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
// $builder fields
// $builder fields only need on edit form not in create
if ($options['curr_action'] !== NULL)
{
$builder
// other $builder fields
->add("orderProducts", "collection", array(
'type' => new OrdersHasProductType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
));
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Tanane\FrontendBundle\Entity\Orders',
'render_fieldset' => FALSE,
'show_legend' => FALSE,
'intention' => 'orders_form',
'curr_action' => NULL
));
}
public function getName()
{
return 'orders';
}
}
In OrderHasProductType.php:
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
->add('amount', 'text', array(
'required' => TRUE,
'label' => FALSE
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Tanane\FrontendBundle\Entity\OrderHasProduct',
'intention' => 'order_has_product'
));
}
public function getName()
{
return 'order_has_product';
}
}
And finally this is Orders.php and OrdersHasProduct.php entities:
class Orders {
use IdentifiedAutogeneratedEntityTrait;
// rest of fields for the entity
/**
* #ORM\OneToMany(targetEntity="OrderHasProduct", mappedBy="order", cascade={"all"})
*/
protected $orderProducts;
protected $products;
/**
* #ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function __construct()
{
$this->orderProducts = new ArrayCollection();
$this->products = new ArrayCollection();
}
public function getOrderProducts()
{
return $this->orderProducts;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
public function getProduct()
{
$products = new ArrayCollection();
foreach ($this->orderProducts as $op)
{
$products[] = $op->getProduct();
}
return $products;
}
public function setProduct($products)
{
foreach ($products as $p)
{
$ohp = new OrderHasProduct();
$ohp->setOrder($this);
$ohp->setProduct($p);
$this->addPo($ohp);
}
}
public function getOrder()
{
return $this;
}
public function addPo($ProductOrder)
{
$this->orderProducts[] = $ProductOrder;
}
public function removePo($ProductOrder)
{
return $this->orderProducts->removeElement($ProductOrder);
}
}
/**
* #ORM\Entity
* #ORM\Table(name="order_has_product")
* #Gedmo\SoftDeleteable(fieldName="deletedAt")
* #UniqueEntity(fields={"order", "product"})
*/
class OrderHasProduct {
use IdentifiedAutogeneratedEntityTrait;
/**
* Hook timestampable behavior
* updates createdAt, updatedAt fields
*/
use TimestampableEntity;
/**
* #ORM\ManyToOne(targetEntity="\Tanane\FrontendBundle\Entity\Orders", inversedBy="orderProducts")
* #ORM\JoinColumn(name="general_orders_id", referencedColumnName="id")
*/
protected $order;
/**
* #ORM\ManyToOne(targetEntity="\Tanane\ProductBundle\Entity\Product", inversedBy="orderProducts")
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
*/
protected $product;
/**
* #ORM\Column(type="integer", nullable=false)
*/
protected $amount;
/**
* #ORM\Column(name="deletedAt", type="datetime", nullable=true)
*/
protected $deletedAt;
public function setOrder(\Tanane\FrontendBundle\Entity\Orders $order)
{
$this->order = $order;
}
public function getOrder()
{
return $this->order;
}
public function setProduct(\Tanane\ProductBundle\Entity\Product $product)
{
$this->product = $product;
}
public function getProduct()
{
return $this->product;
}
public function setAmount($amount)
{
$this->amount = $amount;
}
public function getAmount()
{
return $this->amount;
}
public function getDeletedAt()
{
return $this->deletedAt;
}
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
}
}
But when I try to edit a order with this code in my controller:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('FrontendBundle:Orders')->find($id);
$type = $order->getPerson()->getPersonType() === 1 ? "natural" : "legal";
$params = explode('::', $request->attributes->get('_controller'));
$actionName = substr($params[1], 0, -6);
$orderForm = $this->createForm(new OrdersType(), $order, array('action' => '#', 'method' => 'POST', 'register_type' => $type, 'curr_action' => $actionName));
return array(
"form" => $orderForm->createView(),
'id' => $id,
'entity' => $order
);
}
I get this error:
The form's view data is expected to be of type scalar, array or an
instance of \ArrayAccess, but is an instance of class
Proxies__CG__\Tanane\ProductBundle\Entity\Product. You can avoid this
error by setting the "data_class" option to
"Proxies__CG__\Tanane\ProductBundle\Entity\Product" or by adding a
view transformer that transforms an instance of class
Proxies__CG__\Tanane\ProductBundle\Entity\Product to scalar, array or
an instance of \ArrayAccess.
And I don't find or know how to fix it, can any give me some help?
I think this is happening because this code
class OrdersHasProductType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('product', 'text', array(
'required' => FALSE,
'label' => FALSE
))
));
}
//...
}
means that Symfony is expecting "product" to be a field of type "text", but when it calls getProduct() on the OrderHasProduct it gets a Product object (or a Doctrine Proxy to a Product, since it's not been loaded at that point). Symfony Fields inherit from Form/AbstractType, so they're essentially Forms in their own right, with just one field, hence the error message.
The solution is either to make that field of type "entity", or to create a different method which only gives the name of the Product, e.g. getProductName() on OrderHasProduct, and then use that as the data behind the field.

Categories