symfony2 my own event - events

I made the authorization and authentication via facebook like here:
http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html
and it works
Now I want to make my own event, this event will do something when the user authenticates using facebook. For example-will redirect the user to the home page.
I did it like this
http://symfony.com/doc/current/components/event_dispatcher/introduction.html
So I have this class
http://pastebin.com/2FTndtL4
I do not know how to implement it, what am I supposed to pass as an argument to the constructor

It's really simple. Symfony 2 event system is powerful, and service tags will do the job.
Inject the dispatcher into the class where you want to fire the event. The service id is event_dispatcher;
Fire the event with $this->dispatcher->dispatch('facebook.post_auth', new FilterFacebookEvent($args)) when needed;
Make a service that implements EventSubscriberInterface, defining a static getSubscribedEvents() method. Of course you want to listen to facebook.post_auth event.
So your static method will look like:
static public function getSubscribedEvents()
{
return array(
'facebook.post_auth' => 'onPostAuthentication'
);
}
public function onPostAuthentication(FilterFacebookEvent $event)
{
// Do something, get the event args, etc
}
Finally register this service as a subscriber for the dispatcher: give it a tag (eg. facebook.event_subscriber), then make a RegisterFacebookEventsSubscribersPass (see this tutorial). You compiler pass should retrieve all tagged services and inside the loop should call:
$dispatcher = $container->getDefinition('event_dispatcher');
$subscribers = $container->findTaggedServiceIds('facebook.event_subscriber');
foreach($subscribers as $id => $attributes) {
$definition->addMethodCall('addSubscriber', array(new Reference($id)));
}
This way you can quick make a subscriber (for logging, for example) simply tagging your service.

Event object is just some kind of state/data storage. It keeps data that can be useful for dispatching some kind of events via Subscribers and/or Listeners. So, for example, if you wanna pass facebook id to your Listener(s) - Event is the right way of storing it. Also event is the return value of dispatcher. If you want to return some data from your Listener/Subscriber - you can also store it in Event object.

Related

How to create custom event for updating Query state?

I am trying to create a custom event for Query to reload and refresh the query state when the event happens.
I need a custom event similar to Spartacus' OrderPlacedEvent. My custom event actually works, but the time when
HTTP call for reloading query state is triggered is not right. Instead of firing an HTTP call when I visit the quotes page,
it happens immediately when the event is dispatched on the second step during the checkout process.
Creating event class QuotePlacedEvent:
export abstract class QuoteEvent extends CxEvent {
userId?: string;
activeCartId?: string;
}
export class QuotePlacedEvent extends QuoteEvent {
static readonly type = 'QuotePlacedEvent';
quote: any;
}
Dispatching the event during the checkout process when a quote is created for example on the second step:
this.eventService.dispatch(
{
userId: payload.userId,
activeCartId: payload.cartId,
quote: cart,
},
QuotePlacedEvent);
Quote query called when Quotes page is visited:
protected quotesQuery: Query<any> = this.query.create(() =>
this.userIdService
.getUserId()
.pipe(switchMap(userId => this.quoteConnector.getQuotes(userId))),
{
reloadOn: [LanguageSetEvent, QuotePlacedEvent],
resetOn: [LogoutEvent, LoginEvent],
}
);
getQuotesAndApplication(): Observable<any> {
return this.quotesQuery.get();
}
I saw method in ProfileTagPushEventsService orderConfirmationPageVisited() which listens to OrderPlacedEvent. Do I need that implementation too:
/**
* Listens to QuotePlacedEvent events
*
* #returns observable emitting events that describe order confirmation page visits in a profiltag compliant way
* #see QuotePlacedEvent
* #see QuoteConfirmationPushEvent
*/
quoteConfirmationPageVisited(): Observable<ProfileTagPushEvent> {
return this.eventService
.get(QuotePlacedEvent)
.pipe(map(item => new QuoteConfirmationPushEvent(item)));
}
I wanted to add my custom event by calling the method addPushEvent from ProfileTagPushEventsService, but I can't import it, since it is not exported.
Any idea what am I missing and why the custom event doesn't behave in an expected way?
The query is always "listening" for the events you tell it to listen to, and if you fire the event in the 2nd checkout step, query will react to it. This is by design.
If you need the query to react to an event which happens when you visit the quotes page, you can try to create the QuotesPageEvent, make the query listen to it, and dispatch it once the user actually navigates to the quotes page. You can see an example of a page event here.
Maybe one improvement you can do, is to make sure the that quotes have been placed before dispatching the page event. For this, you can use the power of rxjs to listen to your QuotePlacedEvent and the page visited event, and fire a final event. The quire should be listening to this final event.

Yii2 session event before close/destroy

I want to run some code every time before user session is being destroyed for any reason. I haven't found any events binded to session in official documentation. Has anyone found a workaround about this?
There are no events out of the box for Session component.
You can solve this problem with overriding core yii\web\Session component.
1) Override yii\web\Session component:
<?php
namespace app\components;
use yii\web\Session as BaseSession
class Session extends BaseSession
{
/**
* Event name for close event
*/
const EVENT_CLOSE = 'close';
/**
* #inheritdoc
*/
public function close()
{
$this->trigger(self::EVENT_CLOSE); // Triggering our custom event first;
parent::close(); // Calling parent implementation
}
}
2) Apply your custom component to application config:
'session' => [
'class' => 'app\components\Session' // Passing our custom component instead of core one
],
3) Attach handler with one of available methods:
use app\components\Session;
use yii\base\Event;
Event::on(Session::className(), Session::EVENT_OPEN, function ($event) {
// Insert your event processing code here
});
Alternatively you can specify handler as method of some class, check official docs.
As an alternative to this approach, take a look at this extension. I personally didn't test it. The Yii way to do it I think will be overriding with adding and triggering custom events as I described above.

