amougel
amougel

Reputation: 329

Call a specific controller's action from form inputs

In my view where you can see other users' profile, I want to add a small form only visible for admins and moderators where they can select the role they want to give to the displayed user.

I created a Controller with an action for each promotion type (Becasue the requires are different for each (for exemple : only admins can promote someone admin role) and can be changed).

Now I am not sure if I should :

*Create a in my Twig view and somehow (please help me), redirect to the action accordingly to the inputs (like this maybe)

{% if is_granted("ROLE_MODERATEUR") %}
                        Rendre ce membre : 
                                <form name="form" >
                                <select>
                                    <option >Sélectionner un rôle</option>
                                    {% if is_granted("ROLE_ADMIN") %}
                                    <option value="{{ path('annuaire_admin_admin', {id:membre.id}) }}" >Administrateur</option>
                                    {% endif %}
                                    <option value="{{ path('annuaire_admin_moderateur', {id:membre.id})}}" >Modérateur</option>
                                    <option value="{{ path('annuaire_admin_actif', {id:membre.id})}}" >Utilisateur actif</option>
                                    <option value="{{ path('annuaire_admin_passif', {id:membre.id}) }}" >Utilisateur passif</option>
                                </select>
                                <input type="submit" value="Confirmer">
                                </form>
                    {% endif %}

*Create something more "symfony like" like a FormType or a class to handle this functionnality.

Here is my Controller:

namespace Cua\AnnuaireBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

class AdminController extends Controller
{

    public function adminAction($id)
    {   
        if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
            throw new AccessDeniedException();
        }elseif (isset($id)){

            $membre =$this->getDoctrine()
            ->getManager()
            ->getRepository('CuaUserBundle:Membre')
            ->find($id);

        // Ou nul si aucun membre  n'a été trouvé avec l'id $id
            if($membre === null)
            {
            throw $this->createNotFoundException('Membre[id='.$id.'] inexistant.');

            }
            $membre->setRole("ROLE_ADMIN");
        }
    }

    public function moderateurAction($id)
    {
        if (false === $this->get('security.context')->isGranted('ROLE_MODERATEUR')) {
            throw new AccessDeniedException();
        }elseif (isset($id)){

            $membre =$this->getDoctrine()
            ->getManager()
            ->getRepository('CuaUserBundle:Membre')
            ->find($id);

            // Ou nul si aucun membre  n'a été trouvé avec l'id $id
            if($membre === null)
            {
                throw $this->createNotFoundException('Membre[id='.$id.'] inexistant.');

            }
            if (!$membre->hasRole("ROLE_ADMIN") or $this->get('security.context')->isGranted('ROLE_ADMIN')){
                $membre->setRole("ROLE_MODERATEUR");
            }
        }
    }

    public function actifAction($id)
    {
        if (false === $this->get('security.context')->isGranted('ROLE_MODERATEUR')) {
            throw new AccessDeniedException();
        }elseif (isset($id)){

            $membre =$this->getDoctrine()
            ->getManager()
            ->getRepository('CuaUserBundle:Membre')
            ->find($id);

            // Ou nul si aucun membre  n'a été trouvé avec l'id $id
            if($membre === null)
            {
                throw $this->createNotFoundException('Membre[id='.$id.'] inexistant.');

            }
            if (!$membre->hasRole("ROLE_ADMIN") or $this->get('security.context')->isGranted('ROLE_ADMIN')){
                $membre->setRole("ROLE_UTILISATEUR_ACTIF");
            }
        }
    }

    public function passifAction($id)
    {
        if (false === $this->get('security.context')->isGranted('ROLE_MODERATEUR')) {
            throw new AccessDeniedException();
        }elseif (isset($id)){

            $membre =$this->getDoctrine()
            ->getManager()
            ->getRepository('CuaUserBundle:Membre')
            ->find($id);

            // Ou nul si aucun membre  n'a été trouvé avec l'id $id
            if($membre === null)
            {
                throw $this->createNotFoundException('Membre[id='.$id.'] inexistant.');

            }
            if (!$membre->hasRole("ROLE_ADMIN") or $this->get('security.context')->isGranted('ROLE_ADMIN')){
                $membre->setRole("ROLE_UTILISATEUR_PASSIF");
            }
        }
    }
}

Thank you for your advices!

Upvotes: 0

Views: 2658

Answers (3)

amougel
amougel

Reputation: 329

I am not sure, if it's here that i should post, but the commentary section is too short. So here is my MainController(ProfilController):

<?php

namespace Cua\AnnuaireBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Cua\AnnuaireBundle\Form\Type\RoleType;
class ProfilController extends Controller
{

