DEV Community

Cover image for Mastering Laravel Eloquent ORM - The Eloquent Journey (PART 1)
Samfield Hawb for XenoX

Posted on • Edited on

Mastering Laravel Eloquent ORM - The Eloquent Journey (PART 1)

Laravel is a web application framework with an expressive, elegant syntax, and also currently the most popular PHP framework ever existed.

Eloquent ORM is inclusion in Laravel which enables developers to interact with the database of their applications. I know many people may ask “why should I use ORM when I know my SQL QUERIES?”. I will say that it’s possible to know your SQL queries but I bet you that you may only be limited to one or two databases, but laravel eloquent has support for many underlying database types. You just need to write your eloquent command and allow laravel eloquent to initiate the queries.

Let me show you what I'm talking about, I'm assuming you have your laravel project set up already, with the correct database type in config/database.php of your project. Right out of the box, laravel is configured to use MySQL so we will stick to that for this post.

'default' => env('DB_CONNECTION', 'mysql')
Enter fullscreen mode Exit fullscreen mode

and in your connection array

'mysql' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
Enter fullscreen mode Exit fullscreen mode

Let us say we want to create a blogging platform and we expect to have the following tables (entities) in our database:

  1. Users
  2. Posts
  3. Comments
  4. Replies

The Laravel framework out of the box provides us with the User Model and the create_users_table migration file which exist under the database/migrations folder of our project (migrations are the PHP files which laravel will use to create our database structure). The User Model here represents an entity in the users’ table of our project. Let’s have a look at what the User model which exist in the app/ folder looks like

//User.php


<?php

namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}
Enter fullscreen mode Exit fullscreen mode

Looking at the User model we see that the User model extends the User class in Illuminate\Foundation\Auth\User imported as Authenticatable, this class behind the extends the Model class and implements lots of interfaces.

//Illuminate\Foundation\Auth\User.php

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}
Enter fullscreen mode Exit fullscreen mode

But our focus will be our Model class which is the brain of our Eloquent ORM.

Alt Text

All models representing our database entities must extend the Illuminate\Database\Eloquent\Model, which is used by eloquent to create communication between our application and the database. Let's run the following command to create a Post model and migration;

$ php artisan make:model Post -m
Model created successfully.
Created Migration: 2020_01_07_015353_create_posts_table

Enter fullscreen mode Exit fullscreen mode

The -m directive here instruct laravel to create our migration file alongside creating for our Post model. Let’s take a look at our generated Post model existing in our App namespace.
//Post.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    //
}
Enter fullscreen mode Exit fullscreen mode

Notice that our Post model is extending the Illuminate\Database\Eloquent\Model class, which provide the Post model with the superpowers of Eloquent ORM

Protected $table

If your table name is different from what you have as your model name (let’s say you had an existing database with tables which you want to bind to your laravel project ), you can set up the $table property of the Model class specifying the table name;

protected $table = 'app_posts'; // replace users with your custom table name
Enter fullscreen mode Exit fullscreen mode

one thing to note is that models are singular form for your plural table names, for example, User Model is applicable to users table.

Protected $primaryKey

Also eloquent takes your primary key to be id, but you can as well override this to a custom column name by setting the protected $primaryKey value to your primary key column name.

 protected $primaryKey = 'post_id'; // custom column to use as primary key
Enter fullscreen mode Exit fullscreen mode

NOTE: We will discuss more on customizing of models in subsequent articles

Let’s run our migrations so that laravel will generate our tables for us with the following command

$ php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Let’s create a user for our database, take a look at the create_user_table provided for us in database/migrations, inside our up method of the CreateUserClass with extends the Illuminate\Database\Migrations\Migration class (we will discuss on this class), the columns created for our users’ table can be seen there. On the terminal of your project root, type the following

save() method

We are going to use the interactive shell provided for us by laravel framework,run the following command;

$ php artisan tinker
Enter fullscreen mode Exit fullscreen mode

we are going to use this shell to create a new user,

>>> $user = new \App\User;
>>> $user->name = “Samfield Hawb”;
>>> $user->email = “samfield4sure@gmail.com”;
>>> $user->password = bcrypt(“secret”);
>>> $user->save(); //eloquent save() method
>>> exit
$ Exit:  Goodbye
Enter fullscreen mode Exit fullscreen mode

