Symfony中如何获取搜索表单数据?报错:变量不存在
问题:Twig报错「Variable "category" does not exist」
需求是让用户先通过搜索表单选择大城市(bigcity)和活动类别(category),提交后跳转至活动列表页面展示对应结果。但提交后进入活动页面时出现报错,提示Variable "category" does not exist,说明Twig模板需要的category和bigcity变量未被控制器正确传递。
以下是相关代码:
EventsController.php
<?php namespace App\Controller\Front; use App\Form\SearchType; use App\Repository\EventsRepository; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class EventsController extends AbstractController { #[Route('/search', name: 'search')] public function search( Request $request, SessionInterface $sessionInterface, ){ $data = $request->request->all(); $sessionSearchFormData = $sessionInterface->get('searchFormData'); $form = $this->createForm(SearchType::class, ['data' => $sessionSearchFormData]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $data = $form->getData(); $sessionInterface->set('searchFormData', $data); return $this->redirectToRoute('events', [$data]); } return $this->renderForm('front/search.html.twig', [ 'form' => $form, ]); } #[Route('/events', name: 'events')] public function events( EventsRepository $eventsRepository, ){ $events = $eventsRepository->findAll(); return $this->render("front/events.html.twig", ['events' => $events]); } }
search.html.twig
{% extends 'base.html.twig' %} {% block title %}Liste des sorties et des activités !{% endblock %} {% block main %} {{ form_start(form) }} <p>Où souhaites-tu faire une sortie ou une activité ?</p> {{ form_widget(form.bigcity) }} <p>Quel type de sortie ou d’activité t’intéresse ?</p> {{ form_widget(form.category) }} {{ form_widget(form.save, {'label': 'Je valide') }} {{ form_end(form) }} </div> {% endblock %}
events.html.twig
{% extends 'base.html.twig' %} {% block title %}Liste des activités {{ category.title }} à {{ bigcity.name }}{% endblock %} {% block main %} <div class="events"> <h1 class="display-6 pt-3"> <img src="{{ asset('img/logos/') }}{{ category.image }}" alt="{{ category.title }}" width="auto" height="40"> à <b class="me-1">{{ bigcity.name }}</b> </h1> <div class="vr fixed-top start-50"></div> <div class="row"> <div class="col-12 col-md-6"> <h2 class="text-center my-4"> <img src="{{ asset('img/titres/zpeak-sorties.svg') }}" alt="Les Zpeak Sorties !"> </h2> <ul class="list-group"> {% for event in events %} {% if event and event.organizer.status == 'organizer' %} <a class="list-group-item list-group-item-action"> <img src="{{ asset('img/flag_images/' ~ event.spokenlanguage.image) }}" alt="Drapeau {{ event.spokenlanguage.name }}" class="me-2"> {{ event.title }} </a> {% else %} <p>Il n'y a pas de zpeak sortie organisée.</p> {% endif %} {% endfor %} </ul> </div> <div class="col-12 col-md-6"> <h2 class="text-center my-4"> <img src="{{ asset('img/titres/zpeak-idees.svg') }}" alt="Les Zpeak Idées !"> </h2> <ul class="list-group"> {% for event in events %} {% if event and event.organizer.status == 'member' %} <a class="list-group-item list-group-item-action"> <img src="{{ asset('img/flag_images/' ~ event.spokenlanguage.image) }}" alt="Drapeau {{ event.spokenlanguage.name }}" class="me-2"> {{ event.title }} </a> {% else %} <p>Il n'y a pas de zpeak idée proposée.</p> {% endif %} {% endfor %} </ul> </div> </div> </div> {% endblock %}
SearchType.php
<?php namespace App\Form; use App\Entity\BigCity; use App\Entity\Categories; use Doctrine\ORM\EntityManagerInterface; 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\SubmitType; class SearchType extends AbstractType { private EntityManagerInterface $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } public function buildForm(FormBuilderInterface $builder, array $options): void { $bigcity = $options['sessionSearchFormData'] !== null ? $options['sessionSearchFormData']['bigcity'] : ''; $category = $options['sessionSearchFormData'] !== null ? $options['sessionSearchFormData']['category'] : ''; $builder ->add('bigcity', EntityType::class, [ 'class' => BigCity::class, 'choice_label' => 'name', 'placeholder' => 'Sélectionne une grande ville', 'data'=> $bigcity !== null ? $this->entityManager->getRepository(BigCity::class)->find($bigcity) : '', ]) ->add('category', EntityType::class, [ 'class' => Categories::class, 'choice_label' => 'image', 'expanded' => true, 'multiple' => false, 'data'=> $category !== null ? $this->entityManager->getRepository(Categories::class)->find($category) : '', ]) ->add('save', SubmitType::class) ; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => null, 'sessionSearchFormData' => null, ]); } }
解决方案
1. 修复控制器参数传递问题
events方法没有从会话中读取之前保存的搜索数据,也没有将bigcity和category传递给Twig模板,同时跳转路由的参数传递方式错误。
修改EventsController.php:
<?php namespace App\Controller\Front; use App\Form\SearchType; use App\Repository\EventsRepository; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; class EventsController extends AbstractController { #[Route('/search', name: 'search')] public function search( Request $request, SessionInterface $sessionInterface, ){ $sessionSearchFormData = $sessionInterface->get('searchFormData'); // 修正:将session数据作为表单选项传递,而非data参数 $form = $this->createForm(SearchType::class, null, [ 'sessionSearchFormData' => $sessionSearchFormData ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $data = $form->getData(); $sessionInterface->set('searchFormData', $data); // 修正:跳转时无需传递参数,直接从会话读取即可 return $this->redirectToRoute('events'); } return $this->renderForm('front/search.html.twig', [ 'form' => $form, ]); } #[Route('/events', name: 'events')] public function events( EventsRepository $eventsRepository, SessionInterface $sessionInterface ){ // 从会话获取保存的搜索数据 $searchData = $sessionInterface->get('searchFormData'); // 验证数据是否存在 if (!$searchData || !isset($searchData['bigcity'], $searchData['category'])) { // 若无数据,重定向回搜索页面 return $this->redirectToRoute('search'); } $bigcity = $searchData['bigcity']; $category = $searchData['category']; // 修正:根据条件查询活动,而非获取全部 $events = $eventsRepository->findBy([ 'bigcity' => $bigcity, 'category' => $category ]); // 将变量传递给Twig模板 return $this->render("front/events.html.twig", [ 'events' => $events, 'bigcity' => $bigcity, 'category' => $category ]); } }
2. 修正Twig模板的循环逻辑
原模板中{% else %}会在每次循环中执行,导致无数据时重复显示提示,应将{% else %}放在{% for %}循环外部:
修改events.html.twig中第一个列表部分:
<ul class="list-group"> {% for event in events %} {% if event.organizer.status == 'organizer' %} <a class="list-group-item list-group-item-action"> <img src="{{ asset('img/flag_images/' ~ event.spokenlanguage.image) }}" alt="Drapeau {{ event.spokenlanguage.name }}" class="me-2"> {{ event.title }} </a> {% endif %} {% else %} <p>Il n'y a pas de zpeak sortie organisée.</p> {% endfor %} </ul>
第二个列表同理修改:
<ul class="list-group"> {% for event in events %} {% if event.organizer.status == 'member' %} <a class="list-group-item list-group-item-action"> <img src="{{ asset('img/flag_images/' ~ event.spokenlanguage.image) }}" alt="Drapeau {{ event.spokenlanguage.name }}" class="me-2"> {{ event.title }} </a> {% endif %} {% else %} <p>Il n'y a pas de zpeak idée proposée.</p> {% endfor %} </ul>
3. 优化SearchType的表单数据预填逻辑
简化实体对象的获取逻辑,确保兼容ID或实体对象的存储:
public function buildForm(FormBuilderInterface $builder, array $options): void { $bigcity = null; $category = null; if ($options['sessionSearchFormData']) { $bigcity = $options['sessionSearchFormData']['bigcity']; $category = $options['sessionSearchFormData']['category']; // 若存储的是ID,转换为实体对象;若已是实体则直接使用 if (is_numeric($bigcity)) { $bigcity = $this->entityManager->getRepository(BigCity::class)->find($bigcity); } if (is_numeric($category)) { $category = $this->entityManager->getRepository(Categories::class)->find($category); } } $builder ->add('bigcity', EntityType::class, [ 'class' => BigCity::class, 'choice_label' => 'name', 'placeholder' => 'Sélectionne une grande ville', 'data' => $bigcity, ]) ->add('category', EntityType::class, [ 'class' => Categories::class, 'choice_label' => 'image', 'expanded' => true, 'multiple' => false, 'data' => $category, ]) ->add('save', SubmitType::class) ; }
内容的提问来源于stack exchange,提问作者Emilie Tossan
相关产品推荐
相关产品推荐

