Symfony - Can't get a way to read the property (PropertyAccessor) - symfony

I develop with symfony a form for create tickets but when i try i got this error:
my function buildform from the file tickettype.php:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('Titre', TextType::class)
->add('Message', TextType::class)
->add('Date', DateTimeType::class, ['data' => new \DateTime()] )
->add('Demandeur', EntityType::class, [
'class' => Client::class,
'choice_label' => 'Nom',
])
->add('Agent', EntityType::class, [
'class' => Dealer::class,
'choice_label' => 'Nom',
])
->add('Etat_Ticket', EntityType::class, [
'class' => Etat::class,
'choice_label' => 'Statut',
]);
}
and in the controller :
/**
* #Route("/add/", name="add_ticket")
*
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function addTicketAction(Request $request)
{
$ticket = new Ticket();
$form = $this->createForm(TicketType::class, $ticket);
$form->add('send', SubmitType::class, ['label' => 'créé un nouveau ticket']);
$form->handleRequest($request);
if($form->isSubmitted()){
$ticket->setDate(new \DateTime());
$em = $this->getDoctrine()->getManager();
$em->persist($ticket);
$em->flush();
return $this->redirectToRoute('List_ticket');
}
return $this->render("add.html.twig", array('form' => $form->createView()));
}
and my entity Ticket have this property:
/**
* #ORM\ManyToOne(targetEntity=Etat::class, inversedBy="Etat_Ticket")
* #ORM\JoinColumn(nullable=false)
*/
private $Etat_Ticket;
link to the entity Etat which look like this :
/**
* Etat
*
* #ORM\Table(name="etat")
* #ORM\Entity
*/
class Etat
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="statut", type="string", length=255, nullable=false)
*/
private $statut;
public function getId(): ?int
{
return $this->id;
}
public function getStatut(): ?string
{
return $this->statut;
}
public function setStatut(string $statut): self
{
$this->statut = $statut;
return $this;
}
}

You don't have a getter for Etat_Ticket property, so symfony (and that's a PHP common rule, when the property is not public) can't read its value from outside class scope. Symfony Form component, here, is trying by default to use the getter or access the property directly if it were public, and as neither getter nor public property are found, it symply doesn't know how to retrieve the value.
You can feed the form by yourself (docs) or use property_path.
Remember also that binding entities (or in general the domain model) directly to a form is good for RAD (rapid application development) but not so good in the long term. I would suggest to use a sort of DTO in order to read and write from and to the model (take a look here in order to get an idea about this concept)

Related

symfony - dropdown menu doesn't select the option

I made a page on symfony to administrate some products with a dropdown menu linked to a category table.
The categoryid is well saved on the product, but the dropdown never select the good option, I don't find why.
Here is the category part in my class Dproduct :
/**
* #ORM\ManyToOne(targetEntity=RCategory::class, inversedBy="products")
* #ORM\JoinColumn(name="categoryId", referencedColumnName="categoryId", onDelete="CASCADE")
*/
private $categoryId;
public function getCategoryId(): ?RCategory
{
return $this->categoryId;
}
public function setCategoryId(?RCategory $categoryId): self
{
$this->categoryId = $categoryId;
return $this;
}
here is my class RCategory:
/**
* RCategory
*
* #ORM\Table(name="r_category")
* #ORM\Entity
*/
class RCategory
{
/**
* #var int
*
* #ORM\Column(name="categoryId", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $categoryId;
/**
* #var string
*
* #ORM\Column(name="categoryLib", type="string", length=50, nullable=false)
*/
private $categoryLib;
/**
* #Gedmo\Slug(fields={"categoryLib"})
* #ORM\Column(type="string", length=128, unique=true)
*/
public function getCategoryId(): ?int
{
return $this->categoryId;
}
public function getCategoryLib(): ?string
{
return $this->categoryLib;
}
public function setCategoryLib(string $categoryLib): self
{
$this->categoryLib = $categoryLib;
return $this;
}
here is my buildForm function :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('categoryId', ChoiceType::class, [
'mapped' => false,
'choices' => $options['choiceCategory'],
'label' => 'Catégorie'
])
->add('productLib', TextType::class, [
'label' => 'Libellé',
])
->add('Enregister', SubmitType::class)
;
}
And my choiceCategory function :
public function choiceCategory(){
$choices = [];
$categories = $this->getCategory();
foreach ($categories as $categorie) {
$choices[$categorie->getCategorylib()] = $categorie->getCategoryid();
}
return $choices;
}
And finaly my controller :
$product = $this->getDoctrine()
->getRepository('App:DProduct')
->findOneBy(array('slug' => $slug));
...
$form = $this->createForm(productType::class, $product, array('choiceCategory'=>$categoryController->choiceCategory()));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
... Data is well saved ...
}
return $this->render(
'form/meuble.html.twig',
array(
'form' => $form->createView(),
'titlePage' => $titlePage,
'product' => $product
)
);
Does anyone see where is the problem ?
Thanks,
Best regards,
Matthieu
You are using an unmapped field, therefore it won't set any data based on the product you are editing.
You can set the data with de data option
$product = $builder->getData();
...
->add('categoryId', ChoiceType::class, [
'mapped' => false,
'choices' => $options['choiceCategory'],
'label' => 'Catégorie'
'data' => $product->getCategory(),
])
U might be able to use a mapped field and use the EntityType instead of the ChoiceType to build the choices. Notice the choice_label and query_builder options.

