Laravel One to Many Relationship

Laravel One to Many Relationship: A Beginner’s Guide

Spread the love

Last Updated on June 8, 2024

One-to-many relationships occur when one Entity in the database has an association with multiple records from another Entity. For example, if you have a Flight Model and a Ticket Model, you can say that A Flight has many tickets but each ticket belongs to a Flight.

In this article, I am going to show you how to implement a One to Many Relationship in Laravel

How do you implement a One to Many Relationship in Laravel?

To implement one to many relationships, we will need to follow these steps

1. Create a Laravel Project

The first step is to create a Laravel project if you don’t have one. You can use the Laravel new command if you have Laravel installed globally.

laravel new test

2. Create a Flight Model and Migration

The next step is to create the Flight Model and migration file. We can think of it as the Parent Model because it has to exist for a ticket to also exist.

php artisan make:model Flight -m

This will generate the model and its corresponding migration file. I will update the Model and migration files to resemble the ones below

<?php

namespace App\Models;

use App\Models\Ticket;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;

class Flight extends Model
{
    use HasFactory;
    protected $fillable = ['origin','destination','flight_number','depature','name'];

    public function tickets()
    {
        return $this->hasMany(Ticket::class,'flight_id');
    }

}

Flight Model

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('origin');
            $table->string('destination');
            $table->string('flight_number');
            $table->dateTime('depature');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('flights');
    }
};

Flight Migration File

3. Create a Ticket Model and Migration

The other model to create is the Ticket Model

php artisan make:model Ticket -m 

The -m flag creates a migration file together with your Model. Similar to the Flight’s Model, I will update the Ticket’s model and migration files

<?php

namespace App\Models;

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

class Ticket extends Model
{
    use HasFactory;

    protected $fillable = [
        'flight_id','ticket_number','passenger_name','boarding_gate','class','seat','boarding_time'
    ];

    public function flight()
    {
        return $this->belongsTo(Flight::class,'flight_id');
    }
}

Ticket’s Model

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('tickets', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('flight_id')->index();
            $table->integer('ticket_number');
            $table->string('passenger_name');
            $table->string('boarding_gate');
            $table->string('class');
            $table->string('seat');
            $table->dateTime('boarding_time');
            $table->timestamps();

            $table->foreign('flight_id')->references('id')->on('flights')->cascadeOnDelete();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('tickets');
    }
};

Ticket’s migration file

4. Define the One to Many Relationship

Now that our Models are ready, it is now time to update the Migration files and the Model. In this case we have two Models where one is the Parent Model(Flight Model) and the Child Model(Tickets Model). Laravel Eloquent helps us define the one-to-many relationship in an easy and clean way.

We can update the Flight Model by adding a hasmany() function. This illustrates to Laravel that it is the Parent Model. We can also update the Ticket Model and add belongsto() method.

In those methods, we can define the foreign keys as I find it easier and bug-free when I define them.

public function flight()
{
   return $this->belongsTo(Flight::class,'flight_id');
}

Ticket Model

public function tickets()
{
   return $this->hasMany(Ticket::class,'flight_id');
}

Flight Model

Once we have defined the relationship, we can now migrate the database.

php artisan migrate

5. Leveraging the Relationship in our Controller

Now that the relationship is defined and the database is migrated, we can now start using the power of Eloquent to interact with our Database.

We will first start by adding records to the database. We will create a controller to do so

php artisan make:controller TicketController -r 

The -r flag instructs artisan to create a resourceful controller. This basically means that our controller will have all the basic methods such as index store update and destroy that we will use to interact with the database

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TicketController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

We will first start by handling the store method. This method is responsible for adding records to the database. In our Ticket model earlier we had specified that a foreign key for the Flight’s model is required. Therefore, we need a way to include it as part of the inputs we get from a form.

  public function store(Request $request)
    {
        $data = [
            'flight_id' => $request->input('flight'), //The foreign key of the flight
            'ticket_number' => $request->input('ticket_number'), //12312421
            'passenger_name' => $request->input('name'), //John Doe
            'boarding_gate' => $request->input('boarding_gate'), //A
            'class' => $request->input('class'), //Economy
            'seat' => $request->input('seat'), //48K
            'boarding_time' => Carbon::createFromFormat('d-m-Y H:i:s', $request->input('boarding_time'))
                ->toDateTimeString()
        ];

        Ticket::create($data);

        return redirect('tickets')->with('success', 'Ticket Created Successfully');
    }

