title: Bind one route to different controllers depending on user roles
body: <p>In my Symfony 2 app I have 3 different user roles that can have access to a backend administration part :</p>
  
  <pre><code>role_hierarchy:
      ROLE_STAFF:     ROLE_USER
      ROLE_MODERATOR: ROLE_STAFF
      ROLE_ADMIN:     ROLE_MODERATOR
  </code></pre>
  
  <p>For a route like <code>http://example.org/admin/post/</code>, I'd like my app to display different informations depending on the user role, which means <strong>3 controllers</strong> binding to an <strong>only route</strong>.</p>
  
  <p>What's the best way to handle this ?</p>
  
  <p>I was thinking about some solutions but none seems to be good for me :</p>
  
  <ol>
  <li><p>One controller, and in each action I just test user role :</p>
  
  <pre><code>&lt;?php
  
  /**
   * @Route("/admin/post")
   */
  class PostController extends Controller
  {
      /**
       * Lists all post entities.
       *
       * @Route("/", name="post_index")
       * @Template()
       * @Secure(roles="ROLE_STAFF")
       */
      public function indexAction()
      {
          $user = $this-&gt;get('security.context')-&gt;getToken()-&gt;getUser();
  
          if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_STAFF')) {
              // Do ROLE_STAFF related stuff
          } else if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_MODERATOR')) {
              // Do ROLE_MODERATOR related stuff
          } else if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_ADMIN')) {
              // Do ROLE_ADMIN related stuff
          }
  
          return array('posts' =&gt; $posts);
      }
  }
  </code></pre>
  
  <p>Even if that does the job, IMO obviously that's not a good design.</p></li>
  <li><p>One BackendController that dispatch to 3 different controllers :</p>
  
  <pre><code>&lt;?php
  
  /**
   * @Route("/admin/post")
   */
  class PostBackendController extends Controller
  {
      /**
       * Lists all post entities.
       *
       * @Route("", name="admin_post_index")
       * @Template("AcmeBlogBundle:PostAdmin:index.html.twig")
       * @Secure(roles="ROLE_STAFF")
       */
      public function indexAction()
      {
          if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_STAFF')) {
              $response = $this-&gt;forward('AcmeBlogBundle:PostStaff:index');
          } else if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_MODERATOR')) {
              $response = $this-&gt;forward('AcmeBlogBundle:PostModerator:index');
          } else if ($this-&gt;get('security.context')-&gt;isGranted('ROLE_ADMIN')) {
              $response = $this-&gt;forward('AcmeBlogBundle:PostAdmin:index');
          }
  
          return $response;
      }
  }
  </code></pre>
  
  <p>Same as number one.</p></li>
  <li><p>I tried to make controllers extends each others :</p>
  
  <pre><code>&lt;?php
  
  /**
   * @Route("/admin/post")
   */
  class PostStaffController extends Controller
  {
      /**
       * Lists all post entities.
       *
       * @Route("/", name="post_index")
       * @Template()
       * @Secure(roles="ROLE_STAFF")
       */
      public function indexAction()
      {
          $user = $this-&gt;get('security.context')-&gt;getToken()-&gt;getUser();
  
          // Do ROLE_STAFF related stuff
  
          return array('posts' =&gt; $posts);
      }
  }
  
  &lt;?php
  
  /**
   * @Route("/admin/post")
   */
  class PostModeratorController extends PostStaffController
  {
      /**
       * Lists all post entities.
       *
       * @Route("/", name="post_index")
       * @Template()
       * @Secure(roles="ROLE_MODERATOR")
       */
      public function indexAction()
      {
          $user = $this-&gt;get('security.context')-&gt;getToken()-&gt;getUser();
  
          // As PostModeratorController extends PostStaffController,
          // I can either use parent action or redefine it here
  
          return array('posts' =&gt; $posts);
      }
  }
  
  &lt;?php
  
  /**
   * @Route("/admin/post")
   */
  class PostAdminController extends PostModeratorController
  {
      /**
       * Lists all post entities.
       *
       * @Route("/", name="post_index")
       * @Template()
       * @Secure(roles="ROLE_ADMIN")
       */
      public function indexAction()
      {
          $user = $this-&gt;get('security.context')-&gt;getToken()-&gt;getUser();
  
          // Same applies here
  
          return array('posts' =&gt; $posts);
      }
  }
  </code></pre>
  
  <p>IMO it's a better design but I can't manage to make it works. The routing system stops on the first controller it matches. I'd like to make it act king of cascading style automatically (i.e. if user is staff then go to PostStaffController, otherwise if user is moderator go to PostModeratorController, otherwise go to PostAdminController).</p></li>
  <li><p>Add a listener to kernel.controller in my BlogBundle which will do the same job as number 2 ?</p></li>
  </ol>
  
  <p>I'm looking for the best designed and the more flexible solution has there's chance that we add more roles in the future.</p>