Accessing route path in event listener - php

ROUTE:
user_lock:
path: /user/lock/{id}
defaults: { _controller: SiteMainBundle:Frontend\Default:userLock }
methods: [GET]
As you know, router above will create a URL like htt://mysite.com/app_dev.php/user/lock/66 so I need to get only /user/lock/66 part of it in event listener below. How can I do it?
I tried $request->getBaseUrl() and $request->getBasePath() didn't give me what I wanted.
YAML
services:
kernel.listener.kernel_controller:
class: Site\MainBundle\EventListener\Controller\KernelController
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
CLASS
<?php
namespace Site\MainBundle\EventListener\Controller;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class KernelController
{
public function onKernelController(FilterControllerEvent $event)
{
$request = $event->getRequest();
$this->writeLog('ROUTE', $request->attributes->get('_route'));
$this->writeLog('CONTROLLER', $request->attributes->get('_controller'));
$this->writeLog('ROUTE PARAMETERS', $request->attributes->get('_route_params'));
$this->writeLog('ROUTE PATH', ??????????????????????????????);
}
}

I think, you are looking for
$request->server->get('PATH_INFO');

Related

Call an route on each page

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.

Catch-all route in Symfony 3

I have a catch-all fallback route in Symfony2 that I couldn't get to work in Symfony3. I tried this exact syntax (a verbatim copy of my Symfony2 route) and that didn't work.
fallback:
path: /{req}
defaults: { _controller: MyBundle:Default:catchAll }
requirements:
req: ".+"
How can I get this working in Symfony3? (It's literally the only thing holding me back from using Symfony3 and keeping me at v2.8)
This should help you:
route1:
path: /{req}
defaults: { _controller: 'AppBundle:Default:index' }
requirements:
req: ".+"
Where, my controller is called "DefaultController", and I have a function called "indexAction()".
Here is my code for the DefaultController:
class DefaultController extends Controller
{
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
...
I actually did try what you said in my environment, and it didn't work until I had the right controller settings specified.
EDIT:
For this to work, it was necessary to add the parameter Request $request (with the type hint) to the action's method signature.
I found the current accepted answer almost useful for Symfony 4, so I'm going to add my solution:
This is what I did to get it working in Symfony 4:
Open /src/Controller/DefaultController.php, make sure there is a function called index(){}
It's not required to add the Request $request as first param as some comment suggest.
This is the method that will handle all urls caught by the routes.yaml
Open /config/routes.yaml, add this:
yourRouteNameHere:
path: /{req}
defaults: { _controller: 'App\Controller\DefaultController::index' }
requirements: # the controller --^ the method --^
req: ".*"` # not ".+"
You can also override Exception controller.
# app/config/config.yml
twig:
exception_controller: app.exception_controller:showAction
# app/config/services.yml
services:
app.exception_controller:
class: AppBundle\Controller\ExceptionController
arguments: ['#twig', '%kernel.debug%']
namespace AppBundle\Controller;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ExceptionController
{
protected $twig;
protected $debug;
public function __construct(\Twig_Environment $twig, $debug)
{
$this->twig = $twig;
$this->debug = $debug;
}
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
// some action
return new Response($this->twig->render('error/template.html.twig', [
'status_code' => $exception->getStatusCode()
]
));
}
}

Symfony default session variabe

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');
}
}
}

Symfony2: Check user authentication based on path

in Symfony2, is it possible to check if user is authenticated to access the URl he requested.
What I want to do is, i dont want to allow a logged in user to go back to registration or login or recover password pages.
here is my security.yml:
access_control:
- { path: ^/signup/, roles: IS_AUTHENTICATED_ANONYMOUSLY && !IS_AUTHENTICATED_FULLY}
- { path: ^/register/, roles: IS_AUTHENTICATED_ANONYMOUSLY && !IS_AUTHENTICATED_FULLY}
- { path: ^/recover/, roles: IS_AUTHENTICATED_ANONYMOUSLY && !IS_AUTHENTICATED_FULLY}
but this is showing, access denied page to current user. So i think it would be nice if I can redirect the user to home page on such request, by checking if he is not allowed. Can I check by providing path that user is authenticated or not in listener?
public function onKernelResponse(FilterResponseEvent $event)
{
$request = $event->getRequest();
$path = $request->getPathInfo();
if($this->container->get('security.context')->getToken() != null) {
// To check if user is authenticated or anonymous
if( ($this->container->get('security.context')->getToken() instanceof UsernamePasswordToken) &&
($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') == true) ) {
// HOW TO CHECK PATH ?
// set response to redirect to home page
}
}
}
The security.access_map service
The configuration of security.access_control is processed by ...
SecurityBundle\DependencyInjection\SecurityExtension
... which creates RequestMatchers for the routes (path,hosts,ip,...) and then invokes the service's add() method with the matcher, the allowed roles and the channel (i.e. https ).
The service is usually used by i.e. the AccessListener.
You can use the security.access_map service to access the
security.access_control parameters in your application.
The class used for the security.access_map service is defined by the parameter security.access_map.class and defaults to
Symfony\Component\Security\Http\AccessMap ( implements
AccessMapInterface )
You can use the parameter security.access_map.class to override the service with a custom class (must implement AccessMapInterface):
# i.e. app/config/config.yml
parameters:
security.access_map.class: My\Custom\AccessMap
How to access the service
The security.access_map service is a private service as you can see by it's definition here.
This means you can't request it from the container directly like this:
$this->container->get('security.access_map')
You will have to inject it into another service (i.e. a listener service) explicitly to be able to access it.
A listener example
services:
my_listener:
class: My\Bundle\MyListenerBundle\EventListener\ForbiddenRouteListener
arguments: [ #security.access_map ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Then you can call the getPatterns() method to obtain the RequestMatchers, allowed roles and required channel from there.
namespace My\Bundle\MyListenerBundle\EventListener;
use Symfony\Component\Security\Http\AccessMapInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class ForbiddenRouteListener
{
protected $accessMap;
public function __construct(AccessMapInterface $access_map)
{
$this->accessMap = $access_map;
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$patterns = $this->accessMap->getPatterns($request);
// ...
Maybe this will help someone. I just catch route name and check if they are in array. If yes just redirect. This is event listener.
services.yml
project.loggedin_listener:
class: Project\FrontBundle\EventListener\LoggedInListener
arguments: [ "#router", "#service_container" ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
listener:
namespace Project\FrontBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
class LoggedInListener {
private $router;
private $container;
public function __construct($router, $container)
{
$this->router = $router;
$this->container = $container;
}
public function onKernelRequest(GetResponseEvent $event)
{
$container = $this->container;
$accountRouteName = "_homepage";
if( $container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') ){
$routeName = $container->get('request')->get('_route');
$routes = array("admin_login","fos_user_security_login","fos_user_registration_register","fos_user_resetting_request");
if(in_array($routeName, $routes)){
$url = $this->router->generate($accountRouteName);
$event->setResponse(new RedirectResponse($url));
}
}
}
}
You can do not only inside security.yml options, but also via controller, like this:
if($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirect($this->generateUrl('homepage'));
}

How can I add multiple events in services.yml file as event Listeners in Doctrine symfony

I am using this:
my.listener:
class: Acme\SearchBundle\Listener\SearchIndexer
tags:
- { name: doctrine.event_listener, event: postPersist }
Now if I try to listen for two events like this:
- { name: doctrine.event_listener, event: postPersist, preUpdate }
it gives an error.
I think you can do like this:
my.listener:
class: Acme\SearchBundle\Listener\SearchIndexer
tags:
- { name: doctrine.event_listener, event: postPersist }
- { name: doctrine.event_listener, event: preUpdate }
You need an event subscriber instead of an event listener.
You'd change the service tag to doctrine.event_subscriber, and your class should implement Doctrine\Common\EventSubscriber. You need to define a getSubscribedEvents to satisfy EventSubscriber which returns an array of events you want to subscribe to.
ex
<?php
namespace Company\YourBundle\Listener;
use Doctrine\Common\EventArgs;
use Doctrine\Common\EventSubscriber;
class YourListener implements EventSubscriber
{
public function getSubscribedEvents()
{
return array('prePersist', 'onFlush');
}
public function prePersist(EventArgs $args)
{
}
public function onFlush(EventArgs $args)
{
}
}

Categories