I looked for this info in this forum and many others but I can't understand how to log messages in the profiler.
I attempt to log messages from my controller.
CalendarController.php :
<?php
namespace DJU\CalendarBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Psr\Log\LoggerInterface;
class CalendarController extends Controller
{
protected $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function getweekAction() {
$this->logger->info("this is a test message");
}
}
According to what I've read in the symfony doc, I've also modified the config.yml
app/config/config.yml
monolog:
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
console:
type: console
bubble: false
verbosity_levels:
VERBOSITY_VERBOSE: INFO
VERBOSITY_VERY_VERBOSE: DEBUG
channels: ["!doctrine"]
console_very_verbose:
type: console
bubble: false
verbosity_levels:
VERBOSITY_VERBOSE: NOTICE
VERBOSITY_VERY_VERBOSE: NOTICE
VERBOSITY_DEBUG: DEBUG
channels: ["doctrine"]
This is a simple copy paste from the config_dev.yml.
No log appears in the profiler.
Any suggestion?
Thank you
If you're using constructor in controller class then you should use controller as service to inject logger there.
Normally if you want to call logger service from controller you can simply get it from container:
class CalendarController extends Controller
{
public function getweekAction() {
$this->get('logger')->info("this is a test message");
}
}
what version of symfony? if you're on symfony 2.6 or higher you can just do dump('some log'); and it will appear in the profiler.
http://symfony.com/blog/new-in-symfony-2-6-vardumper-component
Related
Moving from symfony 3 to 4 I started injecting the service according to this.
Most functions where I inject the "helper" service it works fine, but for some reason it fails on a few of them and I can't figure out what I've done differently... Here's the error:
Could not resolve argument $helper of
"App\Controller\Poslog\OperatorController::historyindividualaction()",
maybe you forgot to register the controller as a service or missed
tagging it with the "controller.service_arguments"?
I've omitted the contents if the functions completely as it doesn't matter what they contain, I can comment out the entire code inside the HistoryIndividualAction() and still get the exact same error message.
The OperatorController::newAction() below works perfectly fine (as well as a number of other functions within the same object), while the OperatorController::HistoryIndividualAction() fails.
use App\Service\globalHelper as globalHelper;
...
class OperatorController extends AbstractController
{
public function newAction(Request $request, ACRGroup $ACRGroup = null, globalHelper $helper)
{
...
}
public function HistoryIndividualAction($operatorId, globalHelper $helper)
{
...
}
}
The routing looks like this
operator_new:
path: /new/{ACRGroup}
defaults: { _controller: App\Controller\Poslog\OperatorController::newAction, ACRGroup: null }
methods: [GET, POST]
operator_history_individual:
path: /history/individual/{operatorId}
defaults: { _controller: App\Controller\Poslog\OperatorController::historyIndividualAction }
methods: GET
Services.yml
# This file is the entry point to configure your own services.
# Files in the packages/ subdirectory configure your dependencies.
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en
services:
# default configuration for services in *this* file
_defaults:
autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
# makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# controllers are imported separately to make sure services can be injected
# as action arguments even if you don't extend any base controller class
App\Controller\:
resource: '../src/Controller/'
tags: ['controller.service_arguments']
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
globalHelper:
class: App\Service\globalHelper
public: false
arguments: ['#service_container', '#doctrine.orm.entity_manager']
GlobalHelper starts out like this:
namespace App\Service;
use Symfony\Component\DependencyInjection\ContainerInterface as Container;
//use Doctrine\ORM\EntityManager as EntityManager; //gave deprecation notice, profiler suggested to change to below and the deprecation notice disappeared.
use Doctrine\ORM\EntityManagerInterface as EntityManager;
class globalHelper {
private $container;
private $em;
public function __construct(Container $container, EntityManager $em) {
$this->container = $container;
$this->em = $em;
}
The basic problem is that method names are case sensitive and you had a mismatch.
// Change
public function HistoryIndividualAction(
// To
public function historyIndividualAction(
Normally I would just have called this a typo and moved on but the error is interesting. I would have expected perhaps an unknown method sort of message but Symfony would have dealt with that. The error comes from trying to process the method's arguments.
There is a huge sub-system behind Symfony's ability to inject action arguments. Not as simple as it may look and it involves caching information about the action signatures using the method name. And that is where the case mismatch becomes significant.
So I think it might be worth keeping this answer around just for developers who might encounter a similar error message.
Try sorting your arguments differently in your controller action.
public function newAction(Request $request, ACRGroup, globalHelper $helper, $ACRGroup = null) {
// ...
}
And try to clear the cache:
php bin/console cache:clear
I am new to Symfony framework and am trying to set up a project with Messenger (https://symfony.com/doc/current/messenger.html). My understanding is after setting up the handler class with “implements MessageHandlerInterface” the handler should be available for use but it does not seem to be working for me. I have tried several different things including setting up a new project from scratch. I am using Symfony 5.0.4.
I set up the project like this:
symfony new --full testMessenger
composer require messenger
php bin/console make:controller
Then I made a new messenger and handler and called it from the controller. Doing that I get the exception: “No handler for message "App\Message\Message".”
php bin/console debug:messenger
Output:
Messenger
=========
messenger.bus.default
---------------------
The following messages can be dispatched:
-----------------------------------------------------
Symfony\Component\Mailer\Messenger\SendEmailMessage
handled by mailer.messenger.message_handler
Symfony\Component\Notifier\Message\ChatMessage
handled by chatter.messenger.chat_handler
Symfony\Component\Notifier\Message\SmsMessage
handled by texter.messenger.sms_handler
-----------------------------------------------------
My code is basically the same as the samples in the message handler documentation, but I will add it here.
// src/Message.php
<?php
namespace App\Message;
class Message
{
private $content;
public function __construct(string $content)
{
$this->content = $content;
}
public function getContent(): string
{
return $this->content;
}
}
// src/MessageHandler.php
<?php
namespace App\MessageHandler;
use App\Message\Message;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;
class SmsNotificationHandler implements MessageHandlerInterface
{
public function __invoke(Message $message)
{
// ... do some work - like sending an SMS message!
}
}
// src/Controller/MessageController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use App\Message\Message;
class MessageController extends AbstractController
{
/**
* #Route("/message", name="message")
*/
public function index()
{
$this->dispatchMessage(new Message('Look! I created a message!'));
return $this->render('message/index.html.twig', [
'controller_name' => 'MessageController',
]);
}
}
//config/packages/messenger.yaml
framework:
messenger:
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
# failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
# async: '%env(MESSENGER_TRANSPORT_DSN)%'
# failed: 'doctrine://default?queue_name=failed'
# sync: 'sync://'
routing:
# Route your messages to the transports
# 'App\Message\YourMessage': async
I've struggled a little with similar case, so I hope this will help someone:
So I had autowiring on and multiple buses defined like this:
final class QueryBus implements QueryBusInterface
{
use HandleTrait {
HandleTrait::handle as messengerHandle;
}
public function __construct(MessageBusInterface $messageBus)
{
$this->messageBus = $messageBus;
}
public function handle(object $query): mixed
{
return $this->messengerHandle($query);
}
}
final class CommandBus implements CommandBusInterface
{
use HandleTrait;
public function __construct(
MessageBusInterface $messageBus
) {
$this->messageBus = $messageBus;
}
public function dispatch(object $command)
{
return $this->handle($command);
}
}
// messenger.yaml
framework:
messenger:
default_bus: command_bus
buses:
command_bus: ~
query_bus: ~
And I got the same error for when dispatching a query "No handler for message..."
Eventually what helped was:
Turn off autowiring in Bus implementation directories (by excluding paths in services.yaml.
App\:
resource: '../src/'
exclude:
- '../src/Bus/'
Manually define the services:
// services.yaml
services:
_defaults:
autowire: true
autoconfigure: true
App\src\Bus\CommandBus:
arguments:
- '#command_bus'
App\src\Bus\QueryBus:
arguments:
- '#query_bus'
So actually it seems it was autowiring issue - failing to autowire 2 implementations of same Interface (the MessageBusInterface). The actual error of missing service was hiding under the messenger component.
I am using Symfony2 and need to save the failed login attempts to the database.
I have the following methods which I think I should be using:
// Symfony/Component/Security/Http/Autentication/AbstractAuthenticationListener.php
onFailure()
onSuccess()
But I am not sure how to access the database connection from within them.
How could run a database insert from within these functions?
You need to define your own failure handler in security.yml
form_login:
provider: fos_userbundle
login_path: /user/login
csrf_provider: form.csrf_provider
failure_handler: myBundle.login.failure
Create a service to handle the failures
bundle.login.failure:
class: 'MyBundle\Services\AuthenticationFailureHandler'
arguments: ['#kernel']
Then build your failure handler:
<?php
namespace MyBundle\Services;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class AuthenticationFailureHandler extends DefaultAuthenticationFailureHandler
{
public function __construct(HttpKernelInterface $httpKernel)
{
$this->httpKernel = $httpKernel;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
// the auth just failed :-(
}
}
To save attempts to the database inject your Doctrine manager into the service and persist the attempt from within the onFail method.
Just for logging there is an easy way by using security.authentication.failure listener. See Symfony documentation. You could use this blog post on how to persist logs to the actual database.
namespace AppBundle\EventListener;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
class AuthenticationFailureListener implements LoggerAwareInterface
{
use LoggerAwareTrait;
public function onFailure(AuthenticationFailureEvent $event)
{
$token = $event->getAuthenticationToken();
$username = $token->getUsername();
$this->logger->info('Authentication failed', ['username' => $username]);
}
}
And in services.yml
app.authentication_failure_listener:
class: AppBundle\EventListener\AuthenticationFailureListener
calls:
- [setLogger, ['#logger']]
tags:
- { name: monolog.logger, channel: security }
- { name: kernel.event_listener, event: security.authentication.failure, method: onFailure }
what I am trying to do is to have custom error page, not only will they be extending the base layout but also I want extra up selling content in those pages too so changing templates only is not an option
regardless of the reason (404 Not Found or just missing variable) I would like to show my template and my content instead
I have spent hours trying to get this going with no luck
app/console --version
Symfony version 2.5.6 - app/dev/debug
I tried some resources, but couldn't get it working. The name a few:
http://symfony.com/doc/current/reference/configuration/twig.html
http://symfony.com/doc/current/cookbook/controller/error_pages.html
I'm running in dev with no debug, see app_dev.php below:
$kernel = new AppKernel('dev', false);
following the tutorials i got these extra bits
app/config/config.yml
twig:
exception_controller: SomethingAppBundle:Exception:show
in my bundle
<?php
namespace Something\AppBundle\Controller;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpKernel\Exception\FlattenException;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ExceptionController extends Controller
{
public function showAction( FlattenException $error, DebugLoggerInterface $debug)
{
print_r($error);
}
}
but my error controller does not get executed,
I am on purpose causing error by trying to echo undefined variable in different controller, since it should handle error from entire application
At the beginning you need to create action in the controller:
<?php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ErrorController extends Controller
{
public function notFoundAction()
{
return $this->render('error/404.html.twig');
}
}
Then you need to create a Listener:
<?php
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class NotFoundHttpExceptionListener
{
private $controller_resolver;
private $request_stack;
private $http_kernel;
public function __construct($controller_resolver, $request_stack, $http_kernel)
{
$this->controller_resolver = $controller_resolver;
$this->request_stack = $request_stack;
$this->http_kernel = $http_kernel;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getException() instanceof NotFoundHttpException) {
$request = new \Symfony\Component\HttpFoundation\Request();
$request->attributes->set('_controller', 'AppBundle:Error:notFound');
$controller = $this->controller_resolver->getController($request);
$path['_controller'] = $controller;
$subRequest = $this->request_stack->getCurrentRequest()->duplicate(array(), null, $path);
$event->setResponse($this->http_kernel->handle($subRequest, HttpKernelInterface::MASTER_REQUEST)); // Simulating "forward" in order to preserve the "Not Found URL"
}
}
}
Now register the service:
#AppBundle/Resources/config/services.yml
services:
kernel.listener.notFoundHttpException:
class: AppBundle\EventListener\NotFoundHttpExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException, priority: -10 }
arguments: [ #controller_resolver, #request_stack, #http_kernel ]
Not tested this, but rather it should work;)
EDIT:
Tested, it works. On the rendered page, you have a session, so you have access to app.user, his cart, and other matters related to the session.
How can I inject a service (the service that I created) into my Controller?
A setter injection would do.
<?php
namespace MyNamespace;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller
{
public function setMyService(MyService $myService)
{
$this->myService = $myService;
}
public function indexAction()
{
//Here I cannot access $this->myService;
//Because the setter is not called magically!
}
}
And my route settings :
// Resources/routing.yml
myController_index:
pattern: /test
defaults: { _controller: "FooBarBundle:MyController:index" }
I'm setting the service in another bundle :
// Resources/services.yml
parameters:
my.service.class: Path\To\My\Service
services:
my_service:
class: %my.service.class%
When the route is resolved, the service is not injected ( I know it shouldn't ).
I suppose somewhere in a yml file, I have to set:
calls:
- [setMyService, [#my_service]]
I am not using this Controller as a service, it's a regular Controller that serves a Request.
Edit: At this point in time, I am getting the service with $this->container->get('my_service'); But I need to inject it.
If you want to inject services into your controllers, you have to define controllers as services.
You could also take a look at JMSDiExtraBundle's special handling of controllers — if that solves your problem. But since I define my controllers as services, I haven't tried that.
When using the JMSDiExtraBundle you DON'T have to define your controller as a service (unlike #elnur said) and the code would be:
<?php
namespace MyNamespace;
use JMS\DiExtraBundle\Annotation as DI;
use Path\To\My\Service;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller
{
/**
* #var $myService Service
*
* #DI\Inject("my_service")
*/
protected $myService;
public function indexAction()
{
// $this->myService->method();
}
}
I find this approach very nice because you avoid writing a __construct() method.
Since it's 2017 ending now and there is no tag for Symfony 3 or upcoming Symfony 4 (and I think there should not be), this problem is solvable in a native much better way.
If you are still struggling and somehow ended up on this page and not in Symfony docs, then you should know, that you do not need to declare controller as service, as it is already registered as one.
What you need to do, is check you services.yml:
# app/config/services.yml
services:
# default configuration for services in *this* file
_defaults:
# ...
public: false
Change public: false to public:true if you want all services to be public.
Or explicitly add a service and declare it public:
# app/config/services.yml
services:
# ... same code as before
# explicitly configure the service
AppBundle\Service\MessageGenerator:
public: true
And then in your controller you can get the service:
use AppBundle\Service\MessageGenerator;
// accessing services like this only works if you extend Controller
class ProductController extends Controller
{
public function newAction()
{
// only works if your service is public
$messageGenerator = $this->get(MessageGenerator::class);
}
}
Read more:
Public vs Private services
Services in Container
If you don't want to define your controller as a service, you can add a listener to the kernel.controller event to configure it just before it is executed. This way, you can inject the services you need inside your controller using setters.
http://symfony.com/doc/current/components/http_kernel/introduction.html#component-http-kernel-kernel-controller