Symfony Forms OneToMany/ManyToOne selector problems

I am trying to create a Form with a Category selector for a Page entity - Pages can have many categories in multiple Registries.
The relationship from Page --> Category is a OneToMany/ManyToOne with an intermediate PagesCategoryEntity that has a discriminator property (categoryRegistryId).
I have successfully figured out how to use the 'entity' Type in the FormBuilder to create ONE multiple select box. But in the end, I will need to have multiple select-boxes (for each registry) with a discriminator value in the html somewhere.
So, I need to know how to get the additional properties of PagesCategoryEntity into the Form and then how I can access them in the getters/setters of the PageEntity.
Surely, I cannot be the only person to have values in the intermediate entity that need to be accessible in the form and persistence layer?
I appreciate you taking the time to look at this!
craig
truncated Entity and Form classes for Brevity.
class CategoryEntity
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
// other properties, getters, setters, etc...
}
class PageEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="PagesCategoryEntity",
* mappedBy="page", cascade={"all"},
* orphanRemoval=true, indexBy="categoryRegistryId")
*/
private $categories;
// other properties, getters, setters, etc...
}
class PagesCategoryEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
private $id;
/**
* #ORM\Column(type="integer")
*/
private $categoryRegistryId;
/**
* #ORM\ManyToOne(targetEntity="CategoryEntity")
* #ORM\JoinColumn(name="categoryId", referencedColumnName="id")
*/
private $category;
/**
* #ORM\ManyToOne(targetEntity="PageEntity", inversedBy="categories")
* #ORM\JoinColumn(name="entityId", referencedColumnName="pageid")
*/
private $page;
}
class PageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('categories', 'entity', array(
'class' => 'MyCoolBundle:CategoryEntity',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.parent = :parent')
->setParameter('parent', 19)
->orderBy('c.name', 'ASC');
},
'property' => "name",
'multiple' => true,
'required' => false,
'empty_data' => null,
));
}
}
Try this then:
->add('categories',
'entity',
array(
'class'=>'Acme\MycoolBundle\Entity\Category',
'property'=>'name',
'query_builder' => function (\Acme\MycoolBundle\Entity\CategoryRepository $repository)
{
return $repository->createQueryBuilder('c')
->where('c.parent = :parent')
->setParameter('parent', 19)
->add('c.name', 'ASC');
}
)
);
try to create a category Repository if u don't have and adapt the scripts for ur needs it works for me!
Try to use Collection instead of using Entity!
Collection is used in one to many/ many to one
you can try the tutorial of symfony cookbook for collection forms
http://symfony.com/doc/current/cookbook/form/form_collections.html
i hope it helps ;)

symfony2 form with a many to many entity