    public function voirAction($id)
    {   
        $request=$this->get('request');
        if ($request->getMethod() == 'POST') {
            $admin=$this->get('admin');
            $admin->roleAction($request, $id);
        }
        if (isset($id))
        {   

            $membre =$this->getDoctrine()
            ->getManager()
            ->getRepository('CuaUserBundle:Membre')
            ->find($id);

        // Ou nul si aucun membre  n'a été trouvé avec l'id $id
            if($membre === null)
            {
            throw $this->createNotFoundException('Membre[id='.$id.'] inexistant.');

            }
        }else{
            $membre=$this->getUser();
        }
        $form=$this->CreateForm(new RoleType());
        $postes=$this->getDoctrine()->getManager()->getRepository('CuaAnnuaireBundle:Poste')->listerPostes($membre);
        $cheerups=$this->getDoctrine()->getManager()->getRepository('CuaAnnuaireBundle:Cheerup')->listerCheerups($membre);
        return $this->render('CuaAnnuaireBundle:Profil:voir.html.twig', array('membre' => $membre, 'postes'=>$postes, 'form'=>$form->CreateView(), 'cheerups' =>$cheerups
        ));
    }
}

And here is my modified AdminController:

<?php

namespace Cua\AnnuaireBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Cua\AnnuaireBundle\Form\Type\RoleType;
class AdminController extends Controller
{

    public function roleAction($donnees, $id)
    {
        //We could create an object representing the data behind the form here,
        //but we don't have to.  If we don't, we get a simple array back
        $form2 = $this->createForm(new RoleType() ); //Object representing form itself

        $form2->handleRequest($donnees);

            if ($form2->isValid() )
            {
                 //Get the data from the form, in the form of an array
                 $data = $form2->getData();

                 //Get role chosen from form data (key is fieldname) and choose appropriate method to make change
                 switch($data['role'] ) { 
                     case "admin":
                         $this->donneAdmin($id);
                         break;//etc

I use the RoleType Frumious suggested. When I submit the form, I get this exeption : "FatalErrorException: Error: Call to a member function get() on a non-object in C:\wamp\www\CuaProject\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\Controller.php line 163"

I am not sure about my use of namespace :

**I call to the AdminController passing of the "$donnees" wich may alter the type of "$request". Maybe it is unnecesseray because I could still access the "$request" in my Admin:roleAction knowing the namespace is the same?

*I named the form in AdminController"form2" because the namespace being the same, I wanted to avoid conflict (was it necessary?)

Upvotes: 0

frumious
frumious

Reputation: 1575

You've got what seems like two separate questions there.

Symfony Forms

Basic Form Structure

For creating the form, I agree with Haig that making a FormType is probably best: it packages up everything very nicely, and is easy. Your form is quite simple, though (one field), so it's up to you. Either way, I would use Symfony's Form infrastructure (generating HTML, handling submissions and processing HTTP data into objects), it's very convenient.

Multiple Actions

As for how your form submission can cause different activities based on the dropdown, in your example you've got several Roles as the options in your dropdown, and you want each option to hit a different Symfony Action. This is possible - you'd could use Javascript to alter the form action according to the option chosen - but untidy. Nicer, and more fitting with Symfony Forms, would be to have them all going to one Action (roleAction, for example), and then within that Action examining the role field and executing another method to carry out the required task (these methods would be similar to your existing Actions).

e.g.

FormType

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class RoleType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('role', 'choice', ['choices' => ['admin'=>'Administrateur', 'actif'=>'Actif']]) //etc etc
            ->add('save', 'submit');
    }

    public function getName()
    {
        return 'role';
    }
}

Controller

public function roleAction(Request $request, $id)
{   
    //We could create an object representing the data behind the form here,
    //but we don't have to.  If we don't, we get a simple array back
    //http://symfony.com/doc/current/book/forms.html#using-a-form-without-a-class
    $form = $this->createForm(new RoleType() ); //Object representing form itself

    $form->handleRequest($request);

    if ($form->isValid() )
    {
         //Get the data from the form, in the form of an array
         $data = $form->getData();

         //Get role chosen from form data (key is fieldname) and choose appropriate method to make change
         switch($data['role'] ) 
             case "moderateur":
                 $this->donneModerateur($id);
                 break;
             case "actif":
                 $this->donneActif($id);
                 break;
             //etc etc
    }
}

private function donneModerateur($id)
{
    //Similar to previous Action
}

You'll need to set the Form to submit to a URL containing the user ID, something like ->setAction($this->generateUrl('annuaire_admin_', ['id'=>$user->getId()]))

Upvotes: 1

Leo Bedrosian
Leo Bedrosian

Reputation: 3799

I tend to favor using Symfony form type classes over embedding forms directly into a view. This is because form type classes are extremely reusable, the form handling and validation is taken care of for you (resulting in much leaner controllers and models), and it's very easy to extend if you ever need to add more fields.

I'd certainly recommend going that route. In my experience, once you understand how to create and use Symfony form models and types, it really feels quite clumsy and inefficient going back to hardcoded forms. How to do this is well documented:

Creating Forms from Classes

Upvotes: 0

Related Questions