My goal is to recognize the local user's browser and automatically set the language.
Then allow the user to change language and keep it on other pages.
At the time I set the routes in this way:
# homepage not localized: load the homepage with default language
index_not_localized:
path: /
defaults: { _controller: "AcmeSiteBundle:Default:index", _locale: %locale% }
acme_site:
resource: "#AcmeSiteBundle/Controller/"
type: annotation
prefix: /{_locale}
defaults: { _locale: %locale% }
requirements:
_locale: %route_locale_requirements%
When the user enters the page example.com without specifying the language in the local route is set by default, and the page there is a switcher that allows you to change the language:
<ul class="dropdown-menu">
{% for locale in ['en', 'it'] %}
<li>
<a href="{{ path('homepage', {'_locale': locale}) }}">
</li>
{% endfor %}
</ul>
How do I do what I want?
I have to create a listener? I have put the local session?
I'm confused, I read several answers but have not found a clear answer!
There are at least two ways, but both of them don't gave you 100% guarantee to detect locale and detect it right.
The first is to use $_SERVER['HTTP_ACCEPT_LANGUAGE'] variable. It's gotten via HTTP Headers and can even doesn't exist.
The second is to use 3rd-side services to detect country by IP address and then compare country name to some local table of countries and their locales. For example:
http://api.hostip.info/get_html.php?ip=127.0.0.1
For more information and comments look at this question: Simplest way to detect client locale in PHP
And the final point is to integrate locale detection into the symfony2 project. This is the simplest part. You just need to use kernel.request event listner. Everything is perfectly explained (with examples) here: Symfony 2.1 set locale
Related
I have a weird issue happening. My app uploads an image then returns an absolute URL eg. http://localhost:8000/uploads/images/12-6.jpg to the path via json through from where the user can crop amongst other edits.
This seems to work fine in production mode but I am having problems in dev because for some reason the app decides to match the route defines below:
category:
path: /{parent}/{id}/{category}
defaults: { _controller: "AppBundle:Default:showCat", category: '' }
Is there anyway I can prevent this from happening?
Thanks in advance
Maybe it is working in production because you didn't clear the cache with env=prod?
Your route is too broad, it match almost everything. uploads/images/12-6.jpg match your route with parent: upload, id : images, category 12-6.jpg.
Take a look at the doc if you need more information
You should add a prefix to your route (like categ/{parent}/{id}/{category}) or use requirements like below:
category:
path: categ/{parent}/{id}/{category}
defaults: { _controller: "AppBundle:Default:showCat", category: '' }
requirements:
id: \d+
I recommend you to use a prefix AND a requirement, to not have future route problems
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 %}
I'm building a web application using symfony2. I have different types of users with different roles; ROLE_STUDENT and ROLE_TEACHER, those two user can access a course's details; if the user is a teacher, a button edit is shown and if it's the student then a button subscribe will be shown, and actually this is not secure because it just hides the path to the controllers action, if the student types in the address bar /course/2/edit the edit action would be executed so I had to secure the action using #security annotation:
This is what I have done so far:
/**
* #Security("has_role('ROLE_TEACHER')")
*/ public function editAction()
{}
and in twig :
{% if is_granted('ROLE_TEACHER') %}
edit
{% elseif is_granted('ROLE_STUDENT')%}
subscribe
.
The problem is that I have a lot of accessible content to both users and I think there is a better solution to this instead of copy/past the same code all over. I'm new to Symfony 2, please bear with me.
There are multiple ways to achieve this but what you are doing is not wrong.
One way to achieve this is to set ROLE for the ROUTES so that ROLE_STUDENT roles can only access URLs that will be something like this website.com/students and ROLE_TEACHER can only access website.com/teachers
access_control:
- { path: ^/student/, roles: ROLE_STUDENT }
- { path: ^/teamleader/, roles: ROLE_TEACHER }
You can then set the edit route only for teachers like website.com/teachers/course/2/edit this way no edit route is going to be available for ROLE_STUDENT and they will get 404 error or access denied error if they try to access teacher route. You can do the same for the subscribe feature.
Like I said there are more ways to achieve this and this is one of them.
I have a project (symfony 2.3) and I have some static pages, but i need i18n. What is the best way to achieve it?
I was trying something like this with specific twig templates for each locale, but not work.
static_about:
path: /{_locale}/about
defaults:
_controller: FrameworkBundle:Template:template
template: 'EscFrontendBundle:Static/{_locale}_about.html.twig'
problem:
While {_locale} in the path works with static content ...
... {_locale} in the route's template setting is not being replaced by symfony.
solution:
To overcome this just use a "base" twig template about.html.twig containing an include like this:
{% include app.request.locale ~ '_about.html.twig' %}
I have this in my twig template:
{% trans %}lala{% endtrans %}
{{ 'Presentation'|trans|raw }}
and lots of not translatable twig html in between.
And the only way it applies translations is when in the controller action I call the translator:
$t = $this->get('translator')->trans('lala');
If I comment the line above, the translation does not occur. How can I force that? (Well, what am I doing wrong?)
For more info, this is my config.yml file:
framework:
translator: { fallback: %locale% }
default_locale: "%locale%"
And I get the locale variable through my routing:
my_bundle_name:
resource: "#MyBundle/Resources/config/routing.yml"
prefix: /{_locale}/add
requirements:
_locale: en|ja
EDIT:
The files are located like a normal symfony project.
my twig template is located in:
src/COMP/myBundle/Resources/views/entity1/new.twig.html
The only difference might be that it extends a base template which is located in
src/COMP/myBundle/Resources/views/base.html.twig
The translation are also located in the Resources folder:
src/COMP/myBundle/Resources/translations/messages.en.xlf
src/COMP/myBundle/Resources/translations/messages.ja.xlf
src/COMP/myBundle/Resources/translations/validators.ja.xlf
the controller is also located in the default place:
src/COMP/myBundle/Controller/myentitycontroller.php
I've been keeping developing with that trick, to explicitly call the translator, and now it suddenly works even without that workaround. And I am unable to repeat the same beheaviour as before.
I am still curious of why was that happening to me, but maybe I should delete the question...
My first guess is that I was trying to translate a template which was a "partial". I mean, from base.html.twig I was calling an action of a controller:
{{ render(controller('COMPMyBundle:Default:Welcome', {'aprequest': app.request})) }}
But I am unable to repeat the same beheaviour. (Before, when that was happening to me, and now, when I am trying to get the same beheaviour, I cleared the cache several times, so it shouldn't be that).