EntityType - Can not use query_builder - symfony

I have a problem with my FormType in Symfony. I have a field that allows me to check one or more checkboxs whose values represent objects from another entity. (In this case, types of holidays).
Except that I do not want to display them all, so I use a query_builder as such:
->add('typesConges', EntityType::class, [
'class' => TypeConge::class,
'choice_label' => 'nom',
'expanded' => true,
'multiple' => true,
'query_builder' => function (TypeCongeRepository $repoTypes) {
return $repoTypes->getTypesNotNull();
}
])
But it raised this error :
The name "Heures supp" contains illegal characters. Names should start
with a letter, digit or underscore and only contain letters, digits,
numbers, underscores ("_"), hyphens ("-") and colons (":").
However, if I remove the query_builder, I have all my TypeConge ( the "Heures supp" aswell).
GestionSoldes.php
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
class GestionSoldes
{
/**
* Types de congés
*
* #var Collection|TypeConge[]
*/
private $typesConges;
/**
* All types
*
* #var boolean
*/
private $allTypes;
public function __construct()
{
$this->typesConges = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #return Collection|TypeConge[]
*/
public function getTypesConges(): Collection
{
return $this->typesConges;
}
public function addTypesConge(TypeConge $typesConge): self
{
if (!$this->typesConges->contains($typesConge)) {
$this->typesConges[] = $typesConge;
}
return $this;
}
public function removeTypesConge(TypeConge $typesConge): self
{
if ($this->typesConges->contains($typesConge)) {
$this->typesConges->removeElement($typesConge);
}
return $this;
}
public function getAllTypes(): ?bool
{
return $this->allTypes;
}
public function setAllTypes(bool $allTypes): self
{
$this->allTypes = $allTypes;
return $this;
}
}
Form:
<?php
namespace App\Form;
use App\Entity\TypeConge;
use App\Entity\GestionSoldes;
use App\Repository\TypeCongeRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
class GestionSoldesType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('typesConges', EntityType::class, [
'class' => TypeConge::class,
'choice_label' => 'nom',
'expanded' => true,
'multiple' => true,
'query_builder' => function (TypeCongeRepository $repoTypes) {
return $repoTypes->getTypesNotNull();
}
])
->add('allTypes', CheckboxType::class, [
'required' => false,
'label' => 'Tous les types de congés',
'label_attr' => [
'class' => 'custom-control-label',
'for' => 'allTypes'
],
'attr' => [
'class' => 'custom-control-input',
'id' => 'allTypes'
]
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => GestionSoldes::class,
]);
}
}
My repo function:
/**
* Retourne les types de congés qui ont un solde initial différent de null ( pour form EntityType )
*
* #return void
*/
public function getTypesNotNull()
{
return $this->createQueryBuilder('t')
->where('t.soldeInitial is not null')
->orderBy('t.nom', 'ASC');
}

As it shows no errors when you remove te query-builer, The problem must come from the query-builder.
As the only moment you use the property nom in the query-builder is in
->orderBy('t.nom', 'ASC');
The problem is here.
Make sure that your ORM (doctrine or else) is ok with string containing spaces.
to verify my point try to remove the orderBy from your query

Related

Symfony - ManyToMany - replaces instead of adding

I apologize in advance if my question seems silly to you, I'm a beginner, I've searched but I can't find the answers.
We are in a factory. In this factory, each worker can have several posts, and each posts can contain several workers. So we are in a ManyToMany relationship. The problem is that when I add a worker to a post, he doesn't add to the worker already present in this post, he replaces him! As if a post could only contain one worker.
Can someone tell me what I'm doing wrong or send me precisely the documentation related to this type of problem?
Thanks.
Here is the related code.
(Poste = Post, Operateur = Worker)
in the Post Entity :
/**
* #ORM\ManyToMany(targetEntity=Operateur::class, inversedBy="postes")
* #ORM\JoinTable(name="poste_operateur")
*/
private $operateurs;
/**
* #return Collection|Operateur[]
*/
public function getOperateurs(): Collection
{
return $this->operateurs;
}
public function addOperateur(Operateur $operateur): self
{
if (!$this->operateurs->contains($operateur)) {
$this->operateurs[] = $operateur;
$operateur->addPoste($this);
}
return $this;
}
public function removeOperateur(Operateur $operateur): self
{
$this->operateurs->removeElement($operateur);
$operateur->removePoste($this);
return $this;
}
In the Operateur (worker) entity :
/**
* #ORM\ManyToMany(targetEntity=Poste::class, mappedBy="operateurs")
*/
private $postes;
/**
* #return Collection|Poste[]
*/
public function getPostes(): Collection
{
return $this->postes;
}
public function addPoste(Poste $poste): self
{
if (!$this->postes->contains($poste)) {
$this->postes[] = $poste;
$poste->addOperateur($this);
}
return $this;
}
public function removePoste(Poste $poste): self
{
if ($this->postes->removeElement($poste)) {
$poste->removeOperateur($this);
}
return $this;
}
In the PosteController, method to add an operateur to a post :
/**
* #Route("/{id}/new", name="poste_ope", methods={"GET", "POST"})
*/
public function addOpe(Request $request, Poste $poste): Response
{
$form = $this->createForm(PosteType2::class, $poste);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
$this->addFlash(
'success',
"L'opérateur a bien été ajouté au poste {$poste->getNom()} !"
);
return $this->redirectToRoute('operateur_index');
}
return $this->render('poste/addope.html.twig', [
'poste' => $poste,
'form' => $form->createView(),
]);
}
The form in PostType2 :
class PosteType2 extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('operateurs', EntityType::class, [
'class' => Operateur::class,
'label' => 'ajouter un opérateur à ce poste',
'choice_label' => 'nom',
'multiple' => true,
'expanded' => true,
])
->add('save', SubmitType::class, [
'label' => 'Enregistrer',
'attr' => [
'class' => 'btn btn-primary'
]
]);
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Poste::class,
]);
}
}
The problem was in the PosteController, here is the correction :
add an addPost
Here is the documentation who helped me : https://symfony.com/doc/current/doctrine/associations.html#saving-related-entities

