Skip to content
Advertisement

how to pass parameters to listener in laravel?

I registered LogConnectionFailed like this:

protected $listen = [
    Registered::class => [
        SendEmailVerificationNotification::class,
    ],
    'IlluminateHttpClientEventsConnectionFailed' => [
        'AppListenersLogConnectionFailed',
    ],
];

The ConnectionFailed event is fired if no response is received for a given request.

my class {

  public function send() {

    $response = Http::get('http://example.com');

  }

}

I need to The name of the class and the method in which this happened and duration time call http client in LogConnectionFailed class.

Advertisement

Answer

This is not possible through normal parameter passing, so I utilized PHP native function debug_backtrace() and hacked through it.

The logic is that when the listener wants to handle the event, we get the callback trace and filter through the call stack frames until we find one of our watching location.

The code is this:

use IlluminateSupportStr;
use IlluminateHttpClientEventsConnectionFailed;

class LogConnectionFailed
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    public function handle(ConnectionFailed $event)
    {
        $backtraceCollection = Collect(debug_backtrace());
        $callerClass = $backtraceCollection->first(function($value, $key) use ($event){
            $class = $value['class'] ?? '';

            return $this->classIsWatched($class);
        });

        if ($callerClass) {
            // Store in DB or do some other stuff.
            dd([
                'class'    => $callerClass['class'],
                'function' => $callerClass['function'],
                'line'     => $callerClass['line'],
            ]);
        } else {
            dd("should skip. Not Watching classes.");
        }
    }

    private function classIsWatched(string $className): bool
    {
        return Str::is(
            ['AppHttpControllers*', 'AppMyClass'],
            $className
        );
    }
}

Here take note at the array inside the function classIsWatched:

['AppHttpControllers*', 'AppMyClass']

These are the classes or directories we will watch, which means if the ConnectionFailed due to some calls from these classes, they will be captured, else they will be skipped. This gives you the flexibility to just filter out and watch certain locations inside your application.

Note that we can also use wildcards * for simplifying the path inclusions. For example AppHttpControllersApiEventController is watched too.

For example if I have this class inside the App path:

namespace App;

use IlluminateSupportFacadesHttp;

class MyClass
{
    public static function callEvent()
    {
        $response = Http::get('http://example.com');
    }
}

due to any reason if a ConnectionFailed event dispatches, the output of handle method will be:

array:3 [▼
  "class" => "AppMyClass"
  "function" => "callEvent"
  "line" => 11
]

this will give you the class name, function name and even the line which event was raised there. You can simply replace the dd() inside the handle method of the listener and do what you want to do with the data.

About the Http Call duration, no accurate solution comes to my mind, but you can have a rough estimation using this approach:

dd(microtime(true) - LARAVEL_START);

add the above code inside the handle method too, and this gives you the time difference from the moment that the application started and till you got this point (Http request failed and you got inside this listener).

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement