Additional Choice field for ordering - forms

I want to set the order for new entry. I need order to first position and order after one of the existing entries
I don't know how to manage this in Symfony 4.2
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nameDe')
->add('nameEn')
->add('descriptionDe')
->add('descriptionEn')
->add('rank', EntityType::class, [
'class' => ProductType::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('p')
->orderBy('p.rank', 'ASC');
},
'choice_label' => 'nameDe',
])
->add('active')
->add('creatDate')
->add('updateDate', DateTimeType::class, array('data' => new \DateTime()));
}
I have this:
<select id="product_type_rank" name="product_type[rank]">
<option value="1">Internetseiten</option>
<option value="2">Printmedia</option>
</select>
I need something like this
<select id="product_type_rank" name="product_type[rank]">
<option value="0">At the beginning</option>
<option value="1">after Internetseiten</option>
<option value="2">after Printmedia</option>
</select>

If you want to add custom text in your options, you can use the choice_label option like that :
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nameDe')
->add('nameEn')
->add('descriptionDe')
->add('descriptionEn')
->add('rank', EntityType::class, [
'class' => ProductType::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('p')
->orderBy('p.rank', 'ASC');
},
'choice_label' => function($productType) {
return 'after ' . $productType->getNameDe();
},
'placeholder' => 'At the beginning',
])
->add('active')
->add('creatDate')
->add('updateDate', DateTimeType::class, array('data' => new \DateTime()));
}
With this one, you will have the expected result.
You can add a specific getter into your ProductType entity class and use it directly in the choice_label, like that :
ProductType.php
class ProductType {
...
getNameDeWithCustomText() {
return 'after ' . $this->getNameDe();
}
}
'choice_label' => 'nameDeWithCustomText',

If you want to add a default option to your EntityType field, you can add a placeholder option like this
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nameDe')
->add('nameEn')
->add('descriptionDe')
->add('descriptionEn')
->add('rank', EntityType::class, [
'class' => ProductType::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('p')
->orderBy('p.rank', 'ASC');
},
'choice_label' => 'nameDe',
'placeholder' => 'At the beginning',
])
->add('active')
->add('creatDate')
->add('updateDate', DateTimeType::class, array('data' => new \DateTime()));
}
As I see, you are handling multiple languages in your form, if you want to internationalize your placeholder, just put the translation key directly in the value (you need to install the Symfony translation package : https://symfony.com/doc/current/translation.html)
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('nameDe')
->add('nameEn')
->add('descriptionDe')
->add('descriptionEn')
->add('rank', EntityType::class, [
'class' => ProductType::class,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('p')
->orderBy('p.rank', 'ASC');
},
'choice_label' => 'nameDe',
'placeholder' => 'foo.bar.placeholder',
])
->add('active')
->add('creatDate')
->add('updateDate', DateTimeType::class, array('data' => new \DateTime()));
}
If the translation files don't exist, create them in translations/ folder
# translations/messages.en.yaml
foo:
bar:
placeholder: At the beginning
# translations/messages.de.yaml
foo:
bar:
placeholder: Am Anfang

Related

Symfony: how to cache a FormInterface object

I have a form type in Symfony that shows in every page list and I'd like to catch it to avoid unnecessary database queries as it uses two EntityTypes fields:
->add('brand', EntityType::class, [
'required' => false,
'class' => Brand::class,
'choice_label' => 'name',
'query_builder' => function (BrandRepository $er) {
return $er->createQueryBuilder('b')
->orderBy('b.name', 'ASC');
},
])
->add('car_manufacturer', EntityType::class, [
'class' => CarManufacturer::class,
'choice_label' => 'name',
'required' => false,
'query_builder' => function (CarManufacturerRepository $er) {
return $er->createQueryBuilder('m')
->orderBy('m.name', 'ASC');
},
])
->add('Search', SubmitType::class);
So in the controller I tried to do this:
private function getFiltersForm(): FormInterface {
$cachedForm = $this->cache
->getItem('form_list_filters')
->expiresAfter(3600*24);
if (!$cachedForm->isHit()) {
$form = $this->formFactory->createNamedBuilder('', SearchItemType::class)->getForm();
$cachedForm->set($form);
$this->cache->save($cachedForm);
}
return $cachedForm->get();
}
But it doesn't work, the isHit()is always false and the form is always regenerated which makes me thing there must be some problem on the save process.
Any idea? thanks in advance

