September 20, 2020
laravel v6

A guide to Laravel v6 Queue with data extraction from MySQL

Queues are amazing. Queues literally make your ‘Job’ faster. But, queues are confusing and often too much a hassle to learn. In this tutorial, I will try to make it simple enough to understand yet actual enough to be used in the real world.

This is not a laravel CRUD example. There are already plenty of CRUD tutorials available you can learn by clicking here.

Note: Just a basic setup is shown between Step 1-21; just in case you have no setup ready for laravel queue tutorial. In case you have an existing setup. Jump to Step 22

Let’s get started:-

Step 1: Make a new Laravel 6 Project. Run this command in your terminal

composer create-project  --prefer-dist  laravel/laravel laravel-techflow360
Note: This command will install laravel v6 unless your environment doesn’t have PHP version 7.2. In case PHP 7.2 is not installed an older version of laravel will be installed.

Step 2: Navigate inside the folder and check the version and download additional packages using npm (Node.js and npm is required) using the commands

cd laravel-techflow360
php artisan -V
> Laravel Framework 6.14.0
npm install
Note: This tutorial will work without npm install too. It will basically download all the frontend packages mentioned in the package.json file.

Step 3: Build a MySQL database named laravel-techflow360.Simply use phpMyAdmin to build a database using GUI.

Step 3.1: Open the entire project folder ‘laravel-techflow360‘ in your choice of text editor (I will be using Sublime).

Step 4: Enter your database credentials in the .env file

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-techflow360
DB_USERNAME=root
DB_PASSWORD=
Note: I am not using any password in localhost so password area is blank.

Step 5: Laravel needs few tables to work efficiently. Let’s migrate them now.

php artisan migrate
php artisan migrate output

MVC Framework

Ok so now that we have the basic model ready. Let us explore laravel a bit more. Laravel uses MVC (Model-View-Controller) framework. You can read about MVC framework here. Here is a quick overview.

The model manages the data, logic and the algorithm of the application.

The view is for the representation of the chart, diagram etc. Users only get to see this part.

The controller receives the input and converts it as a command for the view or the model.

> Hello Model

Step 6: Let’s create a model Student

php artisan make:model Student --migration

You will get an output like this:-

Model created successfully.
Created Migration: 2020_02_08_131311_create_students_table

Step 7: Navigate to database\migration\2020_02_08_131311_create_students_table file in your text editor and modify it like this. (Pro Tip: Use Ctrl+P to quickly search for files in Sublime). Postmodification your file will look like this:-

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateStudentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('students', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
            $table->string('name');
            $table->string('roll');
            $table->string('result');
            $table->string('mobile');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('students');
    }
}

We modified and added name, roll, result and mobile column in the schema.

Step 8: Migrate the table now

php artisan migrate

Step 9: Now open the file app\Student.php and modify it accordingly

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    protected $fillable = [
        'name',
        'roll',
        'result',
        'mobile'       
    ];
}

>Hello Controller

Step 10: Create a Controller

php artisan make:controller StudentController --resource

Note:

–resource is a clever little command that automatically creates a CRUD layout in the controller and a single command in the route file web.php creates multiple paths to the controller. Here is the initial skeleton of the controller with path app\Http\Controllers\StudentController. For simplicity of the tutorial, we will only concern ourselves with functions index(), create() and store()

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class StudentController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

Step 11: Navigate to routes\web.php and add the following line (Route::resource(‘students’, ‘StudentController’);). Your web.php file should look like this

Route::get('/', function () {
    return view('welcome');
});
Route::resource('students', 'StudentController');

Step 12: Add use App\Contact; in StudentController. It should look like

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Student;

class StudentController extends Controller
{

Step 13: Modify the Student controller index(),create(),store() function like this:-

    public function index()
    {
        $students = Student::all();

        return view('students.index', compact('students'));
    }  

