Is it possible, to make a time-based link / controller action in symfony2 in the annotation? With a start and a stopdate!?
For example:
/**
*#Route("/mylink", start="14.10.2015" stop="20.12.2015", name="mylink", schemes= { "http" })
public function myLinkAction()
{
.....
}
You cannot extend #Route that way but with defaults and I think the best solution without boilerplate code is a controller filter:
services.yml
services:
time_range_route_filter:
class: AppBundle\Services\TimeRangeRouteFilter
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onFilterController }
DefaultController.php
class DefaultController
{
/**
* #Route("/", name="homepage", defaults={"start"="2015-01-01", "end"="2016-01-01"})
*/
public function indexAction()
{
}
}
TimeRangeRouteFilter.php
class TimeRangeRouteFilter
{
public function onFilterController(FilterControllerEvent $event) {
$request = $event->getRequest();
$attributes = $request->attributes;
$routeParams = $attributes->get('_route_params');
$end = $routeParams['end'];
$start = $routeParams['start'];
if(!/* in range */) {
throw new NotFoundHttpException();
}
}
}
Related
I get some trouble when I would load symfony app:
php.CRITICAL: Type error: Argument 1 passed to Doctrine\Common\EventManager::addEventSubscriber() must implement interface Doctrine\Common\EventSubscriber, instance of optro\Help\ORM\Listener\MessageElasticaListener
See my service configuration:
helpdesk.listner.optro:
class: Optro\Help\ORM\Listener\MessageElasticaListener
arguments:
- '#fos_elastica.object_persister.optro.technical_assistance'
- '#fos_elastica.indexable'
- { index: technical_assistance, type: post, identifier: id }
tags:
- { name: doctrine.event_listener, event: elastica.index.index_post_populate }
This is my class MessageElasticaListener:
use Doctrine\Common\EventArgs;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use FOS\ElasticaBundle\Doctrine\Listener as ElasticaListener;
use optro\Help\Entity\HelpdeskMessage;
class MessageElasticaListener extends ElasticaListener
{
/**
* {#inheritdoc}
*/
private function isObjectIndexable($object)
{
return true;
}
/**
* {#inheritdoc}
*/
public function postPersist(LifecycleEventArgs $eventArgs)
{
if (!$eventArgs instanceof LifecycleEventArgs) {
return;
}
$entity = $eventArgs->getObject();
if ($entity instanceof HelpdeskMessage && $this->isObjectIndexable($entity->getTechnicalAssistance())) {
$this->objectPersister->replaceOne($entity->getTechnicalAssistance());
}
}
}
What's wrong ? Bad services configuration ?
I use symfony 3.4 and FOS Elasticasearch 5.0.3
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 am trying to set up a kernal.controller listener to redirect to another route when a function returns true. I have the route available to me but no way to set the controller from this route using $event->setController().
I'm getting the following error:
FatalThrowableError in FilterControllerEvent.php line 59:
Type error: Argument 1 passed to Symfony\Component\HttpKernel\Event\FilterControllerEvent::setController() must be callable, string given
Does anyone have suggestions on how I can complete this?
class BlockListener
{
public function onKernelController(FilterControllerEvent $event)
{
$block = $this->blockService->checkForBlock($user->getId());
if ($block instanceof Block) {
// $block-getRoute() is a standard Symfony route string. It doesn't work!
$event->setController($block->getRoute());
}
}
}
We were able to get it working by using a Lambda function. Thanks for the help!
if ($block instanceof Block) {
$redirectUrl = $this->router->generate($block->getRoute());
$event->setController(function() use ($redirectUrl) {
return new RedirectResponse($redirectUrl);
});
};
You can modify options below as you wish.
OPTION 1
Full details
LISTENER
namespace Application\BackendBundle\EventListener;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class KernelExceptionListener
{
private $router;
private $redirectRouter = 'application_frontend_default_index';
public function __construct(Router $router)
{
$this->router = $router;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if ($exception instanceof NotFoundHttpException) {
if ($event->getRequest()->get('_route') == $this->redirectRouter) {
return;
}
$url = $this->router->generate($this->redirectRouter);
$response = new RedirectResponse($url);
$event->setResponse($response);
}
}
}
SERVICE DEFINITION
services:
application_backend.event_listener.kernel_exception:
class: Application\BackendBundle\EventListener\KernelExceptionListener
arguments: [#router]
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
OPTION 2
Full details
LISTENER
namespace Application\FrontendBundle\Listener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class PlayerListener
{
public function onKernelController(FilterControllerEvent $event)
{
$message = 'Bye inanzzz';
$event->setController(
function() use ($message) {
return new Response($message, 400);
}
);
}
}
SERVICE DEFINITION
services:
application_frontend.listener.player:
class: Application\FrontendBundle\Listener\PlayerListener
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
Try this instead:
$event->setController( $event->getController() );
I think it should work, but no guarantees.
This passes in the controller instead of a string, which is what your error indicates.
I need to validate a form field against bad words dictionary (Array for example). So to do this I have to create a new Constraint + ConstraintValidator. It works great, the only problem I have is that I want to have different dictionaries for different locales.
Example:
namespace MyNameSpace\Category\MyFormBundle\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class ContainsNoBadWordsValidator extends ConstraintValidator
{
protected $badWordsEN = array('blabla');
protected $badWordsFR = array('otherblabla');
public function validate($value, Constraint $constraint)
{
if (in_array(strtolower($value), array_map('strtolower', $this->getBadWords()))) {
$this->context->addViolation($constraint->message, array('{{ value }}' => $value));
}
}
protected function getBadWords($locale = 'EN')
{
switch ($locale) {
case 'FR':
return $this->badWordsFR;
break;
default:
return $this->badWordsEN;
break;
}
}
}
So how do I pass the locale to Constraint? Or should I implement it differently?
The locale parameter is a member of the Request object.
However, the request object is not created all the time (eg. in a CLI application)
This solution allows you to decouple your validation from the request object, and let your validation to be easily unit-tested.
The LocaleHolder is a request-listener which will hold upon creation the %locale% parameter and then, switch to the Request locale when the event is triggered.
Note: The %locale% parameter is the default parameter defined in config.yml
Your validator must then get this LocaleHolder as a constructor parameter, in order to be aware of the current locale.
services.yml
Here, declare the two services you will need, the LocaleHolder and your validator.
services:
acme.locale_holder:
class: Acme\FooBundle\LocaleHolder
arguments:
- "%locale%"
tags:
-
name: kernel.event_listener
event: kernel.request
method: onKernelRequest
acme.validator.no_badwords:
class: Acme\FooBundle\Constraints\NoBadwordsValidator
arguments:
- #acme.locale_holder
tags:
-
name: validator.constraint_validator
alias: no_badwords
Acme\FooBundle\LocaleHolder
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class LocaleHolder
{
protected $locale;
public function __construct($default = 'EN')
{
$this->setLocale($default);
}
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$this->setLocale($request->getLocale());
}
public function getLocale()
{
return $this->locale;
}
public function setLocale($locale)
{
$this->locale = $locale;
}
}
Acme\FooBundle\Constraints
use Acme\FooBundle\LocaleHolder;
class ContainsNoBadwordsValidator extends ConstraintValidator
{
protected $holder;
public function __construct(LocaleHolder $holder)
{
$this->holder = $holder;
}
protected function getBadwords($locale = null)
{
$locale = $locale ?: $this->holder->getLocale();
// ...
}
}
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);