Could you help me. How can I set default varibles in session in pre-initialization framework, not in some controller? thanks
Symfony has events to which you can attach your own event listener. And the one you could attach your event listener would be kernel.request. Here is the sample source code you can use.
First, inside your services.yml file under Resources/config folder:
services:
listener.my_request_listener:
class: My\AwesomeBundle\Listener\MyListener
arguments: [ #session ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Second, your MyListenerwill look like this:
namespace My\AwesomeBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Session;
class MyListener
{
protected $session;
public function __construct(SessionInterface $session)
{
$this->session = $session;
}
public function onKernelRequest(GetResponseEvent $event)
{
$kernel = $event->getKernel();
$request = $event->getRequest();
//Your logic goes here
if($this->session->has('someKey')){
$this->session->set('someKey','newvalue');
}
}
}
Related
I have a question. I added a new service PopupListener.php:
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\DependencyInjection\ContainerInterface;
class PopupListener
{
protected $router;
public function __construct(Router $router)
{
$this->router = $router;
}
public function onKernelRequest()
{
$this->router->generate('app_popup_trigger');
}
}
services.yml :
popup_listener:
class: App\DesktopBundle\Listeners\PopupListener
arguments: ["#router"]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
routing.yml :
app_popup_trigger:
path: /popup/trigger
defaults: { _controller: AppDesktopBundle:Popup:triggerPopup }
The triggerPopupAction :
class PopupController extends Controller{
public function triggerPopupAction(){
return $this->render('AppDesktopBundle:Popup:index.html.twig', array());
}
}
I want that at each route call the new route added : app_popup_trigger. I made somethink like that but not work. The route is not called. Can you help me please ?
Basically use FOSJsRoutingBundle and trigger your route with javascript. That will be easier than listeners for a popup.
To call a specific route at the start of every request, you just need to extend your code in your PopupListener:
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class PopupListener
{
protected $router;
protected $httpKernel;
public function __construct(Router $router, HttpKernelInterface $httpKernel)
{
$this->router = $router;
$this->httpKernel = $httpKernel;
}
public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$subRequest = Request::create($this->router->generate('app_popup_trigger'));
$response = $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
// do something with the $response here
}
}
Symfony will start a new request-response cycle just for this sub-request and will return the $response of this cycle. Then you have to decide what you are doing with that reponse.
And then add the additional service to your service configuration:
popup_listener:
class: App\DesktopBundle\Listeners\PopupListener
arguments: ["#router", "#http_kernel"]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
You can get more information about symfony sub-requests here: The HttpKernel Component - Sub Request. I linked the documentation for Symfony 2.3. But keep in mind Symfony 2.3 is not maintained anymore and you should consider upgrading to 3.x.
I want to do some post-processing after sending a response object in my Symfony controller. Problem is, the post-processing requires other methods contained in my controller object. I'd like to do something like this:
public function testAction() {
$dispatcher = new EventDispatcher();
$dispatcher->addListener('kernel.terminate', function (Event $event) {
$controller->get('logger');
$logger->info('hello');
});
return new Response();
}
How can I inject the $controller variable into my kernel.terminate post-processing?
it seems you need only the container in your service. To get the container injected into your event listener I prefer to create a separate EventListener which you have to register in your container see code:
First create event listener class:
<?php
namespace Acme\DemoBundle\Listener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\DependencyInjection\ContainerInterface;
class RequestListener
{
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$logger = $this->container->get('logger')->getToken();
$logger->info('.....');
}
}
As you can see, we have now the service container injected and we are able to use it.
Next you have to register the service and inject the service container:
services:
acme.demo.listener.request:
class: Acme\DemoBundle\Listener\RequestListener
arguments: [ #service_container ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Notice in your case you have to select the event you wanna inject to. In my case I used the kernel.request event. You have to select the kernel.terminate event.
That can also be helpful: http://symfony.com/doc/current/cookbook/service_container/event_listener.html
I just began with symfony
I'm trying to build a multilang website but I have a problem to change the locale
I read some posts and I read the documentation about this but the locale don't change, I try:
public function indexAction()
{
$this->get('session')->set('_locale', 'fr');
$request = $this->getRequest();
$locale = $request->getLocale();
return $this->render('PhoneMainBundle:Default:index.html.twig',array('locale'=>$locale));
}
but the value in $locale is always 'en' (my default locale)
I also try
public function indexAction()
{
$this->get('session')->set('_locale', 'fr');
$request = $this->getRequest();
$request->setLocale('fr');
$locale = $request->getLocale();
return $this->render('PhoneMainBundle:Default:index.html.twig',array('locale'=>$locale));
}
In this case $locale is fr but the translations are always from messages.en.yml
I'd like in a first time to detect the user locale using $_SERVER['HTTP_ACCEPT_LANGUAGE'], maybe using a listner on each page actualisation ?
and after I will create a route to change the locale
But I 'd like to find a way to change the locale.
Thanks for your help
Based on this and this answers.
LanguageListener.php:
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LanguageListener
{
private $session;
public function setSession(Session $session)
{
$this->session = $session;
}
public function setLocale(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
$request->setLocale($request->getPreferredLanguage(array('en', 'de')));
}
}
services.yml:
acme.language.kernel_request_listener:
class: Acme\UserBundle\EventListener\LanguageListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: setLocale }
About wrong locale detection in twig, there could be a lot of different causes. Search through the SO, you'll definitely find the answer. Make sure that your '_local' var is defined right, make sure that you put your languages files in the right place, etc. FInally, read again the last version of the documentation: http://symfony.com/doc/current/book/translation.html
I however added this to make it more dynamic
services.yml
services:
acme.language.kernel_request_listener:
class: Acme\UserBundle\EventListener\LanguageListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: setLocale }
arguments: [ #router, #service_container ]
LanguageListener.php:
<?php
namespace Acme\UserBundle\EventListener;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LanguageListener
{
private $session;
private $container;
private $router;
public function __construct($router, $container)
{
// ...
$this->router= $router;
$this->container = $container;
}
public function setSession(Session $session)
{
$this->session = $session;
}
public function setLocale(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
$request = $event->getRequest();
$request->setLocale($request->getPreferredLanguage($this->container->parameters['jms_i18n_routing.locales']));
}
}
Just to be able to get the parameters and values from config.yml.
Regards,
Wick
If for example your default locale is french, except for one controller you want to have the default locale set to english can do that:
routing.yml
desktop_comingsoonpage:
resource: "#RemmelComparabusBundle/Controller/ComingsoonpageController.php"
defaults: { _locale: en }
type: annotation
more info : Symfony doc
I want to create custom events called user_logged so that i can attach my listeners to those events.
I want to execute few functions whenever user has logged in.
Create a class which extends Symfony\Component\EventDispatcher\Event.
Then, use the event dispatcher service to dispatch the event:
$eventDispatcher = $container->get('event_dispatcher');
$eventDispatcher->dispatch('custom.event.identifier', $event);
You can register your event listener service like so:
tags:
- { name: kernel.event_listener, event: custom.event.identifier, method: onCustomEvent }
This answer is little bit extend answer.
services.yml
custom.event.home_page_event:
class: AppBundle\EventSubscriber\HomePageEventSubscriber
tags:
- { name: kernel.event_listener, event: custom.event.home_page_event, method: onCustomEvent }
AppBundle/EventSubscriber/HomePageEventSubscriber.php
namespace AppBundle\EventSubscriber;
class HomePageEventSubscriber
{
public function onCustomEvent($event)
{
var_dump($event->getCode());
}
}
AppBundle/Event/HomePageEvent.php
namespace AppBundle\Event;
use Symfony\Component\EventDispatcher\Event;
class HomePageEvent extends Event
{
private $code;
public function setCode($code)
{
$this->code = $code;
}
public function getCode()
{
return $this->code;
}
}
anywhere you wish, for example in home page controller
use AppBundle\Event\HomePageEvent;
// ...
$eventDispatcher = $this->get('event_dispatcher');
$event = new HomePageEvent();
$event->setCode(200);
$eventDispatcher->dispatch('custom.event.home_page_event', $event);
I need to perform a set of actions after a user successfully logs in. This includes loading data from the database and storing it in the session.
What is the best approach to implementing this?
You can add a listener to the security.interactive_login event.
attach your listener like so. In this example I also pass the security context and session as dependencies.
Note: SecurityContext is deprecated as of Symfony 2.6. Please refer to
http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
parameters:
# ...
account.security_listener.class: Company\AccountBundle\Listener\SecurityListener
services:
# ...
account.security_listener:
class: %account.security_listener.class%
arguments: ['#security.context', '#session']
tags:
- { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
and in your listener you can store whatever you want on the session. In this case I set the users timezone.
<?php
namespace Company\AccountBundle\Listener;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class SecurityListener
{
public function __construct(SecurityContextInterface $security, Session $session)
{
$this->security = $security;
$this->session = $session;
}
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$timezone = $this->security->getToken()->getUser()->getTimezone();
if (empty($timezone)) {
$timezone = 'UTC';
}
$this->session->set('timezone', $timezone);
}
}
You can even fetch the user instance from the event itself, no need to inject the token storage!
public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
{
$event->getAuthenticationToken()->getUser()
}