Symfony doesn't display form properly - forms

I tried to display a simply form that I built in SearchType.php. In my controller, the form is supposed to be displayed with the route /search. But we we go there, I have just one input while I defined two input in SearchType.php. Note : this input is not even a selection, I only can enter text.
search.html.twig
{% extends 'base.html.twig' %}
{% block title %}Liste des sorties et des activités{% endblock %}
{% block main %}
{{ form(form) }}
{% endblock %}
SearchType.php
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class SearchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('bigcity', ChoiceType::class, [
'choices' => [
'Je sélectionne une ville' => '',
'Paris, France' => 'paris'
]
])
->add('category', ChoiceType::class, [
'choices' => [
"Je sélectionne un type d'activité" => '',
'Eat Zpeak !' => 'eatzpeak',
'Party Zpeak !' => 'partyzpeak',
'Run Zpeak !' => 'runzpeak',
'Art Zpeak !' => 'artzpeak',
]
])
->add('save', SubmitType::class)
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => null
]);
}
}
EventsController.php
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Form\Extension\Core\Type\SearchType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class EventsController extends AbstractController
{
#[Route('/search', name: 'search')]
public function search(Request $request)
{
$form = $this->createForm(SearchType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
return $this->render('front/events.html.twig', $data);
}
return $this->render('front/search.html.twig', [
'form' => $form->createView()
]);
}
}

You are usinig a bad class import in your controller
use Symfony\Component\Form\Extension\Core\Type\SearchType;
You should use the namespace of your formType
App\Form\SearchType

Related

How to display form errors in Symfony?

