Registering service provider:
public function register()
{
$this->app->singleton(CartInterface::class, function ($app) {
return new SessionCart($app['session'], $app['events']);
});
}
Firing events within the service above:
$this->events->fire('cart.added', $item);
Testing the service:
public function it_can_add_an_item()
{
Event::fake();
$this->cartService->add(new Item);
$this->assertEquals(1, $this->cartService->count());
Event::assertDispatched('cart.added');
}
Result:
The expected [cart.added] event was not dispatched.
If instead of using $this->events to fire events I just use the event helper like event('cart.added') I'm back to green.
I'm not dying for using the object oriented approach, but I'm really curious about the reason it doesn't work here, because the event helper seems to be using an instance of the dispatcher right from the container just like I do when registering the service.
Any clue?
This is what happens when your test is executed:
The laravel application is bootstrapped; it binds the non-fake event dispatcher to the service container
You bind the CartInterface to the service containing and pass the currently binded event dispatcher (the non-fake one) as a parameter
After the application has been bootstrapped, you swap the event dispatcher with the fake one, however, your CartInterface has already been resolved (since its a singleton) and does not know that the event dispatcher has been swapped
Therefore, the CartInterface still uses the non-fake event dispatcher and your tests fail if you try to make any event assertions. However, if you use the Event facade inside your CartInterface, the event dispatcher will be resolved when you are actually using it, and this is after the dispatcher has been swapped with the fake one. So in this case, you actually get the event fake you want and your tests pass.
Related
There seem to be several questions on how to register events to a gpt service:
Google Publisher Tag registering to Events
registering to events with google publisher tag
How to do this is clearly defined in the documentation:
googletag.pubads().addEventListener('eventName', callbackFn);
I add my event to the service when the component (React) mounts inside the callback function of window.googletag.cmd.push as described in this tutorial by Google.
Now the problem is that every time I change page, more event listeners are added to the service. I can make sure only one event listener executes on the actually existing slots by using this method (from the documentation):
googletag.pubads().addEventListener('impressionViewable', function(event) {
if (event.slot == targetSlot) { // will only run on target slot
// Slot specific logic.
}
});
But more an more event listeners will remain active and keep on executing (without executing the code within the if-statement).
Now, I assumed google would have implemented something like this (to run on componentWillUnmount):
googletag.pubads().removeEventListener('eventName', callbackFn);
But it doesn't exist in the documentation and I can't seem to find any way to remove active event listeners from the service?
So I went with this:
let eventListnerCreated = false;
if(!eventListnerCreated) {
eventListnerCreated = googletag.pubads().addEventListener("slotRenderEnded", function(event) {
// blablabla
});
}
Not clean. But will work.
I know this doesn't solve the original issue of removing the event listener, but this will let's not create event listeners again and again.
I am using the array cache driver while testing, however I want to disable the Cache Events.
I can do this with
$this->withoutEvents();
I'd rather just stop the one event, however
$this->expectsEvents(Illuminate\Cache\Events\KeyForgotten::class);
will throw an error if the event is not called.
One solution would be a function that on the outside allows an event to fire and hides it but doesn't throw an error if the event doesn't occur.
I think I need to mock the Events Dispatcher like so
$mock = Mockery::mock('Illuminate\Contracts\Events\Dispatcher');
$mock->shouldReceive('fire')->andReturnUsing(function ($called) {
$this->firedEvents[] = $called;
});
$this->app->instance('events', $mock);
return $this;
The question would be how to carry on dispatching the non caught events?
I'm trying to use Laravel IoC by creating a singleton object. I'm following the pattern from tutorial as below. I have put a Log message into object (Foobar in this example) constructor and I can see that object is being created every time I refresh page in browser. How is the singleton pattern meant for Laravels IoC? I understood that its shared object for entire application but its obviously being created every time its requested by App:make(...) Can someone explain please. I thought I would use the singleton pattern for maintaining shared MongoDB connection.
App::singleton('foo', function()
{
return new FooBar;
});
What has been said in Laravel Doc
Sometimes, you may wish to bind something into the container that
should only be resolved once, and the same instance should be returned
on subsequent calls into the container:
This is how you can bind a singleton object and you did it right
App::singleton('foo', function()
{
return new FooBar;
});
But, the problem is, you are thinking about the whole process of the request and response in the wrong way. You mentioned that,
I can see that object is being created every time I refresh page in
browser.
Well, this is normal behaviour of HTTP request because every time you are refreshing the page means every time you are sending a new request and every time the application is booting up and processing the request you've sent and finally, once the application sends the response in your browser, it's job is finished, nothing is kept (session, cookie are persistent and different in this case) in the server.
Now, it has been said that the same instance should be returned on subsequent calls, in this case, the subsequent calls mean that, if you call App::make(...) several times on the same request, in the single life cycle of the application then it won't make new instances every time. For example, if you call twice, something like this
App::before(function($request)
{
App::singleton('myApp', function(){ ... });
});
In the same request, in your controller, you call at first
class HomeController {
public function showWelcome()
{
App::make('myApp'); // new instance will be returned
// ...
}
}
And again you call it in after filter second time
App::after(function($request, $response)
{
App::make('myApp'); // Application will check for an instance and if found, it'll be returned
});
In this case, both calls happened in the same request and because of being a singleton, the container makes only one instance at the first call and keeps the instance to use it later and returns the same instance on subsequent calls.
It is meant to be used multiple times throughout the applications instance. Each time you refresh the page, it's a new instance of the application.
Check this out for more info and practical usage: http://codehappy.daylerees.com/ioc-container
It's written for L3, but the same applies for L4.
In this PlunkerDemo, I'm trying to broadcast an event from the parent controller to child controller. However doing it directly in the parent controller won't work. The handler doesn't register the event. However doing it based on an ng-click or based on setTimeout, it works. Is it due to the scope life cycle?
http://beta.plnkr.co/edit/ZU0XNK?p=preview
See the comments of the accepted answer. They explain my problem.
Any changes to angular scope must happen within the angular framework, If any changes have to be made outside the framework we have to use the .$apply function.
$apply() is used to execute an expression in angular from outside of
the angular framework.
In your case you are triggering the $broadcast within setTimeout, where the callback gets called outside the angular framework.
So you have two solutions, either use the $timeout service provided by angular or use .$apply function.
I prefer to use the $timeout function.
var ParentCtrl = function($scope, $rootScope, $timeout){
$scope.broadcast = function(){
$rootScope.$broadcast('Sup', 'Here is a parameter');
};
$timeout(function(){
$scope.$broadcast('Sup');
}, 1000);
//this one does not work! Most likely due to scope life cycle
$scope.$broadcast('Sup');
$scope.$on('SupAgain', function(){
console.log('SupAgain got handled!');
});
};
Demo: Fiddle
Using $apply
setTimeout(function(){
$scope.$apply(function(){
$scope.$broadcast('Sup');
});
}, 1000);
A more reliable option can be to use $interval in child controller. So, instead of having significant timeout, there will be polling every small interval.
Also, instead of broadcast, use a service with a flag. Every poll will check if flag is set. When the flag is set by parent controller, the timer will be stopped during next poll. And that can indicate the event happened. The parent controller can also share data with child controller, via service.
If I have a class that listens to event emitters, is it wrong practice to bind on every instance?
function MyClass() {
emitter.on('ready', function() {
// do something
});
}
myclass = new MyClass();
If I call emitter.on() multiple times, it warns me.
(node) warning: possible EventEmitter memory leak detected. 11
listeners added. Use emitter.setMaxListeners() to increase limit.
Are event emitters meant to be bound only once per module, outside of class instances?
If this is wrong, then how do I access the class instance when events are triggered?
Thanks
The warning is that your attaching 11 event listeneres to the ready event on a single event emitter.
Generally when you listen to the same event multiple times on a single event emitter, it's likely that's a bug. For example say you have an http event emitter, if your listening on the request event 11 times that's probably a bug, you only want to listen and handle request once.
This is a debugging tool. You can get around this by doing
emitter.setMaxListeners(500); // or whatever you think is a sensible limit