diff --git a/book/controller.rst b/book/controller.rst index aa4ffb873e6..1c994d31ae2 100644 --- a/book/controller.rst +++ b/book/controller.rst @@ -430,24 +430,34 @@ Redirecting ~~~~~~~~~~~ If you want to redirect the user to another page, use the -:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::redirect` +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::redirectToRoute` method:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); + + // redirectToRoute is equivalent to using redirect() and generateUrl() together: + // return $this->redirect($this->generateUrl('homepage'), 301); } -The ``generateUrl()`` method is just a helper function that generates the URL -for a given route. For more information, see the :doc:`Routing ` -chapter. +.. versionadded:: 2.6 + The ``redirectToRoute()`` method was added in Symfony 2.6. Previously (and still now), you + could use ``redirect()`` and ``generateUrl()`` together for this (see the example below). + +Or, if you want to redirect externally, just use ``redirect()`` and pass it the URL:: + + public function indexAction() + { + return $this->redirect('http://symfony.com/doc'); + } -By default, the ``redirect()`` method performs a 302 (temporary) redirect. To +By default, the ``redirectToRoute()`` method performs a 302 (temporary) redirect. To perform a 301 (permanent) redirect, modify the second argument:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage'), 301); + return $this->redirectToRoute('homepage', 301); } .. tip:: @@ -623,12 +633,14 @@ For example, imagine you're processing a form submit:: if ($form->isValid()) { // do some sort of processing - $request->getSession()->getFlashBag()->add( + $this->addFlash( 'notice', 'Your changes were saved!' ); - return $this->redirect($this->generateUrl(...)); + // $this->addFlash is equivalent to $this->get('session')->getFlashBag()->add + + return $this->redirectToRoute(...); } return $this->render(...); diff --git a/book/doctrine.rst b/book/doctrine.rst index 0f3f62086d0..305f9fcde65 100644 --- a/book/doctrine.rst +++ b/book/doctrine.rst @@ -662,7 +662,7 @@ you have a route that maps a product id to an update action in a controller:: $product->setName('New product name!'); $em->flush(); - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); } Updating an object involves just three steps: diff --git a/book/forms.rst b/book/forms.rst index 06372726b56..b14ff5bedaa 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -234,7 +234,7 @@ controller:: if ($form->isValid()) { // perform some action, such as saving the task to the database - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } // ... @@ -319,7 +319,7 @@ querying if the "Save and add" button was clicked:: ? 'task_new' : 'task_success'; - return $this->redirect($this->generateUrl($nextAction)); + return $this->redirectToRoute($nextAction); } .. index:: @@ -1233,7 +1233,7 @@ it after a form submission can be done when the form is valid:: $em->persist($task); $em->flush(); - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } If, for some reason, you don't have access to your original ``$task`` object, diff --git a/book/propel.rst b/book/propel.rst index 7d5f919593e..a4acbe721ac 100644 --- a/book/propel.rst +++ b/book/propel.rst @@ -234,7 +234,7 @@ have a route that maps a product id to an update action in a controller:: $product->setName('New product name!'); $product->save(); - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); } Updating an object involves just three steps: diff --git a/book/security.rst b/book/security.rst index c9740cf71b2..312bffe5449 100644 --- a/book/security.rst +++ b/book/security.rst @@ -239,6 +239,77 @@ user to be logged in to access this URL: .. code-block:: php + 'access_control' => array( + array( + 'path' => '^/cart/checkout', + 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY', + 'requires_channel' => 'https', + ), + ), + +.. _book-security-securing-controller: + +Securing a Controller +~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 2.6 + The ``denyAccessUnlessGranted()`` method was introduced in Symfony 2.6. Previously (and + still now), you could check access directly and throw the ``AccessDeniedException`` as shown + in the example below). + +Protecting your application based on URL patterns is easy, but may not be +fine-grained enough in certain cases. When necessary, you can easily force +authorization from inside a controller:: + + // ... + + public function helloAction($name) + { + $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!'); + + // The second parameter is used to specify on what object the role is tested. + // + // Old way : + // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { + // throw $this->createAccessDeniedException('Unable to access this page!'); + // } + + // ... + } + +.. _book-security-securing-controller-annotations: + +.. versionadded:: 2.5 + The ``createAccessDeniedException`` method was introduced in Symfony 2.5. + +The :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createAccessDeniedException` +method creates a special :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` +object, which ultimately triggers a 403 HTTP response inside Symfony. + +Thanks to the SensioFrameworkExtraBundle, you can also secure your controller using annotations:: + + // ... + use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security; + + /** + * @Security("has_role('ROLE_ADMIN')") + */ + public function helloAction($name) + { + // ... + } + +For more information, see the +:doc:`FrameworkExtraBundle documentation `. + +Securing other Services +~~~~~~~~~~~~~~~~~~~~~~~ + +In fact, anything in Symfony can be protected using a strategy similar to +the one seen in the previous section. For example, suppose you have a service +(i.e. a PHP class) whose job is to send emails from one user to another. +You can restrict use of this class - no matter where it's being used from - +to users that have a specific role. // app/config/security.php $container->loadFromExtension('security', array( // ... @@ -798,9 +869,7 @@ You can easily deny access from inside a controller:: public function helloAction($name) { - if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - throw $this->createAccessDeniedException(); - } + $this->denyAccessUnlessGranted('ROLE_ADMIN'); // ... } @@ -833,6 +902,10 @@ using annotations:: */ public function helloAction($name) { + $this->denyAccessUnlessGranted(new Expression( + '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())' + )); + // ... } diff --git a/book/validation.rst b/book/validation.rst index be3fb1caeec..f2b17bb4154 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -231,7 +231,7 @@ workflow looks like the following from inside a controller:: if ($form->isValid()) { // the validation passed, do something with the $author object - return $this->redirect($this->generateUrl(...)); + return $this->redirectToRoute(...); } return $this->render('BlogBundle:Author:form.html.twig', array( diff --git a/components/form/introduction.rst b/components/form/introduction.rst index 09c947429b5..cc7c60a8751 100644 --- a/components/form/introduction.rst +++ b/components/form/introduction.rst @@ -587,7 +587,7 @@ method: // ... perform some action, such as saving the data to the database - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } // ... diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index fa400525187..9d8267c15d2 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -244,7 +244,7 @@ The following controller shows you how to handle the entire process:: $em->persist($document); $em->flush(); - return $this->redirect($this->generateUrl(...)); + return $this->redirectToRoute(...); } return array('form' => $form->createView()); @@ -267,7 +267,7 @@ in a moment to handle the file upload:: $em->persist($document); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } The ``upload()`` method will take advantage of the :class:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile` @@ -432,7 +432,7 @@ call to ``$document->upload()`` should be removed from the controller:: $em->persist($document); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } .. note:: diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 4e4abbb5a05..b6849791212 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -287,7 +287,7 @@ the validation and saves the data into the database:: $em->persist($registration->getUser()); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } return $this->render( diff --git a/cookbook/form/direct_submit.rst b/cookbook/form/direct_submit.rst index 221f7f534d8..7166210319b 100644 --- a/cookbook/form/direct_submit.rst +++ b/cookbook/form/direct_submit.rst @@ -25,7 +25,7 @@ submissions:: if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } return $this->render('AcmeTaskBundle:Default:new.html.twig', array( @@ -66,7 +66,7 @@ method, pass the submitted data directly to if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } } @@ -111,7 +111,7 @@ a convenient shortcut to the previous example:: if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } } diff --git a/cookbook/form/form_collections.rst b/cookbook/form/form_collections.rst index 9793a67d357..e050efd2e61 100644 --- a/cookbook/form/form_collections.rst +++ b/cookbook/form/form_collections.rst @@ -717,7 +717,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. $em->flush(); // redirect back to some edit page - return $this->redirect($this->generateUrl('task_edit', array('id' => $id))); + return $this->redirectToRoute('task_edit', array('id' => $id)); } // render some form template diff --git a/cookbook/security/remember_me.rst b/cookbook/security/remember_me.rst index 590d8d9eaac..2eec5dcfaa6 100644 --- a/cookbook/security/remember_me.rst +++ b/cookbook/security/remember_me.rst @@ -162,11 +162,7 @@ In the following example, the action is only allowed if the user has the public function editAction() { - if (false === $this->get('security.authorization_checker')->isGranted( - 'IS_AUTHENTICATED_FULLY' - )) { - throw new AccessDeniedException(); - } + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); // ... } diff --git a/cookbook/security/securing_services.rst b/cookbook/security/securing_services.rst index b11900638eb..c37022b25f4 100644 --- a/cookbook/security/securing_services.rst +++ b/cookbook/security/securing_services.rst @@ -14,9 +14,7 @@ and checking the current user's role:: public function helloAction($name) { - if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - throw new AccessDeniedException(); - } + $this->denyAccessUnlessGranted('ROLE_ADMIN'); // ... } diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 114b2e587b3..e719f921c14 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -328,13 +328,13 @@ You can also store "flash messages" that will auto-delete after the next request They are useful when you need to set a success message before redirecting the user to another page (which will then show the message):: - public function indexAction(Request $request) - { - // ... + // store a message for the very next request (in a controller) + $this->addFlash('notice', 'Congratulations, your action succeeded!'); - // store a message for the very next request - $this->addFlash('notice', 'Congratulations, your action succeeded!'); - } +.. code-block:: html+jinja + + {# display the flash message in the template #} +