Monday 13 December 2021

 Integrate YugabyteDB with Laravel/Lumen



Yugabyte provides YSQL layer that is the same as PostgreSQL. This article covers how to use PostgreSQL together with the PHP framework Laravel/Lumen to deploy web applications. After walking through the Laravel installation process it shows how to get started and create tables.


 

Prerequisites

As of the time of this writing, the latest available version of Laravel is 6.0 LTS, and can be used with any supported version of PostgreSQL. In reality, Laravel can be used with any of several database engines because of the underlying Eloquent ORM. This article will focus on how to set it up with Postgres, because why would you use anything else? Here’s what you’ll need:

  • PHP 7.2+

  • Composer (a dependency manager for PHP)

  • PostgreSQL 9.5+

Installation of these components is falls outside the scope of this article, but if you need help, you can check out instructions on how to install PHP 7.3 (RHEL/CentOS, Ubuntu) and PostgreSQL (RHEL/CentOS, Ubuntu).

 

Installing Laravel

To install Laravel, simply use Composer to create a new project:

composer create-project --prefer-dist laravel/laravel myproject

 

Getting the plumbing in place

PHP and Laravel both need to know how to talk to PostgreSQL, so the first step is to make sure that the PostgreSQL drivers for PHP are installed. That means you need to have php-pgsql installed. For Linux users, this can be done with “apt-get install php-pgsql” or “yum install php-pgsql” (you may need to customize these commands based on your distribution and/or version of PHP).

Then, edit your “.env” file in the project folder and update the database information accordingly (the values included here are defaults—please adjust to match your configuration):

 

# cat myproject/.env | grep DB

DB_CONNECTION=pgsql

DB_HOST=<your_database_IP_address>

DB_PORT=5432

DB_DATABASE=postgres

DB_USERNAME=postgres

DB_PASSWORD=postgres

 

In some instances, you may need to link “pgsql.so” to “/usr/lib64/php/modules” and also create a corresponding “/etc/php.d/pdo_pgsql.ini”—it really depends on how your PHP was set up.

Finally, test to see if you can communicate with your PostgreSQL database via Laravel:

# cd myproject

# php artisan migrate:install

Migration table created successfully.


Installing the default schema

Laravel comes with a basic user/password schema for testing and tinkering. To load it, simply call it:


# php artisan migrate:fresh

Dropped all tables successfully.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (0.01 seconds)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (0.01 seconds)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (0.01 seconds)

[root@pga laravel-contacts]# php artisan migrate:status

+------+------------------------------------------------+-------+



| Ran? | Migration | Batch |



+------+------------------------------------------------+-------+



| Yes | 2014_10_12_000000_create_users_table | 1 |



| Yes | 2014_10_12_100000_create_password_resets_table | 1 |



| Yes | 2019_08_19_000000_create_failed_jobs_table | 1 |



+------+------------------------------------------------+-------+



 

You can verify that the tables were created by connecting to your PostgreSQL database with “psql”:

postgres=# \d

List of relations

Schema | Name | Type | Owner


--------+--------------------+----------+----------

public | failed_jobs | table | postgres

public | failed_jobs_id_seq | sequence | postgres

public | migrations | table | postgres

public | migrations_id_seq | sequence | postgres

public | password_resets | table | postgres

public | users | table | postgres

public | users_id_seq | sequence | postgres

(7 rows)

Adding test data

Laravel comes with a nice facility to generate test data for its default schema. To generate users in the default schema, first uncomment the UsersTableSeeder reference in “myproject/database/seeds/DatabaseSeeder.php”:

<?php


use Illuminate\Database\Seeder;


class DatabaseSeeder extends Seeder {

/**
* Seed the application's database.
*
* @return void
*/


public function run() {


$this->call(UsersTableSeeder::class);


}


}

 

Then, create a “UsersTableSeeder” class:

# php artisan make:seeder UsersTableSeeder 


Update the newly-generated “myproject/database/seeds/UsersTableSeeder.php” so that the `run()` function looks like this:

public function run()
{
factory(App\User::class, 10)->create();
}

 

Finally, seed the database:

# php artisan db:seed
Seeding: UsersTableSeeder
Seeded: UsersTableSeeder (0.05 seconds)
Database seeding completed successfully.

 

You can now look in the tables to see that data was generated:

postgres=# \x

Expanded display is on.

postgres=# SELECT * FROM users LIMIT 1;

-[ RECORD 1 ]-----+-------------------------------------------------------------

id | 1

name | Miss Yvonne Kunze

email | hschuster@example.org

email_verified_at | 2019-12-03 01:30:57

password | $2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

remember_token | boCKVi9ydO

created_at | 2019-12-03 01:30:57

updated_at | 2019-12-03 01:30:57

 

Showing data in the browser

What’s the point of using Laravel if you can’t make a web page with it? Now that the data has been generated, you can display it in your browser. First, make sure the route exists:

