Symfony2 homepage different for authenticated users - symfony

How can I define my Symfony2 routes to show a different homepage for authenticated users and non-authenticated users? For example, I want to do something like this in my routing.yml file:
homepage_authenticated:
path: /
defaults:
_controller: AcmeBundle:Home:homeAuthenticated
requirements:
user: is_authenticated_remembered # <--- this part here
homepage:
path: /
defaults:
_controller: AcmeBundle:Home:home
Now obviously this doesn't work because I just invented it, but I'm sure there must be a way to do this, but I can't find it. I have an idea Expressions may be the solution to this somehow, but I can't find any examples of actually using them, anywhere.

As Malcom suggested in the comment, it is better to handle redirects/page-rendering based on user's authentication status in the controller.
The security context saves the role related data and the authentication status. You can redirect your users to different pages by checking
$this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') and $this->get('security.context')->isGranted('ROLE_NAME').
For example:
public function homeAction()
{
$em = $this->getDoctrine()->getEntityManager();
if ($this->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY')) {
//Path handling for authenticated users
if ($this->get('security.context')->isGranted('ROLE_ADMIN')) {
return $this->redirect($this->generateUrl('admin_homepage'));
}
if ($this->get('security.context')->isGranted('ROLE_USER')) {
return $this->render('VenomCoreBundle:Default:home.html.twig', array(
'notifications' => $notifications,
'unApprovedCount' => $unApprovedCount,
'status' => $stats,
));
}
}
//non authenticated users are redirected here
return $this->render('VenomCoreBundle:Default:login.html.twig');
}

Related

How to add item_permission on delete action in easyadmin?

I use EasyadminBundle for the Backend of a Symfony application.
Two type of users have access to the back-end and I'd like to keep the right to delete to a small number of persons granted with ROLE_ADMIN.
I'd like to use item_permission parameter as for the other actions (such as show or list) :
Lieu:
class: App\Entity\Lieu
list:
item_permission: ROLE_ENCADRANT
delete:
item_permission: ROLE_ADMIN
But it's not working and I can still delete user when I'm logged with ROLE_ENCADRANT. Is there another solution ?
I currently accomplish it with:
Lieu:
class: App\Entity\Lieu
list:
item_permission: ROLE_ENCADRANT
action: ['-delete']
help: "the delete button is accessible in <b>Edit</b> view"
form:
item_permission: ROLE_ADMIN
I'm just looking for a 100% configuration solution, more elegant than mine.
Take a look at adding an action in the docs. The action can be tied to a route, which allows specifying what role may perform the action. The downside is that the list view button is present regardless of role. You can add a flash message to advise the user whether they have permission.
Here's an example from a project. Not quite what you're looking for but may get you started:
easyadmin.yaml:
Admin:
class: App\Entity\Admin
disabled_actions: ['new', 'edit']
list:
actions:
-
name: 'admin_enabler'
type: 'route'
label: 'Enable/Disable'
controller:
/**
* #Route("/enabler", name = "admin_enabler")
*/
public function enabler(Request $request)
{
$em = $this->getDoctrine()->getManager();
$id = $request->query->get('id');
$admin = $em->getRepository(Admin::class)->find($id);
$enabled = $admin->isEnabled();
if (!$admin->isActivator() && !$admin->hasRole('ROLE_SUPER_ADMIN')) {
$admin->setEnabled(!$enabled);
$em->persist($admin);
$em->flush();
} else {
$this->addFlash('danger', $admin->getFullName() . ' cannot be disabled');
}
return $this->redirectToRoute('easyadmin', array(
'action' => 'list',
'entity' => $request->query->get('entity'),
));
}

Symfony redirect to route passing url slug

I've searched this on SO previously, but it seems that the only answers given are when parameters are passed as a query string, which is not what I want.
I have a page in my Symfony 3 CRM with a route app_litter. There is a required URL slug called litter_id which needs to be passed to the route in order to determine which litter data to show, as follows:
/litter/1
My route definiton in the routing file is:
app_view_litter:
path: /litter/{id}
defaults: { _controller: AppBundle:Litter:view, id: null }
requirements:
id: \d+
There is a function which allows a user to add puppies to their litter, which is a form outside of this page - once the puppies are successfully saved, I want to redirect the user back to the litter in question, so I did this:
return $this->redirectToRoute('app_litter', array('litter_id' => $litter->getId()));
Where $litter is the object retrieved from Symfony. However, this redirects to:
/litter?litter_id=1
Which does not work, as it expects a slug. Is it possible to use redirectToRoute() (or any other method) to render the route with a slug instead of a query string?
Because your route definition is:
app_view_litter:
path: /litter/{id}
defaults: { _controller: AppBundle:Litter:view, id: null }
requirements:
id: \d+
When using the route generator you need to provide an associated array with keys corresponding to the name of your placeholders which is in your case id.
Therefore, it must be:
$this->redirectToRoute('app_litter', array('id' => $litter->getId()));
If you want to use a slug, and there something which not only composed of digits (\d+), you have to either define a new route or modify the existing.
app_view_litter_using_slug:
path: /litter/{slug}
defaults: { _controller: AppBundle:Litter:view, slug: null }
requirements:
id: .*
And you something like:
$this->redirectToRoute('app_litter_using_slug', array('slug' => $litter->getSlug()));
Could it be that you are using the wrong route? Try using app_view_litter instead of app_litter:
return $this->redirectToRoute('app_view_litter', array('id' => $litter->getId()));

