Laravel - Turn part of a function into a queued statement

1.1k views Asked by At

I want to queue part of a function within my controller, mainly because it accesses a 3rd party API and calculates certain information from said request. I also want to do this to increase my knowledge of queues!

The code which I want queueing is:

The only variables that will need pushing with this if statement is $postcode and $clinic ID (which is figured out above the statement).

if($clinic->postcode != $postcode)
    {

     $client = new Client([ 'base_uri' => 'https://api.postcodes.io/','timeout' => 2.0, 'verify' => false ]);
     $response = $client->get('postcodes/'.$postcode)->getBody();

     $input = json_decode($response);

     $clinic->latitude   = $input->result->latitude;
     $clinic->longitude  = $input->result->longitude;
     $clinic->save();
}

So far I have created the queue table and migrated it.

I then ran the command: php artisan make:job GetClinicLatAndLongPoints --queued

My question is, how can I put this function inside the GetClinicLatAndLongPoints including passing the two variables over to do so?

I have so far:

public function handle(Clinic $clinic, $postcode)
    {

    }

But I'm unsure how to lay things out! Any guidance would be hugely appreciated.

1

There are 1 answers

2
peterm On BEST ANSWER

You can pass an instance of your Clinic model and the postal code to the constructor of your job, which may look along the lines of

namespace App\Jobs;

use App\Clinic;
use App\Jobs\Job;
use GuzzleHttp\Client;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;

class GetClinicLatAndLongPoints extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    private $clinic;
    private $postcode;

    public function __construct(Clinic $clinic, $postcode)
    {
        $this->clinic = $clinic; // Laravel will automatically deserialize the model instance
        $this->postcode = $postcode;
    }

    public function handle()
    {
        $coordinates = $this->getCoordinates($this->postcode);

        if (! is_null($coordinates)) {
            // You may want to add error handling
            $this->clinic->latitude   = $coordinates['latitude'];
            $this->clinic->longitude  = $coordinates['longitude'];
            $this->clinic->save();
        }
    }

    private function getCoordinates($postcode)
    {
        $client = new Client(['base_uri' => 'https://api.postcodes.io/','timeout' => 2.0, 'verify' => false]);
        $response = json_decode($client->get('postcodes/'.$postcode)->getBody()->getContents());
        if (! $response || json_last_error() !== JSON_ERROR_NONE) {
            return null;
        }
        if ($response->status == 200 &&
            isset($response->result->latitude) &&
            isset($response->result->longitude)) {
            return [
                'latitude' => $response->result->latitude,
                'longitude' => $response->result->longitude
            ];
        }
        return null;
    }
}

In your controller you dispatch your job

if ($clinic->postcode != $postcode) {
    $this->dispatch(new GetClinicLatAndLongPoints($clinic, $postcode));
}

On a side note: although Laravel comes with the database queue driver using it in production is not a very good idea. Better make use of one of the job queues i.e. beanstalkd.