Foros del Web » Programando para Internet » PHP » Symfony »

[SOLUCIONADO] Formularios en distinto método

Estas en el tema de Formularios en distinto método en el foro de Symfony en Foros del Web. Buenas tardes, otra vez vuelvo acudir al foro por otro problema. A ver si soy capaz d explicarme: Tengo un controller con varios formularios y ...
  #1 (permalink)  
Antiguo 31/10/2015, 14:00
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Formularios en distinto método

Buenas tardes, otra vez vuelvo acudir al foro por otro problema.
A ver si soy capaz d explicarme: Tengo un controller con varios formularios y me parece muy engorroso tener la creación y la ejecución de todos los formularios en el mismo action, entonces he pensado en hacer una función de cada formulario, os enseño el 1º:

Método de creación del formulario
Código PHP:
public function createFormAddSerie($request){
        
$serieForm = new Series();
        
$form $this->createForm(new RegisterSerieType$serieForm);
        
        if(
$request->getMethod() == 'POST'){
            
$form->bindRequest($request);
            
            if(
$form->isValid()){
                        
$manager $this->getDoctrine()->getManager();
                
$manager->persist($serieForm);
                
$manager->flush();

                        return 
$this->redirect($this->generateURL('loadSeries', array('state' => $serieForm->getState())));
            }
        }
        
        return 
$form;
    } 
Llamada desde el action principal del controller
Código PHP:
$request $this->getRequest();
$form $this->createFormAddSerie($request); 
Return del controlador donde renderiza
Código PHP:
return $this->render('TMKSeriesBundle:Default:series.html.twig', array(
            
'series' => $series,
            
'title' => $title,
            
'form' => $form->createView()
            )); 
Decir que teniendo todo el código en el mismo método (el action principal del controller) el formulario funciona perfectamente (creación y ejecución), pero a la hora d tenerlo separados, al crearlo va perfecto, pero al ejecutarlo, cuando entrar en el if para persistir me devuelve un FatalErrorException a la hora de hacer el createView(), pero, no debería hacerlo porque si lo persiste (lo hace, comprobado en la base de datos) debería redireccionar y volver a cargar el controlador pero si entrar en el sitio de persistir.

Espero haberme explicado bien. Gracias
  #2 (permalink)  
Antiguo 31/10/2015, 17:43
 
Fecha de Ingreso: enero-2013
Ubicación: Santa Fe, VT
Mensajes: 68
Antigüedad: 11 años, 9 meses
Puntos: 2
Respuesta: Formularios en distinto método

No soy muy bueno pero voy a tratar de ayudar:
La funcion createFormAddSerie puede devolver o un Response object o un Form object, cuando el formulario es valido devuelve un Response, el objeto Response no tiene el metodo createView(), te aseguraste de que antes de hacer el render te fijes si el $form es un objeto Form o un Response?
  #3 (permalink)  
Antiguo 01/11/2015, 06:44
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Corrígeme si me equivoco pero, al redireccionar de nuevo a la página, esta se volvería a cargar, pero esta vez con el método GET, entraría de nuevo en el método createFormAddSerie(), pero esta vez devolvería el form. ¿Estoy equivocado?
  #4 (permalink)  
Antiguo 01/11/2015, 07:19
 
Fecha de Ingreso: enero-2013
Ubicación: Santa Fe, VT
Mensajes: 68
Antigüedad: 11 años, 9 meses
Puntos: 2
Respuesta: Formularios en distinto método

Creo que seria mejor que subas todo el codigo del Action o el controller por que no puedo entenderte. Ya que el metodo createFormAddSerie puede devolver 2 objetos diferentes.
  #5 (permalink)  
Antiguo 01/11/2015, 09:08
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

También lo he intentando en este controller donde solo hay un formulario, a ver si se puede ver mas claro

Código PHP:
use SymfonyBundleFrameworkBundleControllerController;
use 
TMKSeriesBundleEntitySeries;
use 
TMKSeriesBundleFormRegisterSerieType;