I wish to understand how to display errors that come from forms. For now, when I validate any form on my project, I don't have anything appearing.
How to display form errors in Symfony ?
Thank you for your help.
You can see my code from :
register.html.twig file where my userform helping users to register is shown.
UserController.php file where you can see what happens when userform is validated.
Also User.php and UserType.php.
register.html.twig
{% extends 'base.html.twig' %}
{% block title %}Incris-toi !{% endblock %}
{% block main %}
{{ form_start(userform) }}
<div class="alert alert-danger text-center" role="alert">
{% set formErrors = userform.vars.errors.form.getErrors(true) %}
{% if formErrors|length %}
<div class="alert alert-danger text-center" role="alert">
{% if userform.vars.value.email == null or userform.vars.value.email != 'email' or userform.vars.value.email != 'unique' %}
{{ form_errors(userform.email) }}
{% elseif userform.vars.value.password|length < 6 %}
{{ form_errors(userform.password) }}
{% elseif userform.vars.value.gender == null or (userform.vars.value.gender != 'male' and userform.vars.value.gender != 'female' and userform.vars.value.gender != 'non-binary') %}
{{ form_errors(userform.gender) }}
{% elseif userform.vars.value.firstname|length < 2 %}
{{ form_errors(userform.firstname) }}
{% elseif userform.vars.value.lastname|length < 2 %}
{{ form_errors(userform.lastname) }}
{% elseif userform.vars.value.birthdate == null %}
{{ form_errors(userform.birthdate) }}
{% elseif userform.vars.value.occupation|length < 2 %}
{{ form_errors(userform.occupation) }}
{% elseif userform.vars.value.nationality == null %}
{{ form_errors(userform.nationality) }}
{% elseif userform.vars.value.nativelanguage == null %}
{{ form_errors(userform.nativelanguage) }}
{% endif %}
</div>
{% endif %}
</div>
{{ form_widget(userform.email) }}
{{ form_widget(userform.password) }}
{{ form_widget(userform.gender) }}
{{ form_widget(userform.firstname) }}
{{ form_widget(userform.lastname) }}
{{ form_widget(userform.birthdate) }}
{{ form_widget(userform.occupation) }}
{{ form_widget(userform.nationality) }}
{{ form_widget(userform.nativelanguage) }}
{{ form_widget(userform.save) }}
{{ form_end(userform) }}
UserController.php
<?php
namespace App\Controller\Front;
use App\Entity\User;
use App\Form\UserType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
class UserController extends AbstractController
{
#[Route('/register', name: 'register', methods: ['GET', 'POST'])]
public function createUser(
Request $request,
EntityManagerInterface $entityManagerInterface,
UserPasswordHasherInterface $userPasswordHasherInterface
){
$user = new User();
$userform = $this->createForm(UserType::class, $user);
$userform->handleRequest($request);
if ($userform->isSubmitted() && $userform->isValid()) {
$user->setRoles(["ROLE_USER"]);
$plainPassword = $userform->get('password')->getData();
$hashedPassword = $userPasswordHasherInterface->hashPassword($user, $plainPassword);
$user->setPassword($hashedPassword);
$entityManagerInterface->persist($user);
$entityManagerInterface->flush();
return $this->redirectToRoute('home');
}
return $this->renderForm('front/register.html.twig', [
'userform' => $userform,
]);
}
User.php
<?php
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
#[ORM\Entity(repositoryClass: UserRepository::class)]
class User implements UserInterface, PasswordAuthenticatedUserInterface
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id;
#[ORM\Column(length: 180, unique: true)]
#[Assert\NotBlank(message:'Tu as oublié d\'entrer ton adresse e-mail.')]
#[Assert\Email(message: 'Entre une adresse e-mail valide.')]
private ?string $email = null;
/**
* #var string The hashed password
*/
#[ORM\Column]
#[Assert\NotBlank(message:'Tu as oublié de créer un mot de passe.')]
#[Assert\Length(min: 6, minMessage: 'Crée un mot de passe de 6 caractères minimum.')]
private ?string $password = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message:'Tu as oublié de sélectionner ton genre.')]
private ?string $gender = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message:'Tu as oublié d\'entrer ton prénom.')]
#[Assert\Length(min: 2, minMessage: 'Écris un prénom valide.')]
private ?string $firstname = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message:'Tu as oublié d\'entrer ton nom de famille.')]
#[Assert\Length(min: 2, minMessage: 'Écris un nom de famille valide.')]
private ?string $lastname = null;
#[ORM\Column(type: Types::DATE_MUTABLE)]
#[Assert\NotBlank(message:'Tu as oublié de sélectionner ta date de naissance.')]
private ?\DateTimeInterface $birthdate = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank(message:'Tu as oublié de nous dire ce que tu fais.')]
#[Assert\Length(min: 2, minMessage: 'Écris une occupation valide.')]
private ?string $occupation = null;
#[ORM\ManyToOne(inversedBy: 'users')]
#[Assert\NotBlank(message:'Tu as oublié de nous sélectionner le pays d\'où tu viens.')]
private ?Country $nationality = null;
#[ORM\ManyToOne(inversedBy: 'users')]
#[Assert\NotBlank(message:'Tu as oublié de nous sélectionner ta langue maternelle.')]
private ?Language $nativelanguage = null;
public function __construct()
{
$this->events = new ArrayCollection();
$this->participations = 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;
}
/**
* A visual identifier that represents this user.
*
* #see UserInterface
*/
public function getUserIdentifier(): string
{
return (string) $this->email;
}
/**
* #see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string
{
return $this->password;
}
public function setPassword(string $password): self
{
$this->password = $password;
return $this;
}
/**
* #see UserInterface
*/
public function eraseCredentials()
{
// If you store any temporary, sensitive data on the user, clear it here
// $this->plainPassword = null;
}
public function getGender(): ?string
{
return $this->gender;
}
public function setGender(string $gender): self
{
$this->gender = $gender;
return $this;
}
public function getFirstname(): ?string
{
return $this->firstname;
}
public function setFirstname(string $firstname): self
{
$this->firstname = $firstname;
return $this;
}
public function getLastname(): ?string
{
return $this->lastname;
}
public function setLastname(string $lastname): self
{
$this->lastname = $lastname;
return $this;
}
public function getBirthdate(): ?\DateTimeInterface
{
return $this->birthdate;
}
public function setBirthdate(?\DateTimeInterface $birthdate): self
{
$this->birthdate = $birthdate;
return $this;
}
public function getOccupation(): ?string
{
return $this->occupation;
}
public function setOccupation(string $occupation): self
{
$this->occupation = $occupation;
return $this;
}
public function getNationality(): ?Country
{
return $this->nationality;
}
public function setNationality(?Country $nationality): self
{
$this->nationality = $nationality;
return $this;
}
public function getNativelanguage(): ?Language
{
return $this->nativelanguage;
}
public function setNativelanguage(?Language $nativelanguage): self
{
$this->nativelanguage = $nativelanguage;
return $this;
}
}
UserType.php
<?php
namespace App\Form;
use App\Entity\User;
use App\Entity\Country;
use App\Entity\Language;
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\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('gender', ChoiceType::class, [
'choices' => [
'Je suis ...' => '',
'un homme' => 'male',
'une femme' =>'female',
'non-binaire' => 'non-binary'
]
])
->add('lastname')
->add('firstname')
->add('birthdate', BirthdayType::class, [
'placeholder' => [
'year' => 'Année', 'month' => 'Mois', 'day' => 'Jour',
],
'choice_translation_domain' => true
])
->add('occupation')
->add('nationality', EntityType::class, [
'class' => Country::class,
'choice_label' => 'name',
'placeholder' => 'Je choisis un pays'
])
->add('nativelanguage', EntityType::class, [
'class' => Language::class,
'choice_label' => 'name',
'placeholder' => 'Je sélectionne ma langue maternelle'
])
->add('email')
->add('password', PasswordType::class, [
'mapped' => false
])
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'Les deux mots de passe doivent être identiques.',
'options' => ['attr' => ['class' => 'password-field']],
'required' => true,
'first_options' => ['label' => 'Password'],
'second_options' => ['label' => 'Repeat Password']
])
->add('save', SubmitType::class, [
'attr' => ['class' => 'save'],
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'translation_domain' => 'forms'
]);
}
}
-- This question is still open. --
EDIT : I have found the way to display error messages. But this problem persists : password doesn't show its error message. I don't understand why.
Try to test "firstname" for example with min length 3 by typing only 2 chars in the form, the form error appears or no ?
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
#[Assert\Length(min: 3)]
private ?string $firstname = null;
/**
* #Assert\NotBlank(
* message="Mot de passe ne doit pas être vide."
* )
* #Assert\Length(
* min="6",
* max="32",
* minMessage="Mot de passe doit avoir au minimum ({{ limit }}) caractères.",
* maxMessage="Mot de passe doit avoir au maximum ({{ limit }}) caractères."
* )
* #Assert\Length(max=4096)
*/
private $plainPassword;
public function getPlainPassword(): ?string
{
return $this->plainPassword;
}
public function setPlainPassword(?string $password): self
{
$this->plainPassword = $password;
return $this;
}
FormType:
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array(
'label' => 'Mot de passe (6 caractères au minimum)',
'constraints' => [
new NotBlank([
'message' => 'Mot de passe ne doit pas être vide',
]),
new Length([
'min' => 6,
'minMessage' => 'Mot de passe doit avoir au minimum {{ limit }} caractères',
'max' => 4096,
]),
],
),
'second_options' => array('label' => 'Confirmation'),
'invalid_message' => 'Les deux mots de passe ne sont pas identiques'
))
The controller:
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
private UserPasswordHasherInterface $passwordHasher;
public function __construct(UserPasswordHasherInterface $passwordHasher)
{
$this->passwordHasher = $passwordHasher;
}
if ($form->isSubmitted() && $form->isValid()) {
$user->addRole('ROLE_AAAAAA');
$user->setPassword(
$this->passwordHasher->hashPassword($user, $form->get('plainPassword')->getData()));
// ...........
}
Twig form:
{% if not userform.vars.valid %}
<div class="alert alert-danger">
{{ form_errors(userform) }}
{% for children in userform.children %}
{% if not children.vars.valid %}
{{ form_errors(children) }}
{% endif %}
{% for child in children %}
{% if not child.vars.valid %}
{{ form_errors(child) }}
{% endif %}
{% endfor %}
{% endfor %}
</div>
{% endif %}
<div class="col-md-6">
{{ form_row(form.plainPassword.first) }}
</div>
<div class="col-md-6">
{{ form_row(form.plainPassword.second) }}
</div>
_ I think there is a problem with your User class, you didn't set any validations for your form : https://symfony.com/doc/current/forms.html#validating-forms
Validation is done by adding a set of rules, called (validation) constraints, to a class. You can add them either to the entity class or to the form class.
Try to add some rules (#[Assert\NotBlank]) to your class and your form will throw errors if it's not fit.
_ Also, you need te remove your default value on your fields in your User class ( = null) to the variable you need to be filled (at least you need to remove the ID one, who can't be null).
_ In your form on each fields, you set 'error_bubbling' to true : https://symfony.com/doc/current/reference/forms/types/text.html#error-bubbling
If true, any errors for this field will be passed to the parent field or form. For example, if set to true on a normal field, any errors for that field will be attached to the main form, not to the specific field.
If you want to have the control on every field, i think you need to remove this option, then symfony will attach errors on each fields.
Or you can let this option but then you need to update your code in the Alert div, to not render each fields, but the parent field or form.

How to display inputs created in the form type - Symfony 6.0.2 [duplicate]

I tried to display a simply form that I built in SearchType.php. In my controller, the form is supposed to be displayed with the route /search. But we we go there, I have just one input while I defined two input in SearchType.php. Note : this input is not even a selection, I only can enter text.
search.html.twig
{% extends 'base.html.twig' %}
{% block title %}Liste des sorties et des activités{% endblock %}
{% block main %}
{{ form(form) }}
{% endblock %}
SearchType.php
<?php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class SearchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('bigcity', ChoiceType::class, [
'choices' => [
'Je sélectionne une ville' => '',
'Paris, France' => 'paris'
]
])
->add('category', ChoiceType::class, [
'choices' => [
"Je sélectionne un type d'activité" => '',
'Eat Zpeak !' => 'eatzpeak',
'Party Zpeak !' => 'partyzpeak',
'Run Zpeak !' => 'runzpeak',
'Art Zpeak !' => 'artzpeak',
]
])
->add('save', SubmitType::class)
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => null
]);
}
}
EventsController.php
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Form\Extension\Core\Type\SearchType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class EventsController extends AbstractController
{
#[Route('/search', name: 'search')]
public function search(Request $request)
{
$form = $this->createForm(SearchType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
return $this->render('front/events.html.twig', $data);
}
return $this->render('front/search.html.twig', [
'form' => $form->createView()
]);
}
}
You are usinig a bad class import in your controller
use Symfony\Component\Form\Extension\Core\Type\SearchType;
You should use the namespace of your formType
App\Form\SearchType

