Posted on Leave a comment

Writing A Real Time Location Service – Models and Migrations

[callaction url=”https://www.youtube.com/user/JPlaya01″ background_color=”#333333″ text_color=”#ffffff” button_text=”Go Now” button_background_color=”#e64429″]Subscribe To My Youtube Page[/callaction]

Overview

In this programming series I am going to show you how to create a real time Laravel app that shows the location of an android device on a Google map in real time. This design can easily be applied to iOS and I will cover it at a later date. This project will be constructed of three parts:

  • Laravel app that handles registration/login, saves coordinates and timestamps
  • Node Application that talks to Laravel application and android devices
  • Android application that talks to node application

In this post I will create the Laravel + Node apps and I will write the Android app at a later post. The Laravel app is a run down version of my new application SocketDroid, an application that allows you to control android devices from a web panel. click a button and alert the Android device to send geolocation information back to the server and push it to the browser. The application will store the geolocation information in a database for later analysis if you so choose (in a later post I will expand upon the admin panel). The Laravel app will communicate with the Node app via Redis using the built-in Event system. From there the Node app will communicate with our devices via Socket.io. The Android device will listen on a websocket connection in a background service and listen for an event to start grabbing and posting GPS data, and another event to stop listening. Make sense so far? Good, let’s get started!
 

Scaffolding The Laravel Application

If you have followed any of my Laravel tutorials in the past, you know the drill, create a new application, and scaffold the authentication routes and views:


laravel new real-time-gps
cd real-time-gps
php artisan make:auth

Now we have a basic Laravel application with registration and login logic established. Let’s talk about database design for a moment shall we? This application is going to have 3 really important tables they are:

  • Users (Already made for us be default)
  • Devices
  • Locations
  • ActivationCodes

A user can have many devices, a device can have many locations and belongs to one user, and a location belong to one device, that is the basic relationship structure. Activation codes are for you guessed it activating devices to use the app. Go ahead and create the relations and models for devices and locations using the following commands:


php artisan make:model -m Device
php artisan make:model -m Location
php artisan make:model -m ActivationCode

Device Model

Open up the devices migration file and add the following content to the up() function:


Schema::create('devices', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});

The only things we need to know about devices are who they belong to and what channel they are listening on. We also want to make sure that when a user account is deleted from the database, that all of their devices are also removed from the database.  Now open up the Device model (app/Device.php), there are three things we need to do with this model, the first is tell it which parameters to accept when inserting into the database. The second thing is to tell the model about its relation to the User model, while the third is to tell the model about it’s relation to the Location model. The finished version should look like this:


<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Device extends Model
{
//
protected $guarded = [];
public function user(){
return $this->belongsTo('App\User');
}
public function locations(){
return $this->hasMany('App\Location');
}
}

The Device model and migration is now complete, now on to the Location model and migration.

Location Model

Open up the location migration file and in its up() function we are going to add the following:


Schema::create('locations', function (Blueprint $table) {
$table->increments('id');
$table->string('lat');
$table->string('long');
$table->integer('device_id')->unsigned();
$table->foreign('device_id')->references('id')->on('devices')->onDelete('cascade');
$table->timestamps();
});

Hopefully by now you understand what is going on, we are saving the lat/long acquired from the device, as well as its id. Using this information we can associate geolocations with independent devices. Next we will open up the Location(app/Location.php) model, tell it which properties to fill, and it’s relation to the Device model.


<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
//
public $guarded = [];
public function device(){
return $this->belongsTo('App\Device');
}
}

User Model

The only thing we need to do the user model is make it aware of it’s new device relation open up the User(app/User.php) model and add the following function:


public function devices(){
return $this->hasMany('App\Device');
}

ActivationCode Model

The activation code model is responsible for storing the activation code given from the Android device on app installation to register the device with your account. It will take in the UUID of the device and the activation code, open up the migration file and add the following:


public function up()
{
Schema::create('activation_codes', function (Blueprint $table) {
$table->increments('id');
$table->string('uuid');
$table->string('code');
$table->timestamps();
});
}

Now open up the ActivationCode(app/ActivationCode.php) model and add the following:


<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class AuthCode extends Model
{
//
public $guarded = [];
}

That’s all that’s needed you can now run your migrations!


php artisan migrate

In the next lesson we will be creating the views and front end logic needed to visualize the devices on a Google map!

Posted on Leave a comment

Sending Twilio Notifications With Laravel 5.3

