私の Symfony 2 アプリには、バックエンド管理部分にアクセスできる 3 つの異なるユーザー ロールがあります。
role_hierarchy:
ROLE_STAFF: ROLE_USER
ROLE_MODERATOR: ROLE_STAFF
ROLE_ADMIN: ROLE_MODERATOR
のようなルートhttp://example.org/admin/post/
の場合、ユーザーの役割に応じてアプリにさまざまな情報を表示させたいと考えています。つまり、3 つのコントローラーが唯一のルートにバインドされていることを意味します。
これを処理する最良の方法は何ですか?
私はいくつかの解決策を考えていましたが、どれも私にとって良いものではないようです:
1 つのコントローラーで、各アクションでユーザー ロールをテストするだけです。
<?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->get('security.context')->getToken()->getUser(); if ($this->get('security.context')->isGranted('ROLE_STAFF')) { // Do ROLE_STAFF related stuff } else if ($this->get('security.context')->isGranted('ROLE_MODERATOR')) { // Do ROLE_MODERATOR related stuff } else if ($this->get('security.context')->isGranted('ROLE_ADMIN')) { // Do ROLE_ADMIN related stuff } return array('posts' => $posts); } }
それが機能したとしても、IMO は明らかにそれは良い設計ではありません。
3 つの異なるコントローラーにディスパッチする 1 つの BackendController :
<?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->get('security.context')->isGranted('ROLE_STAFF')) { $response = $this->forward('AcmeBlogBundle:PostStaff:index'); } else if ($this->get('security.context')->isGranted('ROLE_MODERATOR')) { $response = $this->forward('AcmeBlogBundle:PostModerator:index'); } else if ($this->get('security.context')->isGranted('ROLE_ADMIN')) { $response = $this->forward('AcmeBlogBundle:PostAdmin:index'); } return $response; } }
1号と同じ。
コントローラーを互いに拡張させようとしました:
<?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->get('security.context')->getToken()->getUser(); // Do ROLE_STAFF related stuff return array('posts' => $posts); } } <?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->get('security.context')->getToken()->getUser(); // As PostModeratorController extends PostStaffController, // I can either use parent action or redefine it here return array('posts' => $posts); } } <?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->get('security.context')->getToken()->getUser(); // Same applies here return array('posts' => $posts); } }
IMO はより良い設計ですが、うまく機能させることができません。ルーティング システムは、一致する最初のコントローラーで停止します。私はそれを自動的にカスケード スタイルのキングとして機能させたいと思います (つまり、ユーザーがスタッフの場合は PostStaffController に移動し、ユーザーがモデレーターの場合は PostModeratorController に移動し、それ以外の場合は PostAdminController に移動します)。
2番と同じ仕事をするBlogBundleのkernel.controllerにリスナーを追加しますか?
最適な設計のソリューションを探していますが、より柔軟なソリューションには、将来さらに役割を追加する可能性があります。