This is will be similar in the update method. We will also need to pass the flight’s foreign key as part of the input

 public function update(Request $request, $id)
    {
        $ticket = Ticket::find($id);
        $data = [
            'flight_id' => $request->has('flight') ? $request->input('flight') : $ticket->flight_id, //The foreign key of the flight
            'ticket_number' => $request->has('ticket_number') ? $request->input('ticket_number') : $ticket->ticket_number, //12312421
            'passenger_name' => $request->has('name') ? $request->input('name') : $ticket->name, //John Doe
            'boarding_gate' => $request->has('boarding_gate') ? $request->input('boarding_gate') : $ticket->boarding_gate, //A
            'class' => $request->has('class') ? $request->input('class') : $ticket->class, //Economy
            'seat' => $request->has('seat') ? $request->input('seat') : $ticket->seat, //48K
            'boarding_time' => $request->has('boarding_time')
                ? Carbon::createFromFormat('d-m-Y H:i:s', $request->input('boarding_time'))->toDateTimeString()
                : $ticket->boarding_time
        ];

        $ticket->update($data);

        return redirect('tickets')->with('success', 'Ticket Updated Successfully');
    }

In the update method, we are doing some conditional logic by checking if a request parameter such as name or boarding gate has been provided or updated. If so, we change the record otherwise we use the record in the database.

To pass the Flight to the view we can pass the data through the create and edit method that will be responsible for rendering the views.

public function create()
{
    $flights = Flight::all();
    return view('tickets.create', compact('flights'));
}


public function edit($id)
{
   $flight = Flight::find($id);
   return view('tickets.edit', compact('flight'));
}

We can then use a select input field to display the Flights available

With that, our application is almost done.

6. Create/Update Child Records from the Parent Model

We can also manipulate the child records directly from the Parent Model in Laravel. Say you want to create a new ticket for a specific flight, You can use the relationships functions we created to do so

public function store(Request $request, Flight $flight)
{
        $data = [
            'ticket_number' => $request->input('ticket_number'), //12312421
            'passenger_name' => $request->input('name'), //John Doe
            'boarding_gate' => $request->input('boarding_gate'), //A
            'class' => $request->input('class'), //Economy
            'seat' => $request->input('seat'), //48K
            'boarding_time' => Carbon::createFromFormat('d-m-Y H:i:s', $request->input('boarding_time'))
                ->toDateTimeString()
        ];

        $flight->tickets()->create($data);

        return redirect('flights')->with('success', 'Ticket Successfully Created for Flight ' . $flight->flight_number);
}

This makes it easy to update/create these records with little lines of code

7. Retrieve Records

The last step is to retrieve the records. In this part, we want to be careful not to introduce the N+1 query problem. This simply means that we don’t want our application to send multiple queries to the database for it to retrieve the records(lazy loading)

An example of an N+1 query is shown below.

$tickets = Ticket::all();

foreach($tickets as $ticket)
{
   $ticket->flight->name;
}

At face level, this looks like a good query but in the background, there are multiple queries that are being made to the database.

To fix this, we can use the with() method provided by Laravel. This will eager load the records and therefore result in fewer queries to the database and therefore increase the performance of the application

$tickets = Ticket::with('flight')->get();

foreach($tickets as $ticket)
{
   $ticket->flight->name;
}

And that’s it. We have created a One-to-Many relationship in Laravel

Conclusion

In this tutorial, you learnt how to implement one-to-many relationships in Laravel. I hope this article was helpful. I also wrote other articles on how to implement many-to-many relationships in Laravel and how to implement one-to-one relationships in Laravel. You can give it a read. If you have any questions, feel free to ask. Thank you for reading.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *