Creating a Simple Contacts List with Laravel and PostgreSQL

Posted 2019-02-21  in Developer Relations,Community
blog header

In this post, we will build a simple Laravel app that displays a contacts list on a page. Using Eloquent and PostgreSQL's JSON object support, the app will query the database for the contacts and their details. This is what the result will look like:

By doing this, you will learn how to connect Laravel to a DigitalOcean Managed PostgreSQL database cluster, initialize the database with random data using Laravel factories and seeders, and store and read JSON documents in PostgreSQL using Laravel Eloquent.

Requirements

This post assumes that you have a working PHP development environment. You will need:

Step 1: Create a Base Laravel App

Let's start by creating a new blank Laravel app that will serve as a base for our web app. In a directory of your liking, generate a new project using Composer:

```[php]{`

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

`}```

If you browse into the newly-created `laravel-contacts` directory and run Laravel's built-in web server, you will see the default Laravel welcome page:

```[php]{`

cd laravel-contacts

php artisan serve

`}```

Let's think about what our app will need. We want to have a list of contacts, so the database will store them. This means that we will need a ```[php]{`Contact`}``` model and a migration for the ```[php]{`contacts`}``` table. We'll also want to initialize the database with some random contacts so we have something to see, which will require a ```[php]{`Contact`}``` Factory and Seeder.

Let's build them out step by step:

Step 2: Create the Contact Model

As shown in the screenshot above, a contact will have the following properties:

  • Name
  • Phone Number
  • Address
  • Favorite Colors

For the favorite colors property, we will make use of Postgres's JSON data type. We will create a generic "favorites" column that will contain a JSON object with a list of favorite things. In this post we will store favorite colors only, but using a generic “favorites” object allows us to add different types in the future.

Generate a model, factory, and migration using ```[php]{`artisan`}```:

```[php]{`

php artisan make:model -f -m Contact

`}```

Now we'll configure the different parts of the model.

Migration

Edit the generated migration file stored in ```[php]{`database/migrations/*_create_contacts_table.php`}```. Inside the ```[php]{`Schema::create()`}``` block, we will define the structure of the table:

```[php]{`

<?php

use Illuminate\Support\Facades\Schema;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Database\Migrations\Migration;

class CreateContactsTable extends Migration

{

/**

* Run the migrations.

*

* @return void

*/

public function up()

{

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

$table->increments('id');

$table->string('name');

$table->string('phone');

$table->string('address');

$table->jsonb('favorites')->default('{}');

$table->timestamps();

});

}

/**

* Reverse the migrations.

*

* @return void

*/

public function down()

{

Schema::dropIfExists('contacts');

}

}

`}```

This will configure the database column as described above with the `favorites` column set to a JSON object. The default value is an empty object.

Random Contact Generation

The contact factory generates random values for a contact. We will configure a seeder that will use the factory to insert 10 random contacts to the database. This will provide us with an option to seed the database with random contacts when running the migration. Let's start with the factory.

Factory

Edit the generated factory file stored in ```[php]{`database/factories/ContactFactory.php`}```. First, we will generate three random colors to use as favorites:

```[php]{`

$colors = collect(range(1, 3))->map(function() use ($faker) {

return $faker->colorName;

})->toArray();

`}```

We will use these colors along with other data generated using the Faker library to return the contact's properties:

```[php]{`

return [

'name' => $faker->name,

'phone' => $faker->e164PhoneNumber,

'address' => $faker->address,

'favorites' => ['colors' => $colors],

];

`}```

The resulting factory should look like this:

```[php]{`

<?php

use Faker\Generator as Faker;

$factory->define(App\Contact::class, function (Faker $faker) {

// generate 3 random colors

$colors = collect(range(1, 3))->map(function() use ($faker) {

return $faker->colorName;

})->toArray();

return [

'name' => $faker->name,

'phone' => $faker->e164PhoneNumber,

'address' => $faker->address,

'favorites' => ['colors' => $colors],

];

});

`}```

Seeder

Now we need to define a seeder that will be run upon migrating the database. Start by generating the file:

```[php]{`php artisan make:seeder ContactsTableSeeder`}```

Open the generated file ```[php]{`database/seeds/ContactsTableSeeder.php`}``` in an editor and call the factory inside the ```[php]{`run()`}``` function like so:

```[php]{`

<?php

use Illuminate\Database\Seeder;

class ContactsTableSeeder extends Seeder