Can't get a way to read the property "title" in class "App\Entity\Travel" triggered by $form->createView()

I am getting the following error on my symfony page. Using a CRUD system when I try to edit one item, I fall onto the following error:
Can't get a way to read the property "title" in class
"App\Entity\Travel".
My "Travel" entity has no such "title" property as it is not expected. The only place a "title" property is defined is in the TravelTranslation entity, which is in a ManyToOne relationship with travel.
After I have commented all references to the form in my twig templates all I find is that the error is triggered by $form->createView() in my controller.
/**
* #Route("/{id}/edit", name="travel_edit", methods={"GET","POST"})
*/
public function edit(Request $request, Travel $travel): Response
{
$entityManager = $this->getDoctrine()->getManager();
$langs = $entityManager->getRepository(Lang::class)->findAll();
$media = $entityManager->getRepository(Media::class)->findAll();
$form = $this->createForm(TravelType::class, $travel);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$entityManager->flush();
return $this->redirectToRoute('travel_index');
}
return $this->render('crud/travel/edit.html.twig', [
'langs' => $langs,
'travel' => $travel,
'media' => $media,
'form' => $form->createView()
]);
}
But then my TravelType form contains the following code:
class TravelType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('main_title')
->add('category', EntityType::class,[
'class' => Category::class,
'choice_label' => 'name',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->andWhere('c.type = :type')
->setParameter('type', 'country')
->orderBy('c.name', 'ASC');
},
])
->add('price_driver', MoneyType::class,[
'divisor' => 100,
])
->add('price_codriver', MoneyType::class,[
'divisor' => 100,
])
/* ->add('country') */
->add('km')
->add('media', EntityType::class, [
'class' => Media::class,
'choice_label' => 'name',
'multiple' => true
])
->add('status')
->add('duration')
->add('level')
->add('travelTranslations', CollectionType::class, [
'entry_type' => TravelTranslationType::class,
'entry_options' => [
'label' => false
],
'by_reference' => false,
// this allows the creation of new forms and the prototype too
'allow_add' => true,
// self explanatory, this one allows the form to be removed
'allow_delete' => true
])
->add('dates', CollectionType::class, [
'entry_type' => DatesType::class,
'entry_options' => [
'label' => false
],
'by_reference' => false,
// this allows the creation of new forms and the prototype too
'allow_add' => true,
// self explanatory, this one allows the form to be removed
'allow_delete' => true
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Travel::class,
'allow_extra_fields' => true
]);
}
}
I managed to fix the error by getting into the DatesType::class (a custom entity type form not DateType) and fixing it as it was the one getting with the trouble of referring to the wrong property "title" in a collection type
By changing
->add('travel', EntityType::class, [
'class' => Travel::class,
'choice_label' => 'title'
] )
By:
->add('travel', EntityType::class, [
'class' => Travel::class,
'choice_label' => 'main_title'
] )
Where main_title is the real property.

Symfony : Entity of type "App\Entity\Classement" passed to the choice field must be managed. Maybe you forget to persist it in the entity manager?

