I am trying to set up a simple event listener to execute some code at the start of and before every request. I'm just trying to echo out a simple message to check it's all working.
If I make a mistake (e.g. a typo) or wrongly configure (like I have for the last 30 minutes) then it returns various error messages. But I think I have it setup as the error messages have gone.
This is my code:
I have added this to my /app/config.yml file
services:
kernel.listener.request_listener:
class: Acme\Bundle\NewBundle\EventListener\RequestListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelRequest }
And this is the code in the related file
namespace Acme\Bundle\NewBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\Response;
class RequestListener
{
public function onKernelRequest(GetResponseEvent $event)
{
$response = new Response();
$response->setContent("hello");
$event->setResponse($response);
}
}
I believe you have hooked into a wrong event kernel.exception, which is called/dispatched only when exception occurs.
I believe you should have hooked the kernel.request event,
services:
kernel.listener.request_listener:
class: Acme\Bundle\NewBundle\EventListener\RequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
kernel.request is called/dispatched on every request, and before starting to handle a request.
http://symfony.com/doc/2.0/book/internals.html#handling-requests
Before doing anything else, the kernel.request event is notified -- if one of the listeners returns a Response, it jumps to step 8 directly;
Related
I am getting the "Failed to start the session because headers have already been sent" error when running the sample smoke test url example from Symfony, https://symfony.com/doc/5.3/best_practices.html#smoke-test-your-urls
<?php
namespace App\Tests;
use Generator;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class ApplicationAvailabilityFunctionalTest extends WebTestCase
{
/**
* #dataProvider urlProvider
*/
public function testPageIsSuccessful($url)
{
$client = self::createClient();
$client->request('GET', $url);
$this->assertResponseIsSuccessful();
}
public function urlProvider(): Generator
{
yield ['/'];
}
}
I have configured mock sessions in my config/packages/framework.yaml file. There are no other overrides in the config/packages/test folder.
when#test:
framework:
test: true
session:
storage_factory_id: session.storage.factory.mock_file
The phpunit.xml.dist file has the appropriate environment specified for the "test" environment.
<server name="APP_ENV" value="test" force="true" />
It makes no difference whether I execute the test form within PHPStorm or from console via php bin/phpunit. I must be missing something with the configuration. Any ideas?
Here is a stack trace leading to the native session:
Answered my own question, but #dbrumann had me heading in the right direction with the event listener hint. Thanks
I added to services.yaml, the event listeners only for non-test environments.
when#dev:
services:
Symfony\Component\HttpKernel\Profiler\Profiler: '#profiler'
App\EventListener\RequestListener:
tags:
- { name: kernel.event_listener, event: kernel.request }
App\EventListener\ResponseListener:
tags:
- { name: kernel.event_listener, event: kernel.response }
when#prod:
services:
App\EventListener\RequestListener:
tags:
- { name: kernel.event_listener, event: kernel.request }
App\EventListener\ResponseListener:
tags:
- { name: kernel.event_listener, event: kernel.response }
Currently I have monolog sending me emails when there are errors. I found that 404 errors were just polluting my email and my provider ended up suspending my account due to the number of emails I sent myself. I decided to exclude all 404 errors because all of them were due to bots looking for vulnerabilities and not from clients.
Exclude code:
excluded_404s:
- ^/
The problem I'm seeing now is that symfony still logs 404 errors if the bots use http methods other than GET. My email is now polluted with entries like
HEAD :80/phpmyAdmin/
How can I exclude all 404 errors including those using http methods other than GET?
Edit:
Oh boy. Beginner mistake here. It seems that after my last deploy of the configuration I did not clear the prod cache and I'm figuring out that the config is cached. I'm using deployer to deploy my code updates but I guess the clear cache command is missing from it.
Symfony 4.1. upwords can can be configured to ignore HTTP Codes:
config/packages/monolog.yaml
monolog:
handlers:
main:
# ...
type: 'fingers_crossed'
excluded_http_codes: [404]
https://symfony.com/blog/new-in-symfony-4-1-ignore-specific-http-codes-from-logs
I know it is an old question, but it is the 1st one when googling.
Meanwhile I found a solution for symfony 3.4, if you need to exclude all 404 errors from your logs you can create an ExceptionListener and check if the exception is a NotFoundHttpException.
If it is the case, then just return a response so that the event is stopped and the logger will not handle the exception.
src/AppBundle/EventListener/ExceptionListener.php
namespace AppBundle\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if (! $exception instanceof NotFoundHttpException) {
return;
}
$response = new Response($exception->getMessage(), $exception->getStatusCode());
// returning a response stop the event propagation
$event->setResponse($response);
}
}
src/AppBundle/Resources/config/services.yml
services:
app.exception.listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
In Symfony 4/5 you can do:
<?php
declare(strict_types=1);
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class ExceptionListener
{
public function onKernelException(ExceptionEvent $event)
{
$exception = $event->getThrowable();
if ($exception instanceof NotFoundHttpException) {
$response = new Response($exception->getMessage(), $exception->getStatusCode());
$event->setResponse($response);
}
return;
}
}
and
App\EventListener\ExceptionListener:
tags:
- { name: kernel.event_listener, event: kernel.exception }
I have a service that is helping me to validate some forms. I want to set HTTP status code from inside of it when it finds that form is actually invalid.
Is it OK to do so? How do I do it? Thanks!
The way I would do that (probably there's lot more solutions) is throwing some (custom) exception in your service in case your form is invalid.
Then I would create an exception listener which would listen on kernel exception event. Configuration of such listener would look something like this (services.yml)
kernel.listener.your_listener:
class: Acme\Your\Namespace\YourExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onException }
And than your onException method in YourExceptionListener class:
public function onException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if ($exception instanceof YourCustomExceptionInterface) {
$response = new Response('', 400);
$event->setResponse($response);
}
}
This way you get nicely decoupled stuff, and your form validation service is independent of response.
I need to do one of two things (in priority order, but just need one of them).
All of this is to be done inside a function that runs as an Exception Event Listener (http://api.symfony.com/2.2/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.html).
Both below are totally easy inside a normal controller, but I can't see it possible inside an event listener function.
(1) Run a controller as normal and output as normal as though that route had been executed:
e.g. $event->runController('controllerName');
(2) render a template as normal using the same syntax as would inside a normal controller:
return $this->render('Bundle:Default:feedback.html.twig', array([template vars]));
take a look at symfony's default exception listener in Symfony\Component\HttpKernel\EventListener\ExceptionListener.
(1) running a controller can be realized this way:
$request = new \Symfony\Component\HttpFoundation\Request();
$request->setMethod('GET');
[..]
try {
$response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, true);
} catch (\Exception $e) {
return; // pass it to next exception listener this way
}
$event->setResponse($response);
(2) rendering a template in exception listener
all you need to do is pass templating (engine) to the listener inside the service.yml
services:
foobar.exception_listener_service:
class: %foobar.exception_listener_service.class%
arguments:
container: "#service_container"
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: 255 }
inside the listener you can render templates as listed below
$templating = $this->container->get('templating');
$response = new Response($templating->render('foobar:Exception:error404.html.twig', array('exception' => $exception)));
$event->setResponse($response);
I'm working with Symfony 2.1. I want to setup a redirect routine depending on User is logged in or not. The way I check it is $User->isLoggedIn() where User is a service.
I want to do this before a controller executes. I have few other things happening just before Controller executes. I use event: kernel.controller of kernel.event_listener to do those things. But I realized that I can not redirect to a URL using this event.
I understand I need to use event: kernel.request of kernel.event_listener to be able to redirect to a URL.
Problem.
I use the following logic to figure out whether I need to redirect or not.
if (!$controller[0] instanceof NoLogInNeededInterface) {
if (!$User->isLoggedIn()) {
//redirect here
}
}
So, in the kernel.request event, $controler[0] is not available. In the kernel.controller event, response can't be set (will be ignored).
Has anyone got same problem and solved. Or is there any better way of doing, what I'm trying to do?
I realized that what I wanted could be achieved by using kernel.exception event of kernel.event_listner.
So in Services:
my.service:
class: MyBundle\EventListner\ExceptionListner
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
arguments: [ %logoutUrl% ]
Then in the Class itself:
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
class ExceptionListner
{
protected $_url;
public function __construct($url)
{
$this->_url = $url;
}
public function onKernelException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
//dont necessarily need this condition
if ($exception instanceof RedirectException) {
$response = new RedirectResponse($this->_url);
$event->setResponse($response);
}
}
}
I'm still up for suggestion, if this is or is not better approach.
Hope this will help someone who is struggling as well.
P