{

/**

* Run the database seeds.

*

* @return void

*/

public function run()

{

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

}

}

`}```

To enable the seeder, edit `database/seeds/DatabaseSeeder.php` and call it inside the `run()` function:

```[php]{`

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder

{

/**

* Seed the application's database.

*

* @return void

*/

public function run()

{

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

}

}

`}```

Model

There is one final adjustment that we need to make to the model. The ```[php]{`artisan make:model`}``` command generated a model file for us, located in ```[php]{`app/Contact.php`}```. The `favorites` column represents a JSON object, so we need to cast it to a PHP array before using it. Eloquent makes this very easy by automatically casting back and forth between the correct formats. Inside the ```[php]{`Contact`}``` class in ```[php]{`app/Contact.php`}```, we can add the cast:

```[php]{`

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Contact extends Model

{

protected $casts = [

'favorites' => 'array',

];

}

`}```

Step 3: Configure the Database

We will use DigitalOcean Databases for our PostgreSQL cluster. If you haven’t yet, create a new one—it only takes a few minutes. If you prefer a text post, see the product documentation for Databases. If you prefer a video, click here.

In the cluster’s Overview page in the control panel, get its connection details as “Connection parameters”. Open Laravel's ```[php]{`.env`}``` file and set ```[php]{`DB_CONNECTION=pgsql`}```. Below it, set all the other variables according to your connection credentials.

There is one setting that isn’t available as an environment variable: ```[php]{`sslmode`}```. DigitalOcean Databases do not support non-TLS connections so we need to set ```[php]{`sslmode`}``` to ```[php]{`require`}```. Open ```[php]{`config/database.php`}``` in an editor, scroll down to the ```[php]{`pgsql`}``` definition, and update the setting like so:

```[php]{`

'pgsql' => [

...

'sslmode' => 'require',

],

`}```

[Related: Check out our Resource Center for resources and guides on Managed Databases]

Step 4: Migrate and seed

Now that we have completed defining everything database-related in our app, from the Contact model to the database connection info, we can execute the migration and seed the database:

```[php]{`

php artisan migrate --seed

`}```

We have a database filled with contacts now—nice!

Step 4: Build the Contact List Page

Ok, let's finish up by creating a page to show our contacts.

To keep things simple we will replace Laravel's default home page. Edit `routes/web.php` and set the `/` route to the following:

```[php]{`

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

$contacts = App\Contact::all();

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

});

`}```

This will fetch all the contacts from the database and pass them to the ```[php]{`welcome`}``` view.

Then, edit the view located in `resources/views/welcome.blade.php` and replace its contents with the following:

```[php]{`

<!doctype html>

<html>

<head>

<meta charset="utf-8">

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

<title>Contacts</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">Contacts</h1>

@foreach($contacts as $contact)

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

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

<div class="pl2">

<p class="mb2">{{ $contact->phone }}</p>

<p class="pre mb3">{{ $contact->address }}</p>

<p class="mb2"><span class="fw5">Favorite colors:</span> {{ implode(', ', $contact->favorites['colors']) }}</p>

</div>

</div>

@endforeach

</div>

</body>

</html>

`}```

Step 5: Deploy

We're all done! Let's go ahead and try out our app.

Like before, we can use Laravel's built-in web server. Simply run ```[php]{`php artisan serve`}``` and browse to http://127.0.0.1:8000.

Deploy on a Droplet

To deploy the app on a Droplet, follow the How To Deploy a Laravel Application with Nginx on Ubuntu 16.04 guide on the DigitalOcean community.

Conclusion

In this post, we went through building a simple contacts list step by step and explored a few concepts such as seeding the database with sample random data, using JSON-type database fields, and connecting to a managed PostgreSQL Database.

Here are a few things you can do following this post, building on the app we created:

  • Add a favorite shape (square, circle, etc.) to one or more contacts and edit the view template to display it. Update the seeder to include a random shape at random, or for every contact.
  • Extract the route handler (in ```[php]{`web.php`}```) into its own controller. Use ```[php]{`artisan make:controller`}``` to create the controller file. Consult the Laravel documentation on controllers for more details.
  • List the contacts in the order that they were last updated, most recent first.

[Hungry for another tutorial? Try Kamal's guide to "Deploying a Fully-automated Git-based Static Website in Under 5 Minutes"]

Kamal Nasser is a Developer Advocate at DigitalOcean. He is also a Computer Science student with a passion for software engineering and avocados. You can find him on Twitter @kamaln7.