I have this form :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('country', EntityType::class, [
'class' => Country::class,
'choice_label' => 'name',
'label' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
}
])
->add('season', EntityType::class, [
'class' => Season::class,
'choice_label' => 'year',
'label' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s')
->orderBy('s.year', 'ASC');
}
])
->add('clubHistos', CollectionType::class, [
'entry_type' => ClubHistoType::class,
'entry_options' => [
'label' => false
],
'by_reference' => false,
'allow_add' => true
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Classement::class,
]);
}
Here is my ClubHistoType :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('position', null, [
'label' => false
])
->add('matches', null, [
'label' => false
])
->add('victories', null, [
'label' => false
])
->add('draws', null, [
'label' => false
])
->add('losses', null, [
'label' => false
])
->add('goals', null, [
'label' => false
])
->add('points', null, [
'label' => false
])
->add('season', EntityType::class, [
'class' => Season::class,
'choice_label' => 'year',
'label' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('s')
->orderBy('s.year', 'ASC');
}
])
->add('club', EntityType::class, [
'class' => Club::class,
'choice_label' => 'name',
'label' => false,
'required' => false,
'placeholder' => '-',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
}
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => ClubHisto::class,
]);
}
And my function to create a new country table in my controller :
/**
* #Route("back/table/new", name="new_table")
*/
public function createCountryTable(Request $request, EntityManagerInterface $manager) {
$countryTable = new Classement();
$clubHistoriques = new ClubHisto();
$countryTable->addClubHisto($clubHistoriques);
$form = $this->createForm(ClassementType::class, $countryTable);
dd($form);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
// foreach($clubHistoriques as $histo) {
// $histo->setSeason($countryTable->getSeason());
// }
$manager->persist($countryTable);
$manager->flush();
return $this->redirectToRoute('edit_table', ['id' => $countryTable->getId()]);
}
return $this->render('back/createTables.html.twig', [
'form' => $form->createView()
]);
}
But as soon as I call the form, it gives me this error :
Entity of type "App\Entity\Classement" passed to the choice field must be managed. Maybe you forget to persist it in the entity manager?
I don't really understand because I have other forms that work exactly like this one and everything works fine...
I know this subject has been asked many times, but the solutions never worked that were given never really worked.
Your help is highly appreciated !
Try just instantiate your form without $countryTable
$form = $this->createForm(ClassementType::class);
You already bind the form to the data so you shouldn't need to pre-instantiate it.
Then handle the data inside your if (form->isSubmitted()) logic
/* #var $countryTable \App\Entity\Classement */
$countryTable = $form->getData();
$clubHistos = $countryTable->getClubHistos();

How to retrive data from non-mapped field in embeded form

I would like to know if it's possible to get the data from a non-mapped field in an embeded form.
Here is the main form :
class PlayedLifeScoreType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
//->add('nom')
//->add('prenom')
// NOTE: Use form collection to allow multiple `played` forms per JoueurType
->add('playeds', CollectionType::class, [
'entry_type' => PlayedLifeType::class,
'label' => false,
])
->add('submit', SubmitType::class, [
'attr' => ['class' => 'save'],
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Partie::class,
]);
}
}
And the embedded one :
class PlayedLifeType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
/*->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$form = $event->getForm();
$form->add('joueur', null, array(
'data' => $event->getData() ?: options['joueur']
))*/
//->add('joueur')
->add('joueur', TextType::class, [
'label' => false,
'disabled' => 'true',
'attr' => ['class' => 'tinymce'],
])
->add('max')
->add('score')
->add('round', IntegerType::class,[
'mapped' => false,
'label' => 'Round',
])
;
//});
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Played::class,
'joueur' => null
]);
}
}
And want to get the data from "round". I tried like this but doesn't work :
$r = $mainForm->get('playeds')->get("round")->getData();
I get this error :
Child "round" does not exist.
Any idea ?
field "playeds" is a CollectionType.
So, for each entry, there is a 'round' value
To access this, you should do something like:
foreach ($mainForm->get('playeds') as $played) {
//you can access round here with $played->get('round')->getData()
//Or the Played object with $played->getData()
}

I can't use a variable in createFormBuilder

Why I can't use my variable $idType in my function createFormBuilder ?
public function buildForm(FormBuilderInterface $builder, array $options)
{
$idType = $options['data']->getEvenement()->getType()->getId();
$builder
->add('depart', DateTimeType::class, array(
'widget' => 'single_text'
))
->add('inscription', TextType::class)
->add('prixNl', IntegerType::class)
->add('prixL', IntegerType::class)
->add('resultat', TextType::class)
->add('sousType', EntityType::class, array(
'class' => 'CalendrierBundle:SousType',
'choice_label' => 'nom',
'multiple' => false,
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.typeId = :type')
->setParameter('type', $idType);
}
))
->add('save', SubmitType::class)
;
}
She is don't recognize
Thanks for your help
You should use use ($idType) keyword to inherit $idType variable from the parent scope into the closure.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$idType = $options['data']->getEvenement()->getType()->getId();
$builder
->add('depart', DateTimeType::class, array(
'widget' => 'single_text'
))
->add('inscription', TextType::class)
->add('prixNl', IntegerType::class)
->add('prixL', IntegerType::class)
->add('resultat', TextType::class)
->add('sousType', EntityType::class, array(
'class' => 'CalendrierBundle:SousType',
'choice_label' => 'nom',
'multiple' => false,
'query_builder' => function (EntityRepository $er) use ($idType) {
return $er->createQueryBuilder('u')
->where('u.typeId = :type')
->setParameter('type', $idType);
}
))
->add('save', SubmitType::class)
;
}