Under the hood of the save() method, eloquent performs the SQL insert command for us, saving us the stress of thinking on how we can insert the values correctly.

create() method

The above code snippet can also be achieved with the static create() method of the model class, which accepts a keys/values pair array, with the keys representing the table column names.

$user = \App\User::create([
    'name' => 'Samfield Hawb',
    'email' => 'samfield4sure@gmail.com',
    'password' => bcrypt('secret')//create an encrypted password
]);
Enter fullscreen mode Exit fullscreen mode

Once the create method is executed, our user gets created with the $user containing the created user and a generated id property.

Protected $fillable

The command creates a new user in the database too. In other for the create method to work for us, we will need to include the column fields here in our protected $fillable property of our model, we are doing this because Eloquent by default protects all it models against mass assignment vulnerability.
According to Laravel documentation,

A mass-assignment vulnerability occurs when a user passes an unexpected HTTP parameter through a request, and that parameter changes a column in your database you did not expect. For example, a malicious user might send an is_admin parameter through an HTTP request, which is then passed into your model's create method, allowing the user to escalate themselves to an administrator.

So adding the fields in our $fillable array, we instruct Eloquent to allow for the mass assignment of the fields.

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

Enter fullscreen mode Exit fullscreen mode

Protected $guarded

The reverse for the fillable property is protected $gaurded, which can be used to specify the fields we cannot allow for mass assignment

    /**
     * The attributes that are not mass assignable.
     *
     * @var array
     */
    protected $gaurded = [
        'password',
    ];

Enter fullscreen mode Exit fullscreen mode

all() method

With our user model now, let’s say we want to retrieve all our users from the database by

$users = App\User::all(); 
Enter fullscreen mode Exit fullscreen mode

Calling the starting method all() which eloquent provides for us, return a collection of all the users in our database

Under the hood, laravel is executing the MySQL command (since we are using MySQL database)

SELECT * from users
Enter fullscreen mode Exit fullscreen mode

With the collection return, we can easily perform actions with our data. Let print out the names of all the users returned (that will be only if you have data on the users’ table), Let print out the names of all the users from our database now.

foreach ($users as $user)
{
    echo $user->name;
}
//Samfield Hawb
Enter fullscreen mode Exit fullscreen mode

find() method

Laravel Eloquent provides us with the find() method which can be used to get an instance of a model record or records. When the find method is passed in a primary key, it returns a single record matching the primary key, if no record its found, eloquent returns a null.

 $user = App\User::find(1);
Enter fullscreen mode Exit fullscreen mode

Here we instruct Eloquent to retrieve the user with the primary key 1

SELECT * FROM users WHERE id=1
Enter fullscreen mode Exit fullscreen mode

An array of primary keys can also be passed to the find() method of our model,

$users = App\User::find([1,2,3]); 
Enter fullscreen mode Exit fullscreen mode

When this is done the underlying Eloquent fetches and return a collection of records for the primary keys passed to it,

findOrFail() method

In most situations, we may want to throw an error when no model is found for a primary key. This can be achieved using the findOrFail() method on our model

 $user = App\User::findOrFail(1);
Enter fullscreen mode Exit fullscreen mode

When a model is not found, an Illuminate\Database\Eloquent\ModelNotFoundException will be thrown. If the exception is not handled, a 404 HTTP response is automatically sent back to the user which is the Laravel way of handling the ModelNotFoundExeption error.

Conclusion

So far you have seen basically how eloquent is making queries simple. Watch out for my next article, as we continue our journey to see Eloquent ORM superpowers in action.

Top comments (6)

Collapse
 
juangiordana profile image
Juan Francisco Giordana

Thanks for this post, it's a very good explanation for diving into the Eloquent ORM.

I encourage you to re-read it to correct some spelling and grammar details that may confuse new developers trying to learn it.

Collapse
 
montyhollings profile image
Monty Hollings

Thanks for this, I sat down and read this yesterday (sunday).
Got to work this morning and allready am opening this up in another tab for reference.

Collapse
 
psalmfill profile image
Samfield Hawb

You are welcome. I'm so please to hear it's a great guide to you. And a big encouragement to me to continue.

Collapse
 
fininhors profile image
Francisco Junior

Good job Man.

Collapse
 
yassne profile image
yasu uo

thank you for the good explanation

Collapse
 
umoren profile image
Samuel Umoren

Awesome read