One-to-many relationship in Laravel 9

In this article we’ll learn how to define models / tables in Laravel 9 with one-to-many relationship, one of the most common relationships between tables in a database. Then we’ll seed some data into these related tables and check the relationship functions.

Laravel 9.x requires a minimum PHP version of 8.0. This tutorial assumes that you are using Linux, macOS or WSL on Windows and Node.js, Composer and PHP 8 along with required modules i.e., bcmatch, sqlite, mbstring, xml, zip, gd, mcrypt are properly installed. Also make sure that SQLite is installed as we’ll be using SQLite to keep things simple and quick; you may use MySQL or PostgreSQL as you like, however make sure the corresponding PHP module is installed too.

Using composer, enter following command in terminal to install Laravel 9;

composer create-project laravel/laravel app 9.*

Now go inside newly created app folder by executing;

cd app

If you have VS Code installed and want to use it as your code editor, you may enter following command to open this project in VS Code;

code .

Next, we’ll setup database and Laravel environment file. Here, we’re configuring SQLite database for simplicity purposes. So, execute following command inside parent folder (app) to create new SQLite database file;

touch database/database.sqlite

Then find .env config file in the parent folder, open it and amend DB_CONNECTION line as follows;

DB_CONNECTION = sqlite

Remove DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD from .env since we’re using SQLite database.

Now, enter the following command to create Customer model along with its migration:

php artisan make:model Customer -m

Open newly created migration file from database/migrations/ which is named as (date_stamp)_create_customers_table.php and then insert the desired table fields;

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email');
            $table->string('phone');
            $table->text('address');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('customers');
    }
};

Next, create another model Invoice along with its migration by executing following command;

php artisan make:model Invoice -m

Open newly created migration file from database/migrations/ which is named as (date_stamp)_create_invoices_table.php and then insert the desired table fields;

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::create('invoices', function (Blueprint $table) {
            $table->id();
            $table->foreignId('customer_id')->constrained('customers')->onDelete('cascade');
            $table->string('invoice_number');
            $table->date('invoice_date');
            $table->double('amount',15,2);
            $table->text('description');
            $table->timestamps();
        });
    }
    public function down()
    {
        Schema::dropIfExists('invoices');
    }
};

In the above migration, we’re using foriegnId field type in order to establish referential integrity with the id column in customers table.

Now, enter following command in parent folder in order to migrate the above migrations;

php artisan migrate

Next, open app/Models/Customer.php model file and change it as follows;

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Customer extends Model
{
    use HasFactory;

    protected $fillable = [
        'name', 'email', 'phone', 'address'
    ];
    
    public function invoices()
    {
        return $this->hasMany(Invoice::class);
    }
}

In the above model, we’ve defined invoices() function which embodies hasMany() relationship with Invoice model. In simpler words, a customer can have many invoices. Practically speaking, by calling invoices() function on a customer object, we can get all invoices of the customer.

Then, open app/Models/Invoice.php model file and change it as follows;

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model
{
    use HasFactory;

    protected $fillable = [
        'customer_id', 'invoice_number', 'invoice_date', 'amount', 'description'
    ];
        
    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }
}

In the above model, we’ve defined customer() function which embodies belongsTo() relationship with Customer model. In simpler words, an invoice belongs to a particular customer. Practically speaking, by calling customer() function on an invoice object, we get customer object of the invoice.

Now, let’s enter some data in order to test one-to-many relationship we just defined between Customer and Invoice models. Here, we’ll take data seeding route to keep things formal, so enter following command in order to create Customer data seeder;

php artisan make:seeder CustomerSeeder

Then open database/seeders/CustomerSeeder.php and enter following code:

<?php
 
namespace Database\Seeders;
 
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
 
class CustomerSeeder extends Seeder
{
    public function run()
    {
        DB::table('customers')->insert(['name' => 'ABC Supplies', 'email' => 'abc@email.com', 'phone' => '1234567', 'address' => 'ABC Plaza, Z Street.']);
        DB::table('customers')->insert(['name' => 'LMP Inc', 'email' => 'lmp@email.com', 'phone' => '5677865', 'address' => 'LIMP Tower, C Street.']);
        DB::table('customers')->insert(['name' => 'ZP LLC', 'email' => 'zp@email.com', 'phone' => '9876543', 'address' => 'Zip Town, K Street.']);
    }
}

Next, enter following command to create Invoice data seeder;

php artisan make:seeder InvoiceSeeder

Then open database/seeders/InvoiceSeeder.php and enter following code:

<?php
 
namespace Database\Seeders;
 
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
 
class InvoiceSeeder extends Seeder
{
    public function run()
    {
        DB::table('invoices')->insert(['customer_id' => 1, 'invoice_number' => 'INV001', 'invoice_date' => '2023-01-01', 'amount' => 23000, 'description' => 'For providing tax services for the month of December 2022']);
        DB::table('invoices')->insert(['customer_id' => 1, 'invoice_number' => 'INV002', 'invoice_date' => '2023-01-05', 'amount' => 15000, 'description' => 'For providing corporate services for the month of December 2022']);
        DB::table('invoices')->insert(['customer_id' => 2, 'invoice_number' => 'INV003', 'invoice_date' => '2023-01-05', 'amount' => 18500, 'description' => 'For providing accounting services for the month of December 2022']);
        DB::table('invoices')->insert(['customer_id' => 3, 'invoice_number' => 'INV004', 'invoice_date' => '2023-02-03', 'amount' => 17450, 'description' => 'For providing corporate services for the month of January 2023']);
        DB::table('invoices')->insert(['customer_id' => 3, 'invoice_number' => 'INV005', 'invoice_date' => '2023-02-04', 'amount' => 21500, 'description' => 'For providing tax services for the month of January 2023']);
    }
}

Finally, open database/seeders/DatabaseSeeder.php and amend it as follows;

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call([
            CustomerSeeder::class,
            InvoiceSeeder::class,
        ]);
    }
}

To populate customers and invoices tables with the respective records, execute the following command;

php artisan db:seed

Having database populated, let’s play with the one-to-many relationship by using functions (invoices() and customer()) we defined in the models as above. So start tinker shell by executing following command;

php artisan tinker

Enter following command in tinker shell to list down invoices of customer 1;

Customer::find(1)->invoices;

Now, enter following command in order to get the total amount of all invoices of customer 1;

Customer::find(1)->invoices->sum('amount');

Similarly, enter following command to know the name of customer of invoice 4;

Invoice::find(4)->customer->name;

Type exit and press Enter to quit the Tinker shell. In next few articles, we’ll utilize these models and their relationship, so you’d better bookmark this tutorial.

4 thoughts on “One-to-many relationship in Laravel 9”

Leave a Comment