# myproject/routes/web.php
Route::get('/', function () {
return view('welcome', ['users' => App\User::all()]);
});

 

Next, replace the default welcome Blade with a simple listing of all users:

# cat resources/views/welcome.blade.php

<!doctype html>

<html>

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Users</title>

<link rel="stylesheet"
href="https://unpkg.com/tachyons@4.10.0/css/tachyons.min.css"/>

</head>

<body>

<div class="mw6 center pa3 sans-serif">

<h1 class="mb4">Users</h1>

@foreach($users as $user)

<div class="pa2 mb3 striped--near-white">

<header class="b mb2">{{ $user->name }}</header>

<div class="pl2">

<p class="mb2">id: {{ $user->id }}</p>

<p class="mb2">email: {{ $user->email }}</p>

<p class="mb2">details: {{ $user->remember_token }}</p>

</div>

</div>

@endforeach

</div>

</body>

</html>

 

This code pulls all the users out of the database and prints each one out to the screen.  From within the “myproject” directory, call “php artisan serve” and point your browser to http://127.0.0.1:8000. 

Note: If you are using a virtualisation engine like Docker or Vagrant, you may need to add “--host=0.0.0.0” and a custom port number (“--port=5000” in the screenshot above) in order to route traffic to your VM properly.

 

Creating new tables

To expand the schema, you simply need to create a migration and fill in the blanks.  For example, to create a Cars table, first create a migration:

# cd myproject

# php artisan make:model -f -m Cars 

Then, edit the “myproject/database/migrations/*_create_cars_table.php” and fill in “Schema::create”:


# cat database/migrations/2019_12_03_083214_create_cars_table.php

Schema::create('cars', function (Blueprint $table) {

$table->bigIncrements('id');

$table->string('make');

$table->string('model');

$table->integer('year');

$table->timestamps();

});


To autogenerate Car information, edit the factory:

# cat database/factories/CarsFactory.php

<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Cars;
use Faker\Generator as Faker;

$factory->define(Cars::class, function (Faker $faker) {

return [

'make' => $faker->company,

'model' => $faker->word,

'year' => $faker->randomNumber,

];

});

 

Then, create the seeder and edit it:

# php artisan make:seeder CarsTableSeeder

Seeder created successfully.

# cat database/seeds/CarsTableSeeder.php

<?php

use Illuminate\Database\Seeder;

class CarsTableSeeder extends Seeder {

/**
* Run the database seeds.
*
* @return void
*/

public function run() {

factory(App\Cars::class, 10)->create();

}

}

 

Run the migration and seed the table:

# php artisan migrate --seed

Migrating: 2019_12_03_083214_create_cars_table

Migrated: 2019_12_03_083214_create_cars_table (0.01 seconds)

Seeding: UsersTableSeeder

Seeded: UsersTableSeeder (0.06 seconds)

Seeding: CarsTableSeeder

Seeded: CarsTableSeeder (0.01 seconds)

Database seeding completed successfully.

 

Add a route:

# tail -n 6 routes/web.php

Route::get('/', function () {

return view('welcome', ['users' => App\User::all()]);

});

Route::get('/cars', function () {

$cars = DB::table('cars')

->join('users', 'users.id', 'cars.id')

->select('users.name', 'users.email', 'cars.*')

->get();

return view('cars', ['cars' => $cars]);

});

 

Create a template:

# cat resources/views/cars.blade.php

<!doctype html>

<html>

<head>

<meta charset="utf-8">

<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Cars</title>

<link rel="stylesheet" href="https://unpkg.com/tachyons@4.10.0/css/tachyons.min.css"/>

</head>

<body>

<div class="mw6 center pa3 sans-serif">

<h1 class="mb4">Cars</h1>

@foreach($cars as $car)

<div class="pa2 mb3 striped--near-white">

<header class="b mb2">{{ $car->make }}</header>

<div class="pl2">

<p class="mb2">model: {{ $car->model }}</p>

<p class="mb2">year: {{ $car->year }}</p>

<p class="mb2">owner: {{ $car->name }}</p>

<p class="mb2">email: {{ $car->email }}</p>

</div>

</div>

@endforeach

</div>

</body>

</html>

 

Serve it up with “php artisan serve” and point your browser to http://127.0.0.1:8000/cars: 

That’s all there is to it!  Note that creating seeders is not entirely necessary, but can be very useful for demonstrating proof-of-concept and for testing. In the real world, you should define ways for Laravel to insert/update data in the database.

Notice also that when displaying the “Cars” information, we didn’t access the “Cars” class (i.e., in “routes/web.php”, we didn’t call “App/Cars” like we called “App/User”), but used the DB object to join with the “users” table. Laravel allows database access both by using the Query Builder and by the Eloquent ORM. Depending on the design of your app, you may wish to tightly join the Cars and Users tables by defining a One-to-One or One-To-Many relationship in Eloquent.  This will not be covered here, but instructions are readily available in the Laravel documentation.