You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 17:05:30