Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Refactorizar formularios en Symfony 3

17 de febrero de 2016

Tengo un formulario GET que me gustaría reutilizar en varios controladores. Es un formulario que acepta un término de búsqueda con SearchType y categorías con ChoiceType, y en función de lo que se especifique empleará diferentes controladores (una caja de búsqueda).

La parte de la construcción del formulario está en su correspondiente SearchBoxType, y en el controlador tengo:

$form = $this->createForm(SearchBoxType::class);
$form->handleRequest($request);
 
if($form->isValid()) {
    // ... LÓGICA CON LOS DATOS ENVIADOS
}

El formulario funciona, pero la idea es poder emplearlo en varias plantillas, desde varios controladores, evitando copiar todo el contenido en cada uno, especialmente la lógica con los datos enviados.

He intentado creando un servicio, creando un controlador como servicio, o con eventos (aunque he visto que no se pueden añadir eventos al botón de submit), pero me daban errores al pasar el formulario desde un método a otro.

He intentado también aunque sea mover la lógica a un método en el mismo controlador pero también me daba problemas con el renderizado del formulario.

¿Alguna orientación acerca de cómo poder reutilizar la caja de búsqueda?


Respuestas

#1

En estos casos, yo lo que hago es crear una acción en algún controlador que se encargue de mostrar y procesar el formulario. Después, incluyo ese formulario en cualquier plantilla de la aplicación mediante render(controller('...')). Más información: render() y controller()

@javiereguiluz

18 febrero 2016, 8:31
#2

Gracias Javier.

Por si a alguien le sirve está bien explicado aquí

El problema ahora es que no me coge bien el request.

public function searchBoxAction(Request $request)
    {
        $form = $this->createForm(SearchSubType::class);
        $form->handleRequest($request);
 
        $category = '';
        if($form->isValid())
        {
         // ...
        }
 
        return $this->render('form.html.twig', array('form' => $form->createView()));
    }

En la template form.html.twig tengo el formulario, y en la template donde quiero mostrarlo (main.html.twig):

{{ render(controller('AppBundle:Search:searchBox', {'request' : app.request})) }}

El formulario se muestra, pero no funciona el request al enviar el formulario, muestra el siguiente error:

An exception has been thrown during the rendering of a template ("Error when rendering...

Y aparece el GET request textual "?search_sub%5B_token%5D=JbUHbzO3uhNhAdeSxw... ... (Status code is 302).") in mail.html.twig at line 19

Vuelve a intentar acceder a la misma template donde se muestra el formulario (main.html.twig), cuando realmente aplico una redirección a otra url y template con redirectToRoute.

El ajax request si que funciona.

Si el formulario lo pongo en el mismo controller si que funciona todo el proceso.

@diegotham

18 febrero 2016, 10:39
#3

Acabo de ver que no se puede redireccionar desde un embedded controller.

Lo anterior lo he probado con un POST request sin redirecciones y funciona bien.

Voy a ver cómo refactorizar la lógica con redirecciones de una search box. Aquí también se habla de la situación.

@diegotham

18 febrero 2016, 11:51
#4

Por mi encontré una forma.

En lugar de aplicar la lógica en el controller la aplico en la template.

En la template donde se incrusta el formulario (main.html.twig):

{{ render(controller('AppBundle:Search:searchBox', {'request': app.request})) }}

En la template donde se muestra el formulario (searchbox.html.twig), además de mostrar el form con {{ form_start(form) }} incluyo la lógica donde dependiendo de las variables que reciba renderizará un controller u otro:

{% if category is defined %}
    {{ render(controller('AppBundle:Search:searchCategory', {'category': category})) }}
{# ... etc #}

@diegotham

18 febrero 2016, 12:38
#5

La forma anterior me acababa dando problemas para lo que buscaba, así que he aplicado filtros.

De todas formas en el formulario sigo manteniendo redirecciones, del tipo:

if($form->isValid()) {
            $data = $form->getData();
            $category = $data['category'];
            $subcategory = $data['subcategory'];
            $word = $data['word'];
 
            if(!$request->isXmlHttpRequest()) {
                if ($subcategory && $word) {
                    return $this->redirectToRoute('post_search',
                        array('word' => $word, 'subcategory' => $subcategory->getId()));
                } elseif ($category && $word) {
                    return $this->redirectToRoute('post_search',
                        array('word' => $word, 'category' => $category->getId()));
                } elseif ($subcategory) {
                    return $this->redirectToRoute('post_list_subcategory',
                        array('slug1' => $category->getSlug(), 'slug2' => $subcategory->getSlug()));

Funcionar funciona y me permite mantener las URLs en caso de que no se proporcione una palabra en la búsqueda, ya que redirige a una categoría en lugar de aplicar un filtro con la categoría.

El problema surge a la hora de refactorizar para emplearlo en varios controllers, ya que si separo el formulario tendría una respuesta Form y varias respuestas RedirectResponse, lo que me da error a la hora de renderizar el formulario en Twig.

Igual estoy formulando mal el planteamiento, ¿Alguna idea?

@diegotham

22 febrero 2016, 12:35