    public function create()
    {
        return view('students.create');
    }
    public function store(Request $request)
    {
        $request->validate([
            'name'=>'required',
            'roll'=>'required',
            'mobile'=>'required',
            'result'=>'required'
        ]);

        $student = new Student([
            'name' => $request->get('name'),
            'roll' => $request->get('roll'),
            'mobile' => $request->get('mobile'),
            'result' => $request->get('result')
        ]);
        $student->save();
        return redirect('/students')->with('success', 'Student saved!');
    }

>Hello View

Step 14: In resources/views folder create a template.blade.php file

cd resources/views
touch template.blade.php

Step 15: Open resources/views/template.blade.php and modify it

<!DOCTYPE html>
<html lang="en">
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Techflow360 Queue Tutorial</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style>
* {
  box-sizing: border-box;
}

input[type=text], select, textarea {
  width: 100%;
  padding: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  resize: vertical;
}

label {
  padding: 12px 12px 12px 0;
  display: inline-block;
}

input[type=submit] {
  background-color: #4CAF50;
  color: white;
  padding: 12px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  float: right;
}

input[type=submit]:hover {
  background-color: #45a049;
}

.container {
  border-radius: 5px;
  background-color: #f2f2f2;
  padding: 20px;
}

.col-25 {
  float: left;
  width: 25%;
  margin-top: 6px;
}

.col-75 {
  float: left;
  width: 75%;
  margin-top: 6px;
}

/* Clear floats after the columns */
.row:after {
  content: "";
  display: table;
  clear: both;
}

/* Responsive layout - when the screen is less than 600px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
  .col-25, .col-75, input[type=submit] {
    width: 100%;
    margin-top: 0;
  }
}
</style>
</head>
<body>
  <div class="container">
    @yield('main')
  </div>

</body>
</html>

Step 16: Create a new repository named students inside resources/views

mkdir students

Step 17: Navigate inside students and create a blade file named create.blade.php

cd students
touch create.blade.php

Step 18: Open create.blade.php and enter the following code

@extends('template')

@section('main')
<div class="row">
 <div class="col-sm-8 offset-sm-2">
    <h1 class="display-3">Add a Student</h1>
  <div>
    @if ($errors->any())
      <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
              <li>{{ $error }}</li>
            @endforeach
        </ul>
      </div><br />
    @endif
      <form method="post" action="{{ route('students.store') }}">
          @csrf
          <div class="form-group" class="col-25">    
              <label for="name">Full Name:</label>
              <input type="text" class="form-control" name="name"/>
          </div>

          <div class="form-group" class="col-25">
              <label for="roll">Roll Number:</label>
              <input type="text" class="form-control" name="roll"/>
          </div>

          <div class="form-group" class="col-25">
              <label for="mobile">Mobile Number:</label>
              <input type="text" class="form-control" name="mobile"/>
          </div>
          <div class="form-group" class="col-25">
              <label for="result">Result:</label>
              <input type="text" class="form-control" name="result"/>
          </div>
          <div class="row">                      
          <input type="submit"></input>
          </div>  
      </form>
  </div>
</div>
</div>
@endsection

Step 19: Similarly create an index.blade.php file inside students folder

@extends('template')

@section('main')
<div class="row">
<div class="col-sm-12">
    <h1 class="display-3">Students</h1>
   <a class="btn btn-primary" href="{{route('students.create')}}">ADD A NEW STUDENT</a>
  <table class="table table-striped">
    <thead>
        <tr>
          <td>ID</td>
          <td>Name</td>
          <td>Roll</td>
          <td>Result</td>
          <td>Mobile</td>
        </tr>
    </thead>
    <tbody>
        @foreach($contacts as $contact)
        <tr>
            <td>{{$contact->id}}</td>
            <td>{{$contact->name}}</td>
            <td>{{$contact->roll}}</td>
            <td>{{$contact->result}}</td>
            <td>{{$contact->mobile}}</td>
        </tr>
        @endforeach
    </tbody>
  </table>
<div>
</div>
@endsection

Step 20: Start the server and run the code

php artisan serve
>Laravel development server started: http://127.0.0.1:8000

Step 21: Navigate to your URL in my case it’s 127.0.0.1:8000

http://127.0.0.1:8000/students 

>Hello JOB/QUEUE

Let us now start with our actual tutorial of laravel queue. I knowwwww!!!! Gosh! In my defence, basics are important too.

Step 22: Open .env file again and change the queue driver/connection to the database. Additionally, enter two more variables which will be used later. API Key and Sender ID are required to send SMS. It is available for FREE at www.pingsms.in. Check out my Github Repo to learn about the different features of the API.

QUEUE_CONNECTION=database
PINGSMS_API_KEY=NisD1NYRZaye0SuAmzE4wbIsKT0t0kdjjfu82923920203283djna
PINGSMS_SENDERID=PNGDMO

Step 23: We will use the database so we need a job table. Run

php artisan queue:table

Step 24: Migrate the table

php artisan migrate

Step 25: Create a new Job to send SMS. (Don’t worry you can use jobs for mail also)

php artisan make:job SendSMSJob

Step 26: Open the SendSMSJob file in located in app\Jobs

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use DB;
class SendSMSJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    public $tries = 5;
    protected $details;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($details)
    {
        $this->details = $details;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
       $students=$students=DB::select('SELECT * FROM students WHERE id=?',[$this->details]);;
       foreach($students AS $student){
        $curl = curl_init();
        $apiKey=env("PINGSMS_API_KEY"); //Enter The API Key Here
        $senderId=env("PINGSMS_SENDERID"); //Your SenderId. PNGSMS is default senderId
        $mobileNumber=$student->mobile; //10 digit phone number separated by comma (,)
        $language="1";
        $product="1";
        $message="Dear $student->name,
        Your Roll No. is $student->roll and your Result is $student->result.";

        $message=urlencode($message);// Encode the message to send it through URL

        curl_setopt_array($curl, array(
        CURLOPT_URL => "https://www.pingsms.in/api/sendsms?key=".$apiKey."&amp;sender=".$senderId."&amp;mobile=".$mobileNumber."&amp;language=".$language."&amp;product=".$product."&amp;message=".$message,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_ENCODING => "",
        CURLOPT_MAXREDIRS => 10,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
        CURLOPT_CUSTOMREQUEST => "GET",
        CURLOPT_HTTPHEADER => array("X-Authorization: ".$apiKey),
        ));

        $response = curl_exec($curl);
        $err = curl_error($curl);

        curl_close($curl);

        if ($err) {
        echo "cURL Error #:" . $err;
        } else {
        echo $response."\n";
        }

        }
    }

    
}

Step 27: Dispatch the Job in Student controller in the store function. Modified store() will look like:-

    public function store(Request $request)
    {
        $request->validate([
            'name'=>'required',
            'roll'=>'required',
            'mobile'=>'required',
            'result'=>'required'
        ]);

        $student = new Student([
            'name' => $request->get('name'),
            'roll' => $request->get('roll'),
            'mobile' => $request->get('mobile'),
            'result' => $request->get('result')
        ]);
        $student->save();
        dispatch(new \App\Jobs\SendSMSJob($student->id)); //Dispatch the JOB Here
        return redirect('/students')->with('success', 'Student saved!');
    }

Step 28: Run the Job(No Longer required in laravel v6)

php artisan queue:work

I use queue:work in production and queue:listen in local, Check my old article to know why. A better way to run the queue can be found here.

Feel free to comment below if you have additional queries.

Source code is available at https://github.com/sa1if3/laravel-techflow360/

Saifur Rahman

Saifur Rahman is a Full Stack Laravel Developer. Additionally, he has spent a significant amount of time to learn and research in the domain of the Internet of Things (IoT). He loves to share his work and contribute to helping fellow developers. Saifur also runs the following websites and services - Pingsms.in and Techmion.com

View all posts by Saifur Rahman →

Leave a Reply

Your email address will not be published. Required fields are marked *