[callaction url=”https://www.youtube.com/user/JPlaya01″ background_color=”#333333″ text_color=”#ffffff” button_text=”Go Now” button_background_color=”#e64429″]Subscribe To My Youtube Page[/callaction]

Sending Twilio Notifications With Laravel 5.3

One of the greatest features added to Laravel 5.3 IMHO was the introduction of notifications. Notifications allow you to send messages to users over a variety of channels including mail, sms, and slack. You also have the option of storing them in the database. “THIS IS GREAT” I thought as I was reading up on it and contemplating how I was going to refactor my existing hoemebrew Twilio notification systems. There was just one problem. The Laravel notification system’s default SMS driver is for Nexmo, not Twilio! Luckily I found a solution, and I am going to share it with you today

The Application

The application I am going to walk you through writing a simple Laravel 5.3 app that signs users up and sends them daily inspirational quotes. The order of which the application will be written is thus:

  • Create App/Install dependencies
  • Prepare database/Registration
  • Create notification
  • Modify inspire console command

While this application won’t be very exciting, it will demonstrate the groundwork needed to get Twilio up and running in your web application.

Creating App/Installing Dependencies

First off we must create the application open up your terminal and use the following command

laravel new TwilioNotifications

Once the appcation has been scaffolded cd into the new directory and add the following composer package

composer require laravel-notification-channels/twilio

This will add the Twilio dependency we need to make SMS notifications. Now we need to add the following to the providers array in config/app.php

// config/app.php
'providers' => [
    ...
    NotificationChannels\Twilio\TwilioProvider::class,
],

Next we need to update our config/services.php file and add the Twilio credentials
 

// config/services.php
...
'twilio' => [
    'account_sid' => env('TWILIO_ACCOUNT_SID'),
    'auth_token' => env('TWILIO_AUTH_TOKEN'),
    'from' => env('TWILIO_FROM'), // optional
],
...

Make sure you update you .env file to suit, other than that we are ready to go onto the database/registration logic.

Database/Registration

Open up the default database migration. We just need to add a ‘phone_number’ attribute to the migration, add the following

$table->string('phone_number');

You can safely run your migration, nothing else to be done here. Now we need to scaffold the application of authentication logic, please enter the following command in your terminal.
php artisan make:auth
This command creates the views, controllers, and routes for registering users, we just need to add some logic to accommodate for phone_number. First open up resources/views/auth/register.blade.php and underneath the email block of HTML add the following:


<div class="form-group{{ $errors->has('phone_number') ? ' has-error' : '' }}">
<label for="phone" class="col-md-4 control-label">Phone</label>
<div class="col-md-6">
<input id="phone_number" type="tel" class="form-control" name="phone_number" value="{{ old('phone_number') }}" required>
@if ($errors->has('phone_number'))
<span class="help-block">
<strong>{{ $errors->first('phone_number') }}</strong>
</span>
@endif
</div>
</div>

Next open up app/Http/Controllers/Auth/RegisterController.php in your Validator array add the following rule:

'phone_number' => 'required'

In the create method simply add the following in the User::Create array:

'phone_number' => $data['phone_number'],

You should be able to register accounts now! On to the next part, creating the notification

Creating The Notification

Laravel provides an artisan command for creating notifications. Go to the terminal and enter the following

php artisan make:notification InspireUser

This will create a Notifications folder under app/, go there and open InspireUser.php file
In the constructor we are going to be passing in a quote string so we should grab and set it


public $quote;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($quote)
{
//
$this->quote = $quote;
}

Look at the via($notifiable) method, notice is returns an array of channels to send the message to. Since we are not using mail in this example you can safely remove that and replace it with this


public function via($notifiable)
{
return [TwilioChannel::class];
}

Be sure to add the following use clauses at the top


use NotificationChannels\Twilio\TwilioChannel;
use NotificationChannels\Twilio\TwilioSmsMessage;

For every channel you want to broadcast on you must have a corresponding method toChannel($notifiable). So for Twilio we need a toTwilio($notifiable) where $notifiable is the class that is being notified.


public function toTwilio($notifiable)
{
return (new TwilioSmsMessage())
->content("Hello {$notifiable->name} here is your inspiring quote for the day: {$this->quote}");
}

That’s all we have to do, now on to the last part, modifying the inspire console command.

Modifying The Inspire Console Command

Laravel ships with a predefined console command called inspire, it simply echos an inspiring quote to the console. It’s located in routes/console.php delete everything and replace it with this


<?php
use Illuminate\Foundation\Inspiring;
use App\User;
use App\Notifications\InspireUser;
/*
|--------------------------------------------------------------------------
| Console Routes
|--------------------------------------------------------------------------
|
| This file is where you may define all of your Closure based console
| commands. Each Closure is bound to a command instance allowing a
| simple approach to interacting with each command's IO methods.
|
*/
Artisan::command('inspire', function () {
$users = User::all();
$users->each(function($item, $key){
$this->info("Notifying {$item->name}");
$item->notify(new InspireUser(Inspiring::quote()));
});
})->describe('Send an in inspiring quote to all your users');

This version of inspire grabs all the users and sends them a text message with the inspiring quote. You can go to the terminal and type

 php artisan inspire

and all your users will be notified. That’s it in a nutshell, although I would advise putting this command on a daily schedule so you don’t have to manually go into the terminal everyday, but I will leave you to that. If you would like to see the source code, it is available here on Github.

Posted on 6 Comments

Create A Real-Time Microservice With Lumen

Laravel 6 Is Out Which Means New Lumen!

When I was at Laracon 2019 I interviewed Taylor Otwell and one of the things we talked about was new Lumen updates. I have switched to a primarily micro service mentality and I’m excited to write up scalable robust production ready microservices.

Laracon 2019 I interviewed Taylor Otwell

What Is Lumen?

Lumen is microframework provided by Laravel. I use it all the time when I need to create standalone APIs and microservices. Today I will show you how to create a generic real time microservice that can be used for later mobile back end tutorials . The microservice will take messages and push them out to all clients listening setting the ground for push notifications. Without further ado, let’s get started!

Getting Started

Because I want to focus on development, and not system administration, please follow this guide to getting your environment up and running, after doing so, go to your terminal, cd into an empty directory and type in this command or clone the repo:

lumen new real-time-microservice-skeleton

cd into your newly created app. First thing we are going to do is define our events. This microservice will give us real-time updates from those who sent messages to it. In order to provide this, we will leverage the broadcasting paradigm included in the Event class. If you are interested in a deeper understanding on how broadcasting works check here, but in short you tell the event what channel to broadcast on and you give it a driver (Redis, Pusher, log). We will being using Redis with a Node.js implementation. Before we can do any of that, we have to add a dependency or two:

For Composer:

composer require predis/predis

For NPM:

npm install --save socket.io-client

Now open up app/Providers/EventServiceProvider.php and change  the array to this:

protected $listen = [
        'App\Events\NewMessageEvent' => [
            'App\Listeners\NewMessageListener',
        ],
    ];

Event & Listener

Lumen doesn’t have generators so we have to do things manually. Now create those corresponding classes in the app/Events and app/Listeners directories respectively. In the NewMessageEvent add this code:

<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class NewMessageEvent extends Event implements ShouldBroadcast
{
public $message;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($channel, $message)
{
//
$this->message = $message;
}
public function broadcastOn()
{
return new PrivateChannel('example-channel');
}
}

In the NewMessageListener it can just have the default listener code

<?php
namespace App\Listeners;
use App\Events\NewMessageEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class NewMessageListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    /**
     * Handle the event.
     *
     * @param  NewMessageEvent  $event
     * @return void
     */
    public function handle(NewMessageEvent $event)
    {
        //
    }
}

Routing

For the lumen skeleton I will just add two addition routes to the web.php file one GET and one POST that do the same thing. Pass a message parameter to a controller method.

<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/
$router->get('/', function () use ($router) {
    return $router->app->version();
});
$router->get('/message', 'MessageController@sendMessage');
$router->post('/message', 'MessageController@sendMessage');

Controller

The controller will have one method that calls a new event and passes the message as the parameter.

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class MessageController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }
    public function sendMessage(Request $request){
      event(new \App\Events\NewMessageEvent($request->message));
    }
    //
}

Socket-IO Client

We will use Laravel Echo to interact with out redis pub/sub mechanism. Create a new file called socket-client.js and input the following

import Echo from "laravel-echo"
window.io = require('socket.io-client');
window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
});
Echo.private('example-channel')
    .listen('NewMessageEvent', (e) => {
        console.log(e.message);
    });

As you can see we are listening for a private channel with the same name that we broadcasted on in the Event class. Now the only thing needed is an actual socket.io server. I won’t get into that in this tutorial but the official Laravel documentation recommends that you use this github package. In the next step of the tutorial I will add authentication to secure channels.