Symfony2: Time-based Controller Action - php

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

Argument 1 passed to Doctrine\Common\EventManager::addEventSubscriber()

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

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.

Redirect to Another Symfony Route from FilterControllerEvent Listener

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.

Constraint relative to Locale parameter in Symfony2

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();
// ...
}
}

How to create custom event in symfony2

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

Categories