Symfony2 execute service before controller action - symfony

So we've got SomeBundle and want execute some actions (services\another action from another bundle or something else) before SomeBundleControllerAction will be called. I read that some guys tries it from bundle class, some from event listener (but i can not get in how it works) and now question is.
How to call, proper way, (let it be) service before any of action from our SomeBundle will be called?

I don't like just posting a link, but this pretty much explains what I would do in your case. You can inject your service into the listener anyway you would like (constructor, setter).
http://symfony.com/doc/current/cookbook/event_dispatcher/before_after_filters.html#before-filters-with-the-kernel-controller-event

here was a full description of my answer (some bad person put minus =\ but didn't help at all, next time put links if you know where to find an answer) http://symfony.com/doc/current/book/internals.html#kernel-controller-event

Related

Symfony event vs service

Hi I have a question about symfony application architecture,
In my application I create different user, but when a user is created, updated, deleted, or his picture change, I need to do some action.
What is the best way to do this ? I excluded to do this on a controller action. There is 2 others solutions :
Create differents events like user.created, user.updated, ... And dispatch it on the controller action and make different listener to do the different action like MailListener (for user.created) TaskListener (for user.created) for add a task.
Use a service like UserManager and on this service have a method like userCreated() and on this method call differents actions like sendMailOnCreated, addTaskOnCreated for example.
For you what is the best method ?
For me, your first solution is the best one. It's clearly a use case for the Event component. It will be easier to maintain and more readable.
Moreover, if you need to add more listener you just need to create another one and bind it to your event. You don't need to modify your controller anymore.

How to test that EventListener has been called on event in Symfony?

What I have:
I have an EventListener that listens to PreRemove entity event in Symfony.
services:
my_bundle.entity_listener.my_listener:
class: 'MyCompany\MyBundle\MyListener'
public: false
tags:
- { name: doctrine.orm.entity_listener, entity: 'MyCompany\MyBundle\Entity\MyEntity', event: preRemove }
What I want:
I want to have a test (functional/integrational/unit or any other really) that somehow checks that when MyEntity is being removed a particular EventListener is being called.
UPDATE
I don't want to do it in a unit test, the need is to actually check that event dispatcher will really call that particular event listener to that particular event.
UPDATE 2
I thought it was obvious, but it seems that it's not - the solution should NOT modify EventListener or Event.
UPDATE 3
I specified that I do not care what the name of the test is: functional, unit or any other.
UPDATE 4
The solution must guarantee that test will pass in context of any environment. So, if someone extends my bundles and messes with my definitions I should still be able to validate if the EventHandling actually works.
Also, checking the result of handling is not an option because:
EventListener can do absolutely anything - there may be cases where I cannot simply check the result and know for sure that EventListener works.
Someone may handle an Event in almost exactly the same way, so that the "result" is the same, but the "way" is wrong.
A functional test is for testing functionality; it isn't intended to test the implementation of that functionality or the configuration of that implementation.
A test such as the one you propose will be brittle and not very useful.
What you probably want is to test the feature that the event listener implements.
check out this : Write UnitTest for Symfony EventListener
It may be of help, as i had a (sort of) similar issue/question
How about creating a compiler pass and add it to the last stage of container compilation:
$container->addCompilerPass(
new CheckEntityListenerRegistered(),
PassConfig::TYPE_AFTER_REMOVING,
-1000
);
That compiler would get executed last. You could check from that point if your listener is registered properly, and if it is, you could assume it's going to be executed by the Doctrine's Unit of Work.
I think I understand what you want. You want a integration test (to test it on all environment) without modifying the listener, the event dispatcher, etc.
Solution 1
When you work on dev, test or prod symfony load different events dispatchers it use the same interface and behaviour but it is different implementations (I haven't check doctrine one).
So you will have different dispatchers for each environment and you don't want to know what happens inside. Let's call this blackbox.
Action delete -> [ black box -> listener called ] -> listener effect
You don't want to look at the blackbox or touch it in any way? Search for the effect that has the listener on the system. Database, log file, mailer, etc.
Solution 2
If you allow me to hook into the blackbox you I will sorrounder the listener with a proxy and monitor if the listener has been called on the proxy.
Solution 3
Alternative you can use the data collectors from the symfony profiler but you won't probably have that enabled on production.
Maybe you can use the symfony profiler?
see How to Use the Profiler in a Functional Test
in the profiler events section you have two tabs with called / not called Listeners http://whatever.com/app_dev.php/_profiler/352211?panel=events

Where should be defined an action on entity

sorry because my question is dum but I prefer to ask to organize correctly my code.
Actually, in a Controller, I do an action like 'get entity + set activated + persist + send a mail'.
I know this should be placed somewhere else to be usable by others controllers.
I guess that it should be a service, but I got an hesitation, it could be in the model? but given the send mail action, I'm not sure.
I know this is something that may have been discussed in the past, I just couldn't find a clear explanation about that.
There is an official page for business logic on Symfony but not clear about that: http://symfony.com/doc/current/best_practices/business-logic.html
Thank's in advance for your help
You should create custom services and add them to the servicecontainer. This link will help you: http://symfony.com/doc/current/service_container.html#creating-configuring-services-in-the-container

Insert entity in preUpdate event

I'm trying to persist a History entity whenever a Message gets updated. I have too much going on behind the scenes to post all the code here and for it to make sense, but I've basically tracked the issue down to the UnitOfWork::commit method. There, the UOW first loops through the entityInsertions, and finding nothing, continues on to the entityUpdates. There the UOW's entityInsertions gets updated, but since it's already past that loop, it doesn't pick up that it still needs to persist some entities. Is there any way to force the UOW to "restart" this process? If so, how? I'm using Doctrine 2.4.
Thanks for any help!
This might be the dirtiest solution ever, but what I ended up doing was basically the following...
Create an onFlush event subscriber
Inject the entire container into the subscriber (seeing as injecting only the entity manager will result in a circular reference error)
Loop through the UnitOfWork's scheduledEntityUpdates and scheduledEntityInserts (I wasn't interested in deletes)
Handle each scheduled update or insert which you are interested in (in my case, I marked each entity I was interested in with a LoggableInterface, just to know which entities are loggable)
Handle the relevant object with a handler chain (This was just my own algorithm, yours may not require this. This was set up to handle logging of different LoggableInterface objects in different ways)
Persist the entity (the actual history event) via the entity manager, and do the following:
$classMeta = $this->entityManager->getClassMetadata(get_class($historyEntity));
$this->entityManager->getUnitOfWork()->computeChangeSet($classMeta, $historyEntity);
Profit
Hope this helps somebody!

SIMPLE MVC Question MVC Redirect

I have a controller that creates a news article. I want to redirect the user to the article's page, something like: "/article/1". Normally I could just throw in return View("MyAction") but I need to pass the integer along in this case. There are overloads for adding a model to the View method call but I don't see anything that will let me accomplish my goal.
What's the best way to do this?
Also, I used ViewData for my success message... if I use a redirect message it isn't going to function so is there a better way to do that too?
I think this is what you might be looking for.
RedirectToAction(new {controller="controllerName", action="article", id=1});
Hope this helps

Resources