Custom Variables in custom FormType

Got some question about passing custom variables to a custom FormType
I have a custom FormType named KontoType:
I pass some custom variables to it and this works like as expected, if i override the method buildForm and dump the passed $options array, the mandant exists and is a entity.
But how the heck can i now pass this custom variable to the function getChoices() which loads the choices based on the mandant in this custom FormType?
Even if i did reset the $options in the override buildForm function like $options['choices'] = $this->getChoices($options['mandant']) the select box is empty if i render this form.
<?php
namespace App\Form\Type;
use App\Entity\Core\Finanzen\Konto;
use App\Entity\Core\Organisation\Mandant;
use App\Services\LocaleService;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
class KontoType extends AbstractType
{
/**
* #var ObjectManager
*/
private $manager;
/**
* #var TranslatorInterface
*/
private $translator;
/**
* #var LocaleService
*/
private $localeService;
public function __construct(ObjectManager $manager, TranslatorInterface $translator, LocaleService $localeService)
{
$this->manager = $manager;
$this->translator = $translator;
$this->localeService = $localeService;
}
private function getChoices(Mandant $mandant=null)
{
return $this->manager->getRepository(Konto::class)->findBuchbar(true, $mandant);
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'label' => 'konto.name',
'help' => 'konto.help',
'choices' => null,
'attr' => array(
'class' => 'bs-select',
'aria-hidden' => 'true',
'ref' => 'input',
'multiple' => false,
'tabindex' => 1,
'data-live-search' => true,
'data-size' => 6
),
'choice_label' => function ($choiceValue, $key, $value) {
return $choiceValue->getKonto()." ".$this->localeService->doTranslate($choiceValue);
},
'choice_value' => function(Konto $konto = null) {
return $konto ? $konto->getId() : '' ;
},
'required' => true,
'multiple' => false,
'empty_data' => null,
'label_attr' => array(
'class' => 'control-label'
),
'placeholder' => 'message.bitte wählen',
'mandant' => null
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$options['choices'] = $this->getChoices($options['mandant']);
parent::buildForm($builder, $options); // TODO: Change the autogenerated stub
}
public function getParent() {
return ChoiceType::class;
}
}

symfony easyadmin form field type entity with filter list

I use symfony 3.4 and easycorp/easyadmin-bundle 1.17
This is my class "Quotation", the "artisan" field is an "under registration" of the "Person" entity (person.type = 1) :
class Quotation
{
/** others fields... */
/**
* 1 => 'artisan', 2 => 'customer'
*/
private $type;
/**
* #ORM\ManyToOne(targetEntity="Person", inversedBy="artisanQuotations", cascade= { "persist" })
* #ORM\JoinColumn(name="artisan_id", referencedColumnName="id")
*/
private $artisan;
/** getters and setters ... */
I have a problem with a form field using a custom field type
form:
fields:
...
- { property: 'artisan', label: '', type: 'AppBundle\Form\Field\ArtisanType' }
I created this form field type to be able to filter the list thanks to the query_builder :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('artisan', EntityType::class, array(
'class' => 'AppBundle:Person',
'label' => false,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('person')
->where('person.type = 1');
},
'attr' => array('data-widget' => 'select2'),
'multiple' => false,
'expanded'=> false
));
}
my form is displayed perfectly well but when i submit this form i have an error :
Expected argument of type "AppBundle\Entity\Person", "array" given
Thank you in advance for your help
Instead of using the buildForm method you should use configureOptions here. That way your form is not extended by another subform which results in the array.
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ArtisanType extends AbstractType
{
/**
* #param \Symfony\Component\OptionsResolver\OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'class' => 'AppBundle:Person',
'label' => false,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('person')
->where('person.type = 1');
},
'attr' => array('data-widget' => 'select2'),
'multiple' => false,
'expanded'=> false,
]);
}
/**
* #return string|null
*/
public function getParent()
{
return EntityType::class;
}
}

Expected argument of type "string", MyEntity given