Symfony Form never returns a value

I try to make a search bar but my form dont return value.
I am starting, I have already made symfony forms but there I really do not see :(
I use Symfony 4.12.10.
I always have the result in symfony profiler:
App \ Entity \ PropertySearch {# 707 ▼
-searchbar: null
}
html :
<form class="form-inline mr-auto">
{{ form_start(searchForm) }}
{{ form_errors(searchForm) }}
{{ form_row(searchForm.searchbar) }}
<button type="submit" class="btn btn-secondary my-4 ml-1 my-sm-0">🔍</button>
{{ form_end((searchForm)) }}
</form>
repository :
class TextesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Textes::class);
}
/**
* #return Query
*/
public function findAllVisible(PropertySearch $search)
{
$query = $this->createQueryBuilder('p');
if ($search->getSearchbar()) { //Si l'utilisateur recherche
$query = $query->andwhere('p.title = :searchbar');
$query->setParameter('searchbar', $search->getSearchbar());
}
return $query->getQuery()->getResult();
}
form:
class SearchType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('searchbar', TextType::class, [
'label' => false,
'required' => false,
'attr' => [
'placeholder' => 'recherche...',
'style' => 'width: 50vw',
],]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => PropertySearch::class,
'csrf_protection' => false,
]);
}
}
entity for the form:
class PropertySearch{
private $searchbar;
/**
* #return mixed
*/
public function getSearchbar()
{
return $this->searchbar;
}
/**
* #param mixed $searchbar
* #return PropertySearch
*/
public function setSearchbar($searchbar)
{
$this->searchbar = $searchbar;
return $this;
}
}
controller :
class TextController extends AbstractController
{
/**
* #Route("/liste", name="list")
*/
public function index(TextesRepository $repo, Request $request)
{
$search = new PropertySearch();
$searchform=$this->createForm(SearchType::class, $search);
$searchform->handleRequest($request);
return $this->render('text/index.html.twig', [
'controller_name' => 'TextController.php',
'articles' => $repo->findAllVisible($search),
'searchForm' => $searchform->createView()
]);
}
You don't need to use the form tag beacuse using form_start and form_end already creates this tag.
Due to this you have a form inside a form, what may cause some troubles in html forms.
{{ form_start(searchForm) }}
{{ form_errors(searchForm) }}
{{ form_row(searchForm.searchbar) }}
<button type="submit" class="btn btn-secondary my-4 ml-1 my-sm-0">🔍</button>
{{ form_end((searchForm)) }}
Documentation
Also I recommend you to add the submit button to the form. Link

Symfony form with entity

Hi I need a thinking help abaout form with entity class.
I have the edit function
/**
* #Route("/{id}/edit", name="admin_product_group_edit", methods={"GET","POST"})
*/
public function edit(Request $request, ProductGroup $productGroup): Response
{
$form = $this->createForm(ProductGroupType::class, $productGroup);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('admin_product_group_index', [
'id' => $productGroup->getId(),
]);
}
return $this->render('admin/product_group/edit.html.twig', [
'product_group' => $productGroup,
'form' => $form->createView(),
'scrollUp' => true,
]);
}
and I have the form Type
use App\Entity\ProductGroup;
use App\Entity\ProductType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProductGroupType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('nameDe')
->add('nameEn')
->add('descriptionDe')
->add('descriptionEn')
->add('rank')
->add('active')
->add('creatDate')
->add('updateDate')
->add('productTypes', EntityType::class, [
// looks for choices from this entity
'class' => ProductType::class,
// uses the User.username property as the visible option string
'choice_label' => 'nameDe',
// used to render a select box, check boxes or radios
// 'multiple' => true,
// 'expanded' => true,
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProductGroup::class,
]);
}
}
by creating an new ProductGroup all is fin but by edit it, I cannot get the edit Form.
I get this error
Argument 1 passed to App\Controller\Admin\ProductGroupController::edit() must be an instance of App\Entity\ProductGroup, instance of App\Entity\ProductType given, called in /var/www/symfony-michael-roskosch/htdocs/vendor/symfony/http-kernel/HttpKernel.php on line 150
This is symfony 4.3 with symfony2 i had no problems with that, can you giv me a tip?
ok i found it
I had the wrong repositoryClass llinked by the orm annotation
/**
- * #ORM\Entity(repositoryClass="App\Repository\ProductTypeRepository")
+ * #ORM\Entity(repositoryClass="App\Repository\ProductGroupRepository")
*/
class ProductGroup
{
It was not a good idea to take the entity name ProductType because than you have the form ProductTypeType. After bin/console make:crud some mistakes was in the code. I don't know if I did them last night or it cames by the crud process it self.
nevermind now it works :-)

