May, 07 2020

Laravel Lessons: Database (Migrations And Eloquent Models)

In the previous lesson, we learnt about Laravel controllers, handling HTTP request and validating request data.

In this lesson, we will learn how to persist data in the database. Laravel supports lots of databases(MySQL, SQLite, PostgreSQL and SQL Server) with a very simple way to interact with them. Laravel made this possible through the Query Builders and Eloquent ORM but before that lets talk about migration.

Database Setup

Before we proceed in this lesson, we need to create a database and update our .env file with the correct database credentials. MySQL database

Laravel Migration

Migrations are files that contains class definitions for altering and updating the database table structures. The migration class contains two methods, the up() method which applies changes to the database and the down() method which reverts the changes.

The Laravel migration files are stored in the database/migrations directory and Laravel(7.x) ships with two migration files. Using the make:migration artisan command we can create a migration file.

php artisan make:migration create_posts_table

Laravel provides schema builder to expressively create and modify tables. Like this:

...
public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->timestamps();
    });
}

This will create a posts table migration file with id, created_at and updated_at fields. This $table->timestamps() is responsible for adding the created_at and updated_at fields. The above code is the default migration boilerplate generated by the artisan make:migration command. You can see all the available column types on the Laravel docs.

Finally, you can use the artisan migrate command to create the actual table in our database.

php artisan migrate

Later in this lesson I will show you a better way to create migration file. I have to do it this way in order to explain Laravel migration better.

Lets move forward!

Query Builders & Eloquent ORM

We can't talk about Eloquent Model without mentioning Query Builders and Eloquent ORM.

Query Builders: Laravel's database query builder is a convenient fluent interface (method chaining) for creating and running database queries.

Method chaining is a common syntax for invoking multiple method calls in object-oriented programming languages.

Here is an example. Using the DB facade, lets get a list all the posts in a database in descending order.

...
use Illuminate\Support\Facades\DB;
public function index()
{
   $users = DB::table('posts')->orderBy('name', 'desc')->get();
}

Eloquent ORM: Laravel Eloquent ORM is a very expressive ORM(Object-relational mapping), which allow us to work with the database objects and relationships using expressive syntax.

Eloquent Model

Model is used to insert and query data in a database table. Each database table has a model that represents it. Eloquent models Models are stored inside the app directory. Laravel also provides a make:model artisan command for creating a model class.

php artisan make:model Post

This artisan command can also generate a database migration for the User model when we add -m or --migration option.

php artisan make:model Post -m 

Here is

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //
}

Eloquent Model Properties

Let's go through some basic model properties.

Table Name: Eloquent models converts our model class name to its plural form(in snake case) as the default table name. For example if we have Post model, our model will query or insert into the posts table in the database. You can define the $table property to override it.

...
class Post extends Model
{
    protected $table = 'custom_table_name';
}

Primary Key: Eloquent model uses id field as the default primary key for a table. You can define the $primaryKey property to override it.

...
class Post extends Model
{
    protected $primaryKey = 'custom_primary_key_field';
}

Basic Database Operations With Eloquent Model

Lets take a look at some basic database operations we can do with Eloquent models.

Retrieving Records: Using the all(), get() & find() methods we can retrieve a database record. The all() method returns all records in a table while the get() method returns the result of a query with constraints.

<?php
...
  Post::all(); //returns all records
  Post::orderBy('title', 'desc')->get(); //return all records and order by title field in descending order.
  Post::find(1); //returns a single record that has id 1;

Creating & Updating Records: We can create a new record using the create() method. Before we can create or update a record we need to

Post::create([
   'title' => 'Post Title',
   'body' => 'A little post body',
]);

This is called mass-assignment and and Eloquent models prevents this by default. To override this, we have to declare fields that can be mass assigned inside the $fillable property.

$fillable = ['title']; 

We can update a record by calling the update() method on an instance of a model.

$post = Post::find(1);
$posts->update([
   'title' => 'New Post Title'
]);

Now that we have a basic understanding of migrations and the Eloquent Models, let finish up our email sending app.

LiteMailer Model & Migration

Lets start by creating model class and migration file LiteMailer email_lists table.

php artisan make:model EmailList -m

Lets add some fields to our email lists table. Head over to database/migrations and update the up() method of the new migration file like this:

...
public function up()
{
    Schema::create('email_lists', function (Blueprint $table) {
      $table->id();
      $table->string('name')->nullable();
      $table->string('email')->unique();
      $table->timestamps();
    });
}

We added two new fields, the name which we can accept a null value and the email field which is unique and cannot be set to null. Lets run the artisan migrate command.

php artisan migrate

Lets also enable mass-assignment on these two fields. Move over to your app directory and update your EmailList model like this:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;

class EmailList extends Model
{
    protected $fillable = ['email', 'name'];
}

Update: EmailController

Lets update the saveEmail() method of the EmailController that will allow use to save names and emails sent through the add email form.

public function saveEmail()
{
   $data = request()->validate([
      'name' => 'required|string|max:255',
      'email' => 'required|email:rfc|max:255|unique:email_lists,email',
   ]);

   EmailList::create($data);

   return redirect()->back()->with('message', 'Your email was added successfully');
}

We just added another validation rule unique:email_lists,email that checks if the email already exists in the email_lists table. if the validation has no error we create a new record and redirect back with a success message.

Alert Blade View

I usually create an alert blade view that checks and displays an alert message in any blade view where they are included.

Create alert.blade.php file inside a our resource/views directory.

<!-- alert.blade.php -->
@if (session('message'))
<div class="mb-4">
    <div class="bg-teal-100 border-l-4 border-teal-500 text-teal-700 p-4" role="alert">
        <p class="font-bold">Success</p>
        <p>{{ session('message') }}</p>
    </div>
</div>
@endif

Using the @if blade directive, we check and display $message session data if it is available.

Lets include the alert blade view inside our add-email.blade.php and the send-email.blade.php files immediately after the @csrfdeclaration inside the html form. Like this:

...
   @csrf
   @include('alert')
... 

Sending Bulk Email

Laravel provides a clean API around this package called Swiftmailer. This time its Swiftmailer that does all the magic around different mail drivers like

We will use mailtrap.io in order to successfully send mail in our local machine. Mailtrap.io will catch all our outgoing mails. You have to create an account on mailtrap.io and also create your own inbox. Here is how you can do it.

How to setup mailtrap.io accountHow to setup mailtrap.io account

make sure you update your .env file with your correct mailtrap.io details, I will use mine for this example.

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=dc96565a74a54f
MAIL_PASSWORD=21c930c2dcd5ec
MAIL_FROM_ADDRESS=hello@litemailer.test
MAIL_FROM_NAME=LiteMailer

Update: EmailController

Now we can use the Mail facade to send out mails. Lets update our sendEmail() method.

public function sendEmail()
{
   request()->validate([
      'subject' => 'required|string|max:255',
      'message' => 'required',
   ]);

   //data we are passing to our email blade template
   $data = [
      'title' => request('subject'),
      'body' => request('message'),
   ];
  
   // return an array of all the emails in our database
   $emails = EmailList::all('email')->pluck('email')->toArray();

   // send out email 
   Mail::send('emails.welcome', $data, function ($message) use ($emails) {
      $message->to($emails);
      $message->subject('LiteMailer Bulk Email');
   });

   return redirect()->back()->with('message', 'Your bulk email was sent successfully');
}

First we validate the incoming data, then we prepare the data we need to send to the mail. Next, we get a list of all the the emails and assign it to $emails variable. Finally we send out our mail via the send() method of the Mail facade.

The send method accepts three parameters, the first is the name of email blade view template that contains html content of our email. The second is an array of data we want to display on the email view blade view. The third is a callback function that allows set the mail subject, email address we are sending to and so on.

Email Blade Template

We need to create a blade view for our email. Head over to the resources/views directory and create a new directory emails and create a welcome.blade.php file inside it.

I used an email template builder for our welcome email content so the html is a kind of rough, you can find it on GitHub. Copy and paste it inside your resources/views/emails/welcome.blade.php file.

Now you can try sending out mails to the people on our email list.

The final lesson for this series is how to deploy your Laravel app.

Questions

You can drop your question on the comment section, send me a DM on twitter or send an email.

.

Join my inner circle newsletter

Be the first to hear about anything I publish, launch, or think is helpful for you. Subscribe here

Hey, have you tried Litehost lately ?

Litehost is a web hosting platform for PHP & Laravel developers with Composer, Git, PHP & CLI pre-installed. Try it now