I faced a problem when created a dropdown (category, subcategory) instead of input text fields in FormBuilderInterface
When I change it back to text input all working good.
Here is my code for FormType
namespace Expatservice\ManagerBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Doctrine\ORM\EntityRepository;
class ServiceType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('category', EntityType::class, array(
'class' => 'ExpatserviceCategoryBundle:Category',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.parent = 0')
->orderBy('c.title', 'ASC');
},
'choice_value' => 'title',
'choice_label' => 'title'
))
->add('subcategory', EntityType::class, array(
'class' => 'ExpatserviceCategoryBundle:Category',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->where('c.parent = 2')
->orderBy('c.title', 'ASC');
},
'choice_value' => 'title',
'choice_label' => 'title'
))
->add('description')
->add('image', FileType::class, array('data_class' => null, 'required'=>false));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaultOptions(array('data_class' => 'Expatservice\ManagerBundle\Entity\Service'));
}
public function getName()
{
return 'expantservice_managerbundle_service';
}
}
I understand the problem, but can't figure out how to fix it and don't found nothing in internet.
I should use __toString() magic function to get right data type when handle my form submitting.
To be sure that we'll get string, Entity part should look like this:
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
public function __toString() {
return $this->title;
}

FOS UserBundle - Override the FormFactory

i need some help overriding the FormFactory.
My Goal is to change the Profile. So, as i also use Facebook Login, i do not want them to change email, username and password.
So i use the ProfileController in my bundle to hand over the current user to the ProfileFormType class.
What i'm trying to do is to implement my own FormFactory, so i can set the user and put it into the options array inside the call
return $this->formFactory->createNamed($this->name, $this->type, null, array('validation_groups' => $this->validationGroups, 'user' => $this->user));
To achieve this, i need to define my FormFactory in sevices.yml.
Here is the original one from FOSUserBundle:
<service id="fos_user.profile.form.factory" class="FOS\UserBundle\Form\Factory\FormFactory">
<argument type="service" id="form.factory" />
<argument>%fos_user.profile.form.name%</argument>
<argument>%fos_user.profile.form.type%</argument>
<argument>%fos_user.profile.form.validation_groups%</argument>
</service>
I have difficulties to translate this into yml, as i do not understand the usages of aliases completely.
Could you help me to define it correct? Something like
skt_user.profile.form.factory:
class: SKT\UserBundle\Form\Factory\FormFactory
arguments: ???
Funny, after posting it, I found the solution. This is the correct configuration for my FormFactory:
skt_user.profile.form.factory:
class: SKT\UserBundle\Form\Factory\FormFactory
arguments: ["#form.factory", "%fos_user.profile.form.name%", "%fos_user.profile.form.type%", "%fos_user.profile.form.validation_groups%"]
In my controller, I simply used these 2 lines:
$formFactory = $this->container->get('skt_user.profile.form.factory');
$formFactory->setUser($user);
In the factory, I implemented this function
namespace SKT\UserBundle\Form\Factory;
use Symfony\Component\Form\FormFactoryInterface;
use FOS\UserBundle\Form\Factory\FactoryInterface;
class FormFactory implements FactoryInterface
{
private $formFactory;
private $name;
private $type;
private $validationGroups;
private $user;
public function __construct(FormFactoryInterface $formFactory, $name, $type, array $validationGroups = null)
{
$this->formFactory = $formFactory;
$this->name = $name;
$this->type = $type;
$this->validationGroups = $validationGroups;
}
public function createForm()
{
return $this->formFactory->createNamed($this->name, $this->type, null, array('validation_groups' => $this->validationGroups, 'user' => $this->user));
}
public function setUser($user)
{
$this->user = $user;
}
}
and this is how my Formtype looks
<?php
namespace SKT\UserBundle\Form\Type;
use SKT\CaromBundle\Repository\PlayerRepository;
use Symfony\Component\Form\FormBuilderInterface;
use FOS\UserBundle\Form\Type\RegistrationFormType as BaseType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ProfileFormType extends \FOS\UserBundle\Form\Type\ProfileFormType
{
private $class;
/**
* #param string $class The User class name
*/
public function __construct($class)
{
$this->class = $class;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Do not show email and username if login uses facebook
if (!$options['user']->getFacebookId()) {
$builder
->add('email', 'email', array('label' => 'form.email', 'translation_domain' => 'FOSUserBundle'))
->add('username', null, array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle'));
}
$builder
->add('firstname', null, array('label' => 'Vorname'))
->add('lastname', null, array('label' => 'Nachname'))
->add('player', 'entity', array(
'label' => 'Spieler',
'class' => 'SKTCaromBundle:Player',
'property' => 'name',
'query_builder' => function (PlayerRepository $er) {
return $er->createQueryBuilder('p')
->orderBy('p.name', 'ASC');
},
'empty_value' => 'Verbinde Dich mit einem Spieler',
'required' => false,
));
}
public function getName()
{
return 'skt_user_profile';
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => $this->class,
'intention' => 'profile',
'user' => null
));
}
}
works perfect!

Resources