Symfony2 Set _locale in home page base on browser's configuration

My local works everywhere on my website but I cant tell the application the set the proper local on the root of the application.
For exemple :
If my website is http://mycompany.com I want that, when I enter this address the application guess what is my local and set it at the end of the url
http://mycompany.com/en if the local exist on my application. Here en or fr and if not the default en
For now when i go to home page I always get english version but my browser is set in french
routing.yml :
_welcome:
pattern: /{_locale}
defaults: { _controller: MyBundle:Default:landing, _locale: en }
requirements:
_locale: en|fr
See this question asked a few days ago and take a look at the first method in the language listener. It does exactly what you need. And take care of the right settings in config.yml
With the help of many other questions related to locale and symfony2 I finally get want I want ! I guess it is not the perfect answer but at least it works !
My landing action is defined in my routing as _welcome route. It is this action that is loaded when I go to the url's root.
/**
* #Route("/landing")
* #Template()
*/
public function landingAction() {
$localeAvailable = array('en', 'fr');
//user language
$localeUser = substr($this->getRequest()->getPreferredLanguage(), 0, 2);
//application language
$localeApp = $this->getRequest()->attributes->get('_locale');
//Redirect to the good locale page
//only if the locale user is on our manager locale and it is not the current locale of the application
if(in_array($localeUser, $localeAvailable) && $localeApp!=$localeUser){
return $this->redirect($this->generateUrl("_welcome", array('_locale' => $localeUser)));
}
return array();
}

Symfony 2 inconsistency in logout route: logout redirect to login?

I'd like to solve this inconsistency in my Symfony 2 application: when user is not authenticated path /app/logout redirects to /app/login. Instead, user not authenticated should view an error page (maybe 403).
Here is the security configuration. The IS_AUTHENTICATED_FULLY seems mandatory, as an user can do logout only if it's previously authenticated fully:
access_control:
- { path: ^/app/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/app/logout, roles: IS_AUTHENTICATED_FULLY }
And the logout action of my AccessController:
/**
* #Extra\Route("logout")
* #Extra\Template
*/
public function logoutAction()
{
// Set the token to null and invalidate the session
$this->getSecurityContext()->setToken(null);
$this->getSession()->invalidate();
// Redirect url and seconds (window.location)
$seconds = 5;
$redirect = $this->getRouter()->generate('access_login');
return array('seconds' => $seconds, 'redirect' => $redirect);
}
One solution would be removing the route /app/logout from access control and then throwing an exception if user it's not fully authenticated:
if(false === $this->getSecurityContext()->isGranted('IS_AUTHENTICATED_FULLY'))
throw new AccessDeniedException();
But this way /app/logout would be accessible even from not authenticated users! Anyone knows a better solution?
Just remove the logout path from access_control. Nothing bad is going to happen if a not authenticated user goes to the logout page — it's safe. Don't overengineer this stuff. ;)
BTW, why aren't you using the Symfony's built-in logout controller? You could create a logout handler to put your custom code in it instead of reinventing the wheel by handling all the logout stuff yourself.

Symfony 2 FOSFacebookBundle custom redirection before login

i'm using the FOSUserBundle and the FOSFacebookBundle (for version SF 2.0.x) in my project. Additionally, i implemented and custom FacebookProvider as described in the FOSFacebookBundle documentation. I would like to achieve the following workflow:
1.) A user visits my portal the first time
2.) He clicks the Facebook-Login-Button
3.) Now i need to check, if this user, who clicked the Facebook-Login-Button has already Facebook-Friends on my portal.
4.) If he has friends, redirect him to a sign-up page (including information from Facebook like, username, first_name, last_name, etc.) with prefilled input fields.
5.) If he has no Facebook-friends on my portal, redirect him to another page
I've started looking at the Webprofiler, which events are called. I've started creating my own event listener as descried on this page: http://www.dobervich.com/2011/10/13/login-redirection-revisited/ but the profile shows me my listener in the list of "not called listeners": security.interactive_login SecurityListener::onSecurityInteractiveLogin
Does anyone know, how i could customize this pre-login-check and redirect a user to a page?
Would be great to get some help on this.
Thank you,
Ramo
You need to configure a custom authentication success handler. Configure a service that implements AuthenticationSuccessHandlerInterface:
facebook_auth_success_handler:
class: MyHandler
public: false
arguments:
# your dependencies...
Then add this handler to security.yml under your fos_facebook block:
firewalls:
foo:
fos_facebook:
success_handler: facebook_auth_success_handler
The handler itself should look something like this:
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$user = $token->getUser();
$hasFriendsHereAlready = // your logic here
if ($hasFriendsHereAlready) {
$route = 'foo';
} else {
$route = 'bar';
}
return new RedirectResponse($this->router->generate($route));
}

Resources