May, 07 2020
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.
Before we proceed in this lesson, we need to create a database and update our .env
file with the correct database credentials. MySQL database
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!
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.
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
{
//
}
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';
}
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.
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'];
}
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.
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 @csrf
declaration inside the html form. Like this:
...
@csrf
@include('alert')
...
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 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
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.
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.
You can drop your question on the comment section, send me a DM on twitter or send an email.
.
Be the first to hear about anything I publish, launch, or think is helpful for you. Subscribe here
Litehost is a web hosting platform for PHP & Laravel developers with Composer, Git, PHP & CLI pre-installed. Try it now