ZF2: Attach event to another Controller's Action and get Service Locator

I am new to Zend Framework 2. I have two modules 'A' and 'B'. I trigger an event in LoginController's LoginAction of "A" module. I want to attach LoginController's LoginAction or LoginController's testMe() method.
In "A" module's LoginController's LoginAction, I have written
$this->getEventManager()->trigger('checkme.post', null, array('user_id' => $userData->usydstudentid));
In Module.php of "B" module, in on Bootstrap method, I have given
$loginController = new B\Controller\LoginController();
$sharedEventManager->attach('A\Controller\LoginController', 'checkme.post', array($loginController, 'LoginAction'), 100);
In LoginController's LoginAction of "B" module, I can access data but I can not access service manager in order to get module' config. When I try to use
$this->getServiceLocator()->get('Config');
I get error
Call to a member function get() on a non-object
In other words, I want to trigger an event from one controller's method and attach to another controller's method. After listening, getting data from that event, I want to get module's config. Please help in this regard.
First of all, you shouldn't use events and controllers this way. Your controller from B isn't a controller, but you should put that one rather in a service layer.
Then, the service locator must be injected. If you do $controller = new SomeController this service locator is not injected. Thus, fetching any object from it will fail. What you should do is using the controller loader to get the controller.
So instead of this:
$loginController = new B\Controller\LoginController();
$sharedEventManager->attach('A\Controller\LoginController',
'checkme.post',
array($loginController, 'LoginAction'),
100);
You should write this:
// $sl is instance of Service Locator
// E.g. $sl = $e->getApplication()->getServiceManager();
// Where $e is the event from the onBootstrap() method
$loader = $sl->get('ControllerLoader');
$loginController = $loader->get('B\Controller\LoginController');
$sharedEventManager->attach('A\Controller\LoginController',
'checkme.post',
array($loginController, 'LoginAction'),
100);
But as said, triggering an action in a controller this way with events isn't realy a good way to do it. You better dispatch it with for example the controller plugin Forward or (as I said it before), remove the logic from the controller's LoginAction and locate it in a service class or something.

Modifying User entity when registering using FOS User Bundle and Symfony2

As many people know, the FOS User Bundle doesn't provide roles automatically when a user registers. The most common solution is to either a) modify the User entity constructor to automatically assign a role, or b) override the entire registration controller.
Neither of these solutions seems perfect, and I want to make use of the Events that the FOS user bundle provides.
I have managed to capture the event I want (FOSUserEvents::REGISTRATION_INITIALIZE), but I am having trouble figuring out how to pass the modified User entity back to the registration form.
The code I have so far is as follows:
namespace HCLabs\UserBundle\EventListener;
use FOS\UserBundle\FOSUserEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\Model\UserInterface;
class AutoRoleAssignmentListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [ FOSUserEvents::REGISTRATION_INITIALIZE => 'onRegistrationInitialise' ];
}
public function onRegistrationInitialise( UserEvent $event )
{
$user = $event->getUser();
$user->addRole( 'ROLE_USER' );
// what do
}
}
The YML for the event listener:
services:
hc_labs_user.reg_init:
class: HCLabs\UserBundle\EventListener\AutoRoleAssignmentListener
tags:
- { name: kernel.event_subscriber }
If more code is needed I'm happy to provide it. Thanks for your help.
Answer is very simple - you have to do nothing to get updated User object in registration form after updated User in event listener for FOSUserEvents::REGISTRATION_INITIALIZE event.
Let me explain. FOSUserEvents::REGISTRATION_INITIALIZE is dispatched in RegistrationController by:
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, new UserEvent($user, $request));
And, before this dispatch in code (https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Controller/RegistrationController.php#L43) new User is created:
$user = $userManager->createUser();
$user->setEnabled(true);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, new UserEvent($user, $request));
During dispatching, by default PHP call_user_func (http://php.net/manual/en/function.call-user-func.php ) is called with pasted event name (function in defined object) and Event object. After that, event listener has possibility to modify pasted Event object - particularly event property.
In your case, your event listener modify User property via:
$user = $event->getUser();
$user->addRole( 'ROLE_USER' );
So in fact, you have to do nothing to pass the modified User entity back to the registration form.

Observe customer account verification event in Magento

Is there a way to catch the event when the customer verifies it's account? I need this feature to enable user's access to other integrated subsystem
Since confirmAction() doesnt seem to fire any events in
/app/code/core/Mage/Customer/controllers/AccountController.php
You could do either
Overriding Frontend Core Controllers to create you own event using Mage::dispatchEvent() or add code directly to confirmAction in AccountController.php
Use #Pavel Novitsky answer but you may need to check that you are on the confirm account controller or check for the changing of email verification flag, because this event will trigger every time a customer information is change/updated
eg
public function myObserver(Varien_Event_Observer $observer)
{
if(Mage::app()->getRequest()->getControllerName() == '....account_confirm'){
$customer = $observer->getCustomer();
....
}
}
Every model has standard load_before, load_after, save_before, save_after, etc. events. Look at the Mage_Core_Model_Abstract to get the list of all predefined events.
For customers you can use customer_save_after event. In observer check original data vs new data:
public function myObserver(Varien_Event_Observer $observer)
{
$customer = $observer->getCustomer();
$orig_active_flag = $custoner->getOrigData('is_active');
$new_active_flag = $customer->getData('is_active');
// do something here …
return $this;
}
Even you can create your own event after customer vefication using below code.
Mage::dispatchEvent('Yuor_Unique_Event_Name', array());
Now using this event you can do anything you want.

Resources