class 
DefaultController extends Controller
{
    public function 
indexAction($name)
    {
        return 
$this->render('TMKSeriesBundle:Default:index.html.twig', array('name' => $name));
    }
    
    public function 
loadSeriesAction($state)
    {    
 
        
$request $this->getRequest();

        
$form $this->createFormAddSerie($request);
        
        if(
$state == '0'){
            
$title 'Siguiendo';
            
$state = array(0,3);
        } else if(
$state == '1'){
            
$title'Vistas';
        } else if (
$state == '2'){
            
$title 'Pendientes';
        }
        
        
$manager $this->getDoctrine()->getManager();
        
        
$series $manager->getRepository('TMKSeriesBundle:Series')->findByStateOrderBy($state);
        
        return 
$this->render('TMKSeriesBundle:Default:series.html.twig', array(
            
'series' => $series,
            
'title' => $title,
            
'form' => $form->createView()
            ));
    }
    
    public function 
createFormAddSerie($request){
        
$serieForm = new Series();
        
$form $this->createForm(new RegisterSerieType$serieForm);
        
        if(
$request->getMethod() == 'POST'){
            
$form->bind($request);
            
            if(
$form->isValid()){
                
$manager $this->getDoctrine()->getManager();
                
$manager->persist($serieForm);
                
$manager->flush();

                return 
$this->redirect($this->generateURL('loadSeries', array('state' => $serieForm->getState())));
            }
        }
        
        return 
$form;
    }

  #6 (permalink)  
Antiguo 01/11/2015, 11:14
 
Fecha de Ingreso: enero-2013
Ubicación: Santa Fe, VT
Mensajes: 68
Antigüedad: 11 años, 9 meses
Puntos: 2
Respuesta: Formularios en distinto método

No puedo probar el codigo ahora pero la solucion mas rapida y simple que te puedo dar es esta(no estoy seguro de que sea practica y de rendimiento pero es la que menor cantidad de modificaciones necesita):

Código PHP:
use SymfonyBundleFrameworkBundleControllerController;
use 
TMKSeriesBundleEntitySeries;
use 
TMKSeriesBundleFormRegisterSerieType;

class 
DefaultController extends Controller
{
    public function 
indexAction($name)
    {
        return 
$this->render('TMKSeriesBundle:Default:index.html.twig', array('name' => $name));
    }

    public function 
loadSeriesAction($state)
    {

        
$request $this->getRequest();

        
$form $this->createFormAddSerie($request);

       
// CODIGO AGREGADO****************************************
        
if(get_class($form) == 'Symfony\Component\HttpFoundation\RedirectResponse')
        {
          return 
$form;
        }
        
//FIN DE CODIGO AGREGADO**********************************

        
if($state == '0'){
            
$title 'Siguiendo';
            
$state = array(0,3);
        } else if(
$state == '1'){
            
$title'Vistas';
        } else if (
$state == '2'){
            
$title 'Pendientes';
        }

        
$manager $this->getDoctrine()->getManager();

        
$series $manager->getRepository('TMKSeriesBundle:Series')->findByStateOrderBy($state);

        return 
$this->render('TMKSeriesBundle:Default:series.html.twig', array(
            
'series' => $series,
            
'title' => $title,
            
'form' => $form->createView()
            ));
    }

    public function 
createFormAddSerie($request){
        
$serieForm = new Series();
        
$form $this->createForm(new RegisterSerieType$serieForm);

        if(
$request->getMethod() == 'POST'){
            
$form->bind($request);

            if(
$form->isValid()){
                
$manager $this->getDoctrine()->getManager();
                
$manager->persist($serieForm);
                
$manager->flush();

                return 
$this->redirect($this->generateURL('loadSeries', array('state' => $serieForm->getState())));
            }
        }

        return 
$form;
    }

solo agregue 2 lineas.
como la funcion createFormAddSerie te puede devolver tanto como un redirectResponse o un Form, comprobamos antes si es un redirect, en el caso de que sea un redirect le agregamos un Return y listo. Otra cosa que podes hacer pero necesitarias mas cambios es hacer un metodo aparte para validar el formulario, pero si esta respuesta te sirve y sentis que es practica me quedaria con esa, sino estaria bueno esperar la respuesta de alguien que sepa mas que yo(casi todos XD), si no te sirve o tenes errores dejame un mensaje aca y mas tarde lo leo.
  #7 (permalink)  
Antiguo 01/11/2015, 14:50
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Funciona perfecto, pero ¿No hay otra solución? ¿Alguna forma que redireccione desde ese método?

Gracias
  #8 (permalink)  
Antiguo 02/11/2015, 05:39
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Perdona por ser pesado, pero ahora doy un paso más y el último. Me gustaría tener una clase aparte, solo para la creación de formulario ¿es buena práctica?

Esta es mi clase
Código PHP:
<?php
namespace TMKSeriesBundleController
;

use 
SymfonyBundleFrameworkBundleControllerController;
use 
TMKSeriesBundleEntitySeries;
use 
TMKSeriesBundleFormRegisterSerieType;

class 
FormCreator extends Controller{

    public function 
createFormAddSerie($request){
        
$serieForm = new Series();
        
$form $this->createForm(new RegisterSerieType$serieForm);
        
        if(
$request->getMethod() == 'POST'){
            
$form->bind($request);
            
            if(
$form->isValid()){
            
$manager $this->getDoctrine()->getManager();
                
$manager->persist($serieForm);
                
$manager->flush();

                return 
$this->redirect($this->generateURL('loadSeries', array('state' => $serieForm->getState())));
            }
        }
        
        return 
$form;
    }

}

?>
Al ejecutar mi aplicación me devuelve este error

FatalErrorException: Error: Call to a member function get() on null in /Applications/MAMP/htdocs/seriesmoko/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php line 163

Y este es el método del fichero Controller.php donde da el error
Código PHP:
    public function createForm($type$data null, array $options = array())
    {
        return 
$this->container->get('form.factory')->create($type$data$options);
    } 
¿Sabes cual puede ser el problema?

PD: Muchas gracias por toda la ayuda que me estás brindando
  #9 (permalink)  
Antiguo 02/11/2015, 17:52
 
Fecha de Ingreso: enero-2013
Ubicación: Santa Fe, VT
Mensajes: 68
Antigüedad: 11 años, 9 meses
Puntos: 2
Respuesta: Formularios en distinto método

Te voy a dar un ejemplo de symfony 2.6(Trata de adaptarlo a tu symfony), pero es algo complicado(ya que veo que tenes un nivel bajo de comprension en symfony):

Para crear una clase que administre los formularios como vos quieras vas a necesitar declararla como un servicio, primero creamos nuestra clase el directorio Utils de tu bundle(si no lo tenes lo creas)

Código PHP:
<?php
// AppBundle\Utils\Formularios.php;
namespace AppBundleUtils;

use 
SymfonyComponentFormFormFactoryInterface;
///ENTITY
use AppBundleEntityCuentas;
//TYPE
use AppBundleFormTypeCuentasType;

class 
Formularios
{
  public 
$formFactoryInterface;

  public function 
__construct(FormFactoryInterface $formFactoryInterface)
  {
    
$this->formFactoryInterface $formFactoryInterface;
  }

  public function 
getForm()
  {
    return 
$this->formFactoryInterface->create(new CuentasType(),new Cuentas());
  }
}
El FormFactoryInterface es para crear los formularios como si fuera del controller( $this->createForm).

luego vas a la configuracion de servicios(services.yml), yo la tengo en .yml :
Código YML:
Ver original
  1. my_form:
  2.         class: AppBundle\Utils\Formularios
  3.         arguments: ["@form.factory"]

La linea arguments es para insertar en la clase el servicio form.factory.

En el controller:
Código PHP:
public function cuentasAction(Request $request)
     {
$form$this->get('my_form')->getForm();
$form->handleRequest($request/// <--- Creo que es el equivalente de $form->bind

if($form->isValid()) {
          ......
          return .......;
}

 return 
$this->render('panel/registrarCuenta.html.twig',array(
             
'renderizar' => $form->createView()
         ));

Con eso ya estaria todo, tendrias que adaptarlo a lo que vos necesites, podes crear un formulario dentro de la clase Formularios con solo hacer:
$this->formFactoryInterface->create($type,$data,[$array])
como si fuera del controller, en mi ejemplo te devuelve el form, podes adaptarlo para que se valide desde esa clase o lo que vos quieras.

Con respecto si esto es buena practica, no lo se.
Espero haberte podido ayudar
  #10 (permalink)  
Antiguo 03/11/2015, 01:34
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Muy bien, noto como si lo tuviera casi, pero también quiero meter la ejecución del formulario, para eso he tenido que crear un objeto controller, esta es mi clase

Código PHP:
<?php

namespace TMKSeriesBundleUtils
;

use 
SymfonyBundleFrameworkBundleControllerController;
use 
SymfonyComponentFormFormFactoryInterface;
use 
TMKSeriesBundleEntitySeries;
use 
TMKSeriesBundleFormRegisterSerieType;

class 
FormCreator
{
    public 
$formFactoryInterface;
    
    public function 
__construct(FormFactoryInterface $formFactoryInterface){
        
$this->formFactoryInterface $formFactoryInterface;
    }
    
    public function 
getFormAddSerie($request){
        
$controller = new Controller();
        
$serie = new Series();
        
$form $this->formFactoryInterface->create(new RegisterSerieType(), $serie);
        
        if(
$request->getMethod() == 'POST'){
            
$form->bind($request);
            
            if(
$form->isValid()){
            
$manager $controller->getDoctrine()->getManager();
                
$manager->persist($serie);
                
$manager->flush();

                return 
$this->redirect($this->generateURL('loadSeries', array('state' => $serie->getState())));
            }
        }
        
        return 
$form;
    }

}
?>
Pero me devuelve este error:
FatalErrorException: Error: Call to a member function has() on null in /Applications/MAMP/htdocs/seriesmoko/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php line 198

Es cuando intenta hacer esta linea
Código PHP:
$manager $controller->getDoctrine()->getManager(); 
Este es el método del archivo controller:
Código PHP:
public function getDoctrine()
    {
        if (!
$this->container->has('doctrine')) {
            throw new 
LogicException('The DoctrineBundle is not registered in your application.');
        }

        return 
$this->container->get('doctrine');
    } 
PD: Estoy aprendiendo paso a paso symfony, pero me cuesta mucho mucho. Gracias

Última edición por Chino27; 03/11/2015 a las 01:52 Razón: Añadido el método del archivo controller
  #11 (permalink)  
Antiguo 03/11/2015, 16:59
 
Fecha de Ingreso: enero-2013
Ubicación: Santa Fe, VT
Mensajes: 68
Antigüedad: 11 años, 9 meses
Puntos: 2
Respuesta: Formularios en distinto método

Services.YML:
Código YML:
Ver original
  1. my_form:
  2.             class: AppBundle\Utils\Formularios
  3.             arguments: ["@form.factory","@doctrine.orm.entity_manager"]

Custom Class:
use Doctrine\ORM\EntityManager;
Código PHP:
 <?php

namespace TMKSeriesBundleUtils
;

//Agregamos el entity Manager de doctrine
use DoctrineORMEntityManager;

use 
SymfonyBundleFrameworkBundleControllerController;
use 
SymfonyComponentFormFormFactoryInterface;
use 
TMKSeriesBundleEntitySeries;
use 
TMKSeriesBundleFormRegisterSerieType;

class 
FormCreator
{
    public 
$formFactoryInterface;
    public 
$entityManager;
    
    public function 
__construct(FormFactoryInterface $formFactoryInterfaceEntityManager $entityManager){
        
$this->formFactoryInterface $formFactoryInterface;
        
$this->entityManager $entityManager;
    }
    
    public function 
getFormAddSerie($request){
        
//$controller = new Controller(); << no hace falta crear un controller
        
$serie = new Series();
        
$form $this->formFactoryInterface->create(new RegisterSerieType(), $serie);
        
        if(
$request->getMethod() == 'POST'){
            
$form->bind($request);
            
            if(
$form->isValid()){
                
$this->entityManager->persist($serie);
                
$this->entityManager->flush();
                
/* esto esta mal a menos que en el controller lo uses como te indique anteriormente
                *if(get_class($form) == 'Symfony\Component\HttpFoundation\RedirectResponse') 
                *{
                *return $form;
                *}
                */
                
return $this->redirect($this->generateURL('loadSeries', array('state' => $serie->getState()))); 
              
//return true;
              //return $form;
            
}
        }
        
        return 
$form;
    }

}
?>
Como ves, le agregas al constructor el EntityManager para usarlo desde la clase. Seguis haciendo lo de devolver un Response, si devolves un Response tenes que decirle al metodo del controller que es un response, sino cuando hagas el form->createView() te va a saltar el error de que ese metodo no existe ya que es un Response.
Sigo insistiendo que es mejor para mi hacer todo en el metodo del controller pero si te sirve para hacer lo que queres tambien es valido(creo).
El codigo no lo probe, si tiene un error trata de arreglarlo y adaptarlo a tu necesidad. Suerte
  #12 (permalink)  
Antiguo 03/11/2015, 18:03
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Va casi perfecto, esta al 99% pero aún me falla la linea que redirecciona, ya que no sería $this por que esta clase no es un controller
¿Qué sería en este caso?

PD Muchisimas gracias por todo
  #13 (permalink)  
Antiguo 03/11/2015, 20:32
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 4 meses
Puntos: 379
Respuesta: Formularios en distinto método

En este caso la clase es un servicio, en el mensaje 9 te muestra como llamar el servicio en tu controller
Código PHP:
Ver original
  1. $form= $this->get('my_form')->getForm();
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #14 (permalink)  
Antiguo 04/11/2015, 01:40
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Si eso si, ¿pero como hago esta linea dentro del este servicio?
Código PHP:
                return $this->redirect($this->generateURL('loadSeries', array('state' => $serie->getState()))); 
  #15 (permalink)  
Antiguo 04/11/2015, 09:48
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 11 años, 4 meses
Puntos: 379
Respuesta: Formularios en distinto método

Las redirecciones se hacen en el Controller que utiliza tu servicio
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #16 (permalink)  
Antiguo 04/11/2015, 14:40
 
Fecha de Ingreso: septiembre-2015
Mensajes: 71
Antigüedad: 9 años, 2 meses
Puntos: 0
Respuesta: Formularios en distinto método

Perfecto, muchas gracias por todo

Etiquetas: distinto, formularios
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 07:23.