How to structure Symfony to check for `onChange` dropdown fields?

In my example, I have four entities that I want to use for a blog platform: Owner Post User Location
An Owner can have multiple Posts
A Post can have multiple Users and Locations
I am trying to create an admin form where I can select the Owner from a dropdown menu, that will refresh the form onChange to populate the dropdown menu of Posts.
When a Post is then selected, the form is again refreshed with form fields Users and Locations associated to that post. I can then either:
Update the existing entities with more information (eg User's date of birth or Location's GPS coordinates)
Create a new instance of either entity to attach to the Post
I've not included the Location entity and not included the namespaces/include statements as they would detract from my main question of how such an admin page should be coded in the controller/Formtypes (my attempts are as follows):
Controller:
/**
* #Route("/adminposts", name="admin_posts")
*/
public function updatePostsAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($owner);
$em->persist($post);
$em->persist($user);
$em->persist($location);
$em->flush();
return $this->redirectToRoute('homepage');
}
return $this->render('AppBundle:Default:adminupdate.post.html.twig', array(
'form' => $form->createView(),
));
}
User Formtype:
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('owner','entity',array(
'class'=>'AppBundle:Owner',
'choice_label'=>'username',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('d')
->orderBy('d.username','ASC');
}))
->add('post','entity',array(
'class'=>'AppBundle:Post',
'choice_label'=>'posttext',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('d')
->orderBy('d.postdate','ASC');
}))
->add('Firstname')
->add('Surname')
->add('DOB')
->getForm();
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Users',
));
}
public function getName()
{
return 'user';
}
}
Ok, maybe you can take a look here : Symfony2: Change choices with ajax and validation or follow my method :
In your UserType :
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('owner','entity',array(
'class'=>'AppBundle:Owner',
'choice_label'=>'username',
'query_builder'=>function(EntityRepository $er) {
return $er->createQueryBuilder('o')
->orderBy('o.username','ASC');
}))
->add('Firstname')
->add('Surname')
->add('DOB');
// Add listeners for Post field
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
}
protected function addElements(FormInterface $form, $owner = null)
{
if($owner){
$form->add('post','entity',array(
'class'=>'AppBundle:Post',
'choice_label'=>'posttext',
'query_builder'=>function(EntityRepository $er, $owner) {
return $er->createQueryBuilder('p')
->join('p.owner', 'o')
->where('o.id = :ownerID')
->setParameter('ownerID', $owner->getID() )
->orderBy('d.postdate','ASC');
}));
}
else{
$form->add('post','choice',array(
'choice_label'=>'posttext',
'empty_value' => '-- Choose --',
'choices' => array())
);
}
}
public function onPreSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$this->addElements($form, $data->getOwner());
}
public function onPreSetData(FormEvent $event)
{
/** #var User user */
$user = $event->getData();
$form = $event->getForm();
$this->addElements($form, $user->getOwner());
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Users',
));
}
public function getName()
{
return 'user';
}
}
I assume you know how to create an onChange Event in jQuery (I use to use it) and an ajax call.
Just for remind, in your view :
{{ form_row(
form.owner,
{
'attr': {
'data-owner-id': ""~form.owner.vars.id,
'class': "change-posts-per-owner",
}
}
) }}
{{ form_row(form.post) }}
{{ form_row(form.firstname) }}
{{ form_row(form.surname) }}
{{ form_row(form.DOB) }}
And your Ajax Script :
$(document).on('change', 'select .change-posts-per-owner', function(){
var ownerID = $(this).data("owner-id");
$.ajax({
url: your_url,
type: "GET", //or POST
data: 'ownerID='+ownerID,
dataType: 'JSON', //or html or whatever you want
success:function(data) {
//Replace <option element in your select element for post list considering your dataType (type of response)
}
});
}
You also can use $.post() or $.get() instead of explicit method $.ajax();
I sugget you to use FOSJSRoutingBundle for indicating your url with Routing.generate() method.