Routing one url to two controller actions based on authentication - symfony

I'm a bit new to Symfony, but I've got an easy to explain situation:
I've got a public home page, and a private home page. I'd like to have both of these accessible with the URL "/"
When a non-authenticated person visits the address www.example.com/ I'd like for them to be routed to PublicController::indexAction()
When an authenticated user visits the address www.example.com/ I'd like for them to be routed to Privatecontroller::indexAction()
Is this possible?
(symfony 2.7 btw)

Definitely possible, although the details depend on what you're doing in each controller action. The easiest way would be to have:
class PublicController extends \Symfony\Bundle\FrameworkBundle\Controller\Controller
{
public function indexAction()
{
if ($this->getUser() !== null) {
return $this->forward('BundleName:PrivateController:index');
}
// do public controller details
}
}
So by default everyone is sent to PublicController:indexAction which does a check to see if there is a logged in user (using the getUser method from Symfony's Controller class) and if there is, forward the request over to PrivateController:indexAction. If not, then it just shows the public action as expected. You could invert this if you're expecting more logged in than logged out users as there will be a performance penalty for forwarding (as Symfony will create and dispatch a subrequest).
The longer answer is understanding what you're doing in each controller that requires them to be separate and whether you could combine the functionality into a service or otherwise re-architect them. Without knowing more about your specific problem domain, the above seems like the best way forward.

Got a social network startup running on Symfony (always using latest versions) so naturally I encountered this challenge of showing different content on the homepage dependent on first, your loggedin or not status, and second if logged in different personalized content dependent on your logged in user id. Although the answer above works, I found it much better and performant to use twig to display which content because I could use the render_esi tag to use a reverse proxy cache and avoid not just database lookups but template generation and the whole request hitting Symfony.
For example
{# src/MyApp/AppBundle/Resources/views/Page/index.html.twig #}
{% extends 'MyAppAppBundle::layout.html.twig' %}
.....
{% block body %}
{% if not app.user %}
Code for non-logged in user
e.g. {{ render_esi(controller('MyAppAppBundle:Home:non_logged_in_user')) }}
{% else %}
Code for logged in user
e.g {{ render_esi(controller('controller('MyAppAppBundle:Home:logged_in_user', { 'user': app.user.id })) }}
{% endif %}
....
{% endblock %}

Related

Symfony generate css

I need a little help.
Imagine that in database for every user have stored color of background.
Everytime when user login, first for that user in some folder is generated css file with name of id of user and included in html template.
I need help to understand how to generate css file ?
Thanks.
I Symfony with FOSUserBundle, you can use app.user to get the user in your twig files.
If you open a MySQL console and enter describe fos_user; then you will see all the fields you can use in your Twig file. So in your table you could store for each of the FOS users a color
Then in Twig you could use something like this:
{% if app.user %}
{% set backColor = app.user.color %}
{% else %}
{% set backColor = 'none' %}
{% endif %}
...
<body style="background-color:{{ backColor }};">
You get the idea...
You might want to figure out a way to store the color preference for the FOS user using a Symfony form. And then store preference in database. You can raise a separate question for that if you have difficulties - it should be easy.
Quite simple...
You need to generate a twig file for every user in your desired folder, and place "inline" CSS in it.
{% block css %}
<style>
.class {
parameter: {{ entity.value }};
}
</style>
{% endblock css %}
To generate the file, create a service, which you will call when a page is loaded.
It will have to first check if the file exist, if it does, it will read from it (no query to the DB), if not, it will generate the file, and read need data from DB.
Look at answer from me and Gopal on this page to know how to make a service How to use session in Symfony.
You sould be able to use it for your need... ;)
Also look at the Symfony Filesystem Component
file_put_contents() should help you write content of the file... ;)

How to pass user informations to a template using Symfony2 and FosUserBundle

I'm using symfony2, I installed FosUserBundle and I created a bundle UserBundle as indicated in the FosUserBundle online docs. so far so good.
I also created another controller and I'm able to access the logged user information in this way:
$user = $this->container->get('security.context')->getToken()->getUser();
now imagine that in my website, for all the pages/controller, I need to display some user information, even a simple "Welcome MyUser" at the top of the page (so in base.html.twig). I don't want to replicate the line above in all the controllers, so where is the best place to get this information once and pass them to the base template?
For the example you gave, "Welcome MyUser" , you can get this var in twig template with
{% if is_granted("ROLE") %}
Hi {{ app.user.username }}
{% endif %}
This is, if you don't need logic
Also if you didn't knew it you can use heritage in twig, so that you can create a navbar.html.twig with this fosuser var in it, and then in all your templates do
{% extends "AcmeMyBundle::navbar.html.twig" %}
{% block body %}
....
{% endblock %}

Symfony - translations stop working after rendering controler in another's view

I'm building a webiste, where there will be lots of "widgets" displayed on the front page. One of them is the calendar.
I wanted to make a new controller for each this "widget", and then render them all (like the example below), in the Homepage view.
Hovewer - the translations stop working after that. If I visit mywebpage/calendar, they work, but not when I got to mywebpage/home.
This is the code I currently have for my Homepage view.
{% block Calendar %}
{{ render(controller('MyWebsite:Calendar:index')) }}
{% endblock %}
Am I approaching this correctly or not? And why do the translations stop working?
Also - I hope you will understand what the issue is :)
Thanks!
I am surprised that doesn't work, do you have anything else in your app interfering with the Request object?
Maybe passing the locale from the request as an argument to the controller may work (although a bit of a hack)?
{% block Calendar %}
{{ render(controller('MyWebsite:Calendar:index', { _locale: app.request.locale })) }}
{% endblock %}

Is there a way for TWIG to access page's access_control settings in security config file?

I new to Symfony.
I want a piece of code only to show on pages that are publicly available. Is it possible for Twig to detect if the page is public?
The page is under IS_AUTHENTICATED_ANONYMOUSLY, but I still want the piece of code to show even if the user is already logged-in.
For Example:
www.somesite.com (shows the code, publicly available)
www.somesite.com/login (user login, publicly available, shows code)
//user is not logged in
www.somesite.com/dosomething (only available to logged-in users, code is hidden)
//user goes to the home page, still logged-in
www.somesite.com (must show the code, publicly available)
I know I could manually include the code for my public pages, but is there a way to automatically detect if the page is outside the firewall?
Please Help. =)
You can hide parts of twig template with a check like so:
{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
{# stuff only logged in users can see #}
{% endif %}
Or check for role IS_AUTHENTICATED_FULLY
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{# stuff only logged in users can see #}
{% endif %}
Check the doc here: http://symfony.com/doc/current/book/security.html#retrieving-the-user-object
i guess there is no way to do this. =(

In Symfony2 -> Twig, how to detect if the execution is from CLI mode or through browser?

I am making a Symfony2 console command that will send a e-mail rendering a Twig template.
The e-mail template uses some standard layout that is also included in the e-mails sent from browser requests.
In this template i have some links like this:
{{ url('deal_category_index', {'city':app.session.get('system.user.city'), 'slug':cat.getSlug()}) }}
But if i use the app.session in CLI mode, i get this error:
An exception has been thrown during the rendering of a template ("You cannot create a service ("request") of an inactive scope ("request").")
So i need a way to know if the template is rendered from CLI so i can use a "generic" way to create this link.
Thank you!
Extract the city from the session in the controller and pass it to the render() function. This way, your template should look like:
{{ url('deal_category_index', {'city': city, 'slug':cat.getSlug()}) }}
And in your controller:
$this->render("YourBundle:Yourcontroller:yourView.html.twig', array('city' => $this->get('session')->get('system.user.city'), 'cat' => $category);
When calling the render() in CLI, you should grab the city from database instead of the session.
Wrap the layout part depending on the request context in a block:
{% block foobar_url %}
{{ url('deal_category_index', {'city':app.session.get('system.user.city')}) }}
{% endblock %}
Use this layout in the emails sent from browser context just as you did before.
Override the code block foobar_url in your CLI templates like so:
{% block foobar_url %}
{{ url('deal_category_index', {'city':cityRetrievedFromDatabaseOrElsewhere}) }}
{% endblock %}

Resources