I have this form with manyTomany relation working perfectly like this:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('manifestations', 'entity', array(
'class' => 'PrifProtocoleBundle:Manifestation',
'multiple' => true,
'expanded' => false,
'property' => 'libelle',
'empty_value' => 'Choississez',
'required' => false,));
}
but i want to set the'multiple' parameter to 'false', this way, i just have a select box with the option 'Choississez', so when i click on it, it displays all the other values. Unfortunately i get an error message: nor of the methods _set()" or "_call()" exist and have public access in class. i've been searching for some solutions on the web and tried this one:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('manifestations', 'collection', array(
'type' => 'entity',
'options' => array(
'class' => 'AcmeProtoBundle:Manifestation',
'multiple' => false,
'expanded' => false,
'property' => 'libelle',
'empty_value' => 'Choisissez',
'required' => false,)));
}
i have no error message! but the select form doesn't display even when i set the 'multiple' to 'true, i only have the submit button, when clicked shows me the results, so i think i miss something in the parameters to display the form!
can anyone help? Thanks
Manifestation.php
/**
* #ORM\Entity
* #ORM\Entity(repositoryClass="ManifestationRepository")
*/
class Manifestation {
public function __construct() {
$this->dateCreation = new \DateTime;
$this->dateModif = new \DateTime;
}
public function __toString() {
return $this->getLibelle();
}
/**
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Id
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="integer")
* #Assert\GreaterThan(
* value = 0,
* message = "La valeur doit être positive"
* )
*/
private $numOrdre;
/**
* #ORM\Column(type="string",length=50)
* #Assert\Length(
* min = "5",
* minMessage = "Le libellé doit faire au moins {{ limit }} caractères"
* )
*/
private $libelle;
/**
* #ORM\Column(type="datetime")
*/
private $dateCreation;
/**
* #ORM\Column(type="datetime")
*/
private $dateModif;
/**
* #ORM\Column(type="boolean")
* #Assert\NotBlank( message=" ")
*/
private $etat;
//getters and setters
invite.php
/**
* #ORM\Entity
* #ORM\Entity(repositoryClass="InviteRepository")
*
*/
class Invite {
/**
* #var boolean
*
* #ORM\ManyToMany(targetEntity="Acme\ProtoBundle\Entity\Manifestation", cascade={"persist"})
* #Assert\NotBlank(message=" ")
*/
private $manifestations;
Can you show your manifestation.php file (your entity)?
Multiple doesn't have the behaviour you are looking for : Multiple is used to allow a user to check multiple checkboxes (true) or only one (false) of a given form (symfony doc : multiple).
In your case a common solution is to use javascript on a parent field that would disable/enable the children fields. Make sure to add server-side validation on these fields if you go for this.
This is the solution working for me now with 'multiple' => false':
i've added this function in the other entity in relation with Manifestation, to consider manifestations as an array
public function setManifestations($manifestations){
if(!is_array($manifestations)){
$manifestations = array($manifestations);
}
$this->manifestations = $manifestations;
}

Delete an item from oneToMany relationship

I have the following Gallery entity
class Gallery
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var ArrayCollection
* #ORM\OneToMany(targetEntity="Tessa\GalleryBundle\Entity\Photo", mappedBy="gallery", cascade={"persist", "remove"})
*/
private $photos;
/* ... */
}
This gallery is linked with a manyToOne relationship to a PointOfInterest entity. Here is the declaration
class PointOfInterest
{
/* ... */
/**
* #ORM\ManyToOne(targetEntity="Tessa\GalleryBundle\Entity\Gallery", cascade={"persist", "remove"})
* #ORM\JoinColumn(nullable=false)
*/
private $gallery;
/* ... */
I also use a Form to update the PointOfInterest entity. Here is the form declaration
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text')
->add('gallery', new GalleryType())
;
}
and the GalleryType declaration.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('photos', 'collection', array('type' => new PhotoType(),
'required' => false,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false
))
;
}
When I edit the PoI I can add photos to the gallery without problem, but I can't delete anything.
I tried to hook on gallery PreUpdate, but it is never called. I printed output in removePhotos method of Gallery entity, and the photos are removed from the gallery. I then suspect the Gallery to never be persisted.
Here is the code when I persist the PoI after editing.
private function handleForm($elem, $is_new)
{
$form = $this->createForm(new CircuitType, $elem);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($elem);
$em->flush();
return $this->redirect($this->generateUrl('tessa_circuit_index'));
}
}
return $this->render('TessaUserBundle:Circuits:add.'.'html'.'.twig',
array(
'form' => $form->createView(),
'is_new' => $is_new,
));
}
There is article in Symfony2 cookbook about handling this type of situation. As you have OneToMany relationship, you have to remove related objects manually in controller.
Edit:
Or you can make use of Doctrine's orphan removal feature.
class Gallery
{
//...
/**
* #ORM\OneToMany(targetEntity="Photo", mappedBy="gallery", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private $photos;
//...
public function removePhotos($photo)
{
$this->photos->remove($photo);
$photo->setGallery(null);
}
}

Exclude certain values in ManytoOne Array Colletion/Formbuilder

I am having trouble getting a formular in Symfony2 where I want to exclude certain values within an array collection - or I have to say I don't know how (where to exclude them).
This is my newTag Action:
public function newTagAction()
{
$tag = new Tag();
$form = $this->createForm(new tagType(), $tag);
return $this->render('MyMyBundle:Admin:newTag.html.twig', array('form' => $form->createView()));
}
And Tag.php Entity, which has a ManyToOne relation to Movie and vice verca (Movie->Tag = OneToMany):
class Tag
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $name;
/**
* #ORM\ManyToOne(targetEntity="Movie", inversedBy="videotags")
* #ORM\JoinColumn(name="movie_id", referencedColumnName="id")
*/
protected $movie;
// ...
In the TagType.php form it says:
class TagType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('name')
->add('movie') // This is where certain movies should be excluded, it displays an array collection of all movies
;
}
Any help appreciated!
Thanks!
You can use custom queries to get only the results you want.
It's explained in the documents. Here is a quick example:
$builder->add('movie', 'entity', array(
'class' => 'MyMovieBundle:Movie',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.name = ?1');
},
));

Resources