Book Image

Laravel 5 Essentials

By : Martin Bean
Book Image

Laravel 5 Essentials

By: Martin Bean

Overview of this book

Table of Contents (15 chapters)
Laravel 5 Essentials
Credits
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Don't wait any longer with queues


Queues allow you to defer the execution of functions without blocking the script. They can be used to run all sorts of functions, from e-mailing a large number of users to generating PDF reports.

Laravel 5 is compatible with the following queue drivers:

  • Beanstalkd, with the pda/pheanstalk package

  • Amazon SQS, with the aws/aws-sdk-php package

  • IronMQ, with the iron-io/iron_mq package

Each queue system has its advantages. Beanstalkd can be installed on your own server; Amazon SQS might be more cost-effective and require less maintenance, as will IronMQ, which is also cloud-based. The latter also lets you set up push queues, which are great if you cannot run background jobs on your server.

Creating a command and pushing it onto the queue

Jobs come in the form of commands. Commands can be either self-handling or not. In the latter case, a corresponding handler class would take the data from the command class and then act upon it.

Command classes reside in the app/Commands directory, and command handler classes can be found in the app/Handlers/Commands directory. Classes for a command and its handler can be generated with an Artisan command as follows:

$ php artisan make:command CommandName --handler --queued

The --handler option tells Artisan to create a handler class (omitting this option would create a self-handling command class only), and the --queued option designates that this should be added to the queue, instead of being handled synchronously.

You can then use the Queue façade to add the command to the queue:

Queue::push(new SendConfirmationEmail($order));

Alternatively, you can dispatch commands using the command bus. The command bus is set up by default in controllers using the DispatchesCommands trait. This means in your controller actions you could use the dispatch method:

public function purchase(Product $product)
{
  // Create order
  $this->dispatch(new SendConfirmationEmail($order));
}

Commands are simple classes that contain the data needed to execute an action—the handler then performs the actual processing at a later stage using the data provided by the command. An example may be sending a confirmation e-mail after an order is placed. The command for this will look like the following:

<?php namespace App\Commands;

use App\Order;
use Illuminate\Contracts\Queue\ShouldBeQueued; 
use Illuminate\Queue\InteractsBeQueued;
use Illuminate\Queue\SerializesModels; 

class SendConfirmationEmail extends Command implements ShouldBeQueued {

  use InteractsWithQueue, SerializesModels;

  public $order;

  public function __construct(Order $order) {
    $this->order = $order;
  }
}

The handler—when executed by the queue—will then perform the actual sending of the e-mail, passing the order to the e-mail template to display the details of the customer's purchase as follows:

<?php namespace App\Handlers\Commands;

use App\Commands\SendConfirmationEmail;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\InteractsWithQueue;

class SendConfirmationEmailHandler {

  public function __construct(Mailer $mail) {
    $this->mail = $mail;
  }

  public function handle(SendConfirmationEmail $command) {
    $order = $command->order;
    $data = compact('order');
    $this->mail->send('emails.order.confirmation', $data, function($message) use ($order) {
      $message->subject('Your order confirmation');
      $message->to(
        $order->customer->email,
        $order->customer->name
      );
    });
  }
}

As command handlers are resolved via the service container, we can type-hint dependencies. In the preceding case, we need the mailer service, so we type-hint the contract to get an implementation. We can then use the mailer to send an e-mail to the customer using the order data received from the command class.

Note

The app/Commands directory will be renamed app/Jobs from Laravel 5.1 to indicate it is primarily for queued jobs.

Listening to a queue and executing jobs

The following are the functions used for listening to a queue and executing jobs:

  • We can listen to the default queue as follows:

    $ php artisan queue:listen
  • We can specify the connection on which to listen as follows:

    $ php artisan queue:listen connection
  • We can specify multiple connections in the order of their priority as follows:

    $ php artisan queue:listen important,not-so-important

The queue:listen command has to run in the background in order to process the jobs as they arrive from the queue. To make sure that it runs permanently, you have to use a process control system such as forever (https://github.com/nodejitsu/forever) or supervisor (http://supervisord.org/).

Getting notified when a job fails

To get notified when a job fails, we use the following functions and commands:

  • The following event listener is used for finding the failed jobs:

    Queue::failing(function($job, $data) {
      // Send email notification
    });
  • Any of the failed jobs can be stored in a database table and viewed with the following commands:

    $ php artisan queue:failed-table // Create the table 
    $ php artisan queue:failed // View the failed jobs

Queues without background processes

Push queues do not require a background process but they only work with the iron.io driver. Push queues will call an endpoint in your application when a job is received, rather than to a queue that is handled by a constantly-running worker process. This is handy if you do not have the ability to define the processes, which run on your application's server (such as is the case on shared hosting packages). After signing up for an account on iron.io and adding your credentials to app/config/queue.php, you use them by defining a POST route that receives all the incoming jobs. This route calls Queue::marshal(), which is the method responsible for firing the correct job handler:

Route::post('queue/receive', function() {
  return Queue::marshal();
});

This route then needs to be registered as a subscriber with the queue:subscribe command:

$ php artisan queue:subscribe queue_name http://yourapp.example.com/queue/receive

Once the URL is subscribed on http://iron.io/, any newly created jobs with Queue::push() will be sent from Iron back to your application via a POST request.