DEV Community

Cover image for Creating a Reservation System in Laravel with Lara Reserve: A Step-by-Step Guide
shayan yousefi
shayan yousefi

Posted on

Creating a Reservation System in Laravel with Lara Reserve: A Step-by-Step Guide

Greetings, and welcome to my first post on this site!

Introduction:

In this tutorial, I will show you how to create a restaurant reservation system using Laravel and the Lara Reserve package. This package provides a range of valuable features for building reservation systems, making it an ideal choice for this project. Let's dive in!

Link to Lara Reserve Github repository: https://github.com/shayan-yousefi/lara-reserve

read that documentation for more features. I will not use all features in this article.
(🌟 give a star to it if you like that 🌟)

Let's follow below steps:

Step 1: Install Lara Reserve.

To start, we need to install the Lara Reserve package. You can do this by running the following command in your terminal:

composer require shayanys/lara-reserve
Enter fullscreen mode Exit fullscreen mode

After Lara Reserve Install, we must run the migrations to create the necessary database tables. To do this, run the following command:

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

Above command will create the Lara Reserve tables in your database, which we'll use later in the tutorial.

Stay tuned for the next step, where we'll build the reservation system!

Step 2: model and migrations

We need a model, migration, request and controller for restaurant tables. To create these files, run the following command in your terminal:

php artisan make:model ResturantTable --migration --request --controller
Enter fullscreen mode Exit fullscreen mode

Open RestaurantTable Model and implement it from the ReservableInterface interface and use the reservable trait in the Model class:

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use ShayanYS\LaraReserve\Interfaces\ReservableInterface;
use ShayanYS\LaraReserve\Traits\Reservable;

class RestaurantTable extends Model implements ReservableInterface
{

    protected $fillable = ['table_number','capacity'];

    use HasFactory, reservable;
}

Enter fullscreen mode Exit fullscreen mode

After doing these works now, we go for migration, so open the RestaurantTable migration file and do this:

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('restaurant_tables', function (Blueprint $table) {
            $table->id();
            $table->smallInteger('table_number')->unique();
            $table->tinyInteger('capacity');
            $table->timestamps();
        });
    }

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

Enter fullscreen mode Exit fullscreen mode

I used 'table_number' to identify what table is under reserve in the restaurant and the 'capacity' to specify the count of seats per table. You can customize this migration as you want.
Now you should run migrations by:

php artisan migrate
Enter fullscreen mode Exit fullscreen mode

The last work you should do is open the User Model and implement from the CustomerInterface interface and use the customer trait in the Model class:

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use ShayanYS\LaraReserve\Interfaces\CustomerInterface;
use ShayanYS\LaraReserve\Traits\Customer;

class User extends Authenticatable implements CustomerInterface
{
    use HasApiTokens, HasFactory, Notifiable, customer;

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

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Enter fullscreen mode Exit fullscreen mode

Step 3: Controllers and Requests

At this article's beginning, we created a controller for RestaurantTable Model. Now we need another controller named 'ReserveRestaurantTableController'. Run the following command in your terminal:

php artisan make:request ReserveRestaurantTableController
Enter fullscreen mode Exit fullscreen mode

After this, we need a request to validate reserves:

php artisan make:controller ReserveTableRequest
Enter fullscreen mode Exit fullscreen mode

RestaurantTableController

Open the 'RestaurantTableController' and write the below codes:

namespace App\Http\Controllers;

use App\Http\Requests\StoreRestaurantTable;
use App\Models\RestaurantTable;
use Illuminate\Http\Request;

class RestaurantTableController extends Controller
{
    public function index(){

        $tables = RestaurantTable::paginate(15);
        return view('restaurantTable',compact('tables'));
    }

    public function store(StoreRestaurantRequestTable $request){
        RestaurantTable::create($request->validated());
        return redirect()->back();
    }
}

Enter fullscreen mode Exit fullscreen mode
  • 'index' -> shows a form to submit new tables and a list of our restaurant tables.
  • 'store' -> This will create a new record for restaurant tables. ### StoreRestaurantTableRequest Now we should write validations for RestaurantTable to store. Open the 'StoreRestaurantTableRequest' and write the following lines:
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreRestaurantTableRequest extends FormRequest
{
    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
     */
    public function rules(): array
    {
        return [
            'table_number' => 'required|numeric|min:0|max:255,unique:restaurantTable',
            'capacity' => 'required|numeric|min:1|max:12',
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

ReserveRestaurantTableController

now we should write codes to make reservations in 'ReserveRestaurantTableController':

namespace App\Http\Controllers;

use App\Http\Requests\ReserveTableRequest;
use App\Models\RestaurantTable;
use App\Models\User;
use Carbon\Carbon;
use ShayanYS\LaraReserve\Models\Reserve;

class ReserveRestaurantTableController extends Controller
{
    public function reserveForm(RestaurantTable $resturantTable)
    {
        $users = User::all();
        return view('reserveForm', compact('resturantTable', 'users'));
    }

    public function reserveTable(ReserveTableRequest $request, RestaurantTable $resturantTable)
    {

        $customer = User::find($request->validated('customer'));
        $reserveDate = Carbon::parse($request->validated('reserved_date'));
        $reserveTime = $request->validated('reserved_time');

        $customer->reserve($resturantTable, $reserveDate, $reserveTime);

        return redirect()->route('reserve.index')->with('success','reserved successfully');
    }

    public function index()
    {
        $reserves = Reserve::all();

        return view('reserveIndex',compact('reserves'));
    }
}
Enter fullscreen mode Exit fullscreen mode
  • 'reserveForm' -> shows a form to submit a reserve. Gets a {restaurantTable} to make a reservation;
  • 'reserveTable' -> will create a reservation record.
  • 'index' -> will show a list of reservations.

ReserveTableRequest

we should validate data passed from users (They may have been playful) 😅, so open 'ReserveTableRequest' and write these:

namespace App\Http\Requests;


use Illuminate\Foundation\Http\FormRequest;

class ReserveTableRequest extends FormRequest
{


    /**
     * Get the validation rules that apply to the request.
     *
     * @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array|string>
     */
    public function rules(): array
    {
        return [
            'reserved_date' => 'required|after:yesterday|date',
            'reserved_time' => 'required|date_format:H:i:s',
            'customer' => 'required|exists:users,id',
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Routes

it's wrong to expect the website without routes 😁, so open the web.php routes file and write the following routes:

Route::group([],function (){

    Route::get('/', [\App\Http\Controllers\RestaurantTableController::class,'index'])->name('table.index');
    Route::post('/store', [\App\Http\Controllers\RestaurantTableController::class,'store'])->name('table.store');

});

Route::name('reserve.')->prefix('/reserve')->group(function (){
    Route::get('/{resturantTable}', [\App\Http\Controllers\ReserveRestaurantTableController::class,'reserveForm'])->name('table.form');
    Route::post('/reserveTable/{resturantTable}', [\App\Http\Controllers\ReserveRestaurantTableController::class,'reserveTable'])->name('reserveTable');
    Route::get('/', [\App\Http\Controllers\ReserveRestaurantTableController::class,'index'])->name('index');
});

Enter fullscreen mode Exit fullscreen mode

Last Step: views

don't think I will leave this article without making views for this project (Although they are simple, they are finally views 😂).

reserveForm.blade.php

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>restaurant tables</title>
    </head>
    <body>

        <ul>
            @foreach($errors->all() as $error)
                <li>
                    {{$error}}
                </li>
            @endforeach
        </ul>

        <form action="{{route('reserve.reserveTable',[$resturantTable->id])}}" method="post">
            @csrf
            reserve date: <input type="date" name="reserved_date" value="{{old('reserved_date')}}">
            reserve time: <input type="text" name="reserved_time" value="{{old('reserved_time')}}">
            <select name="customer">
                <option value="">
                    select a user
                </option>
                @foreach($users as $user)
                    <option value="{{$user->id}}" {{old('customer') == $user->id ? 'selected':''}}>{{$user->email}}</option>
                @endforeach
            </select>
            <input type="submit">
            @csrf
        </form>

    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

reserveIndex.blade.php

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>restaurant tables</title>
    </head>
    <body>


        <p>
            {{session('success')}}
        </p>


        <table style="width: 500px;text-align: center">
            <thead>
            <th>
                id
            </th>

            <th>
                reserve date
            </th>

            <th>
                reserve time
            </th>

            <th>
                table number
            </th>
            </thead>

            <tbody>
            @foreach($reserves as $reserve)
                <tr>
                    <td>
                        {{$reserve->id}}
                    </td>

                    <td>
                        {{$reserve->reserved_date->toDateString()}}
                    </td>

                    <td>
                        {{$reserve->reserved_time}}
                    </td>

                    <td>
                        {{$reserve->reservable->table_number}}
                    </td>
                </tr>
            @endforeach
            </tbody>
        </table>

    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

restaurantTable.blade.php

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>restaurant tables</title>
    </head>
    <body>

        <ul>
            @foreach($errors->all() as $error)
                <li>
                    {{$error}}
                </li>
            @endforeach
        </ul>

        <form action="{{route('table.store')}}" method="post">
            tabel number:<input type="number" name="table_number" value="{{old('table_number')}}">
            table capacity: <input type="number" name="capacity" value="{{old('capacity')}}">
            <input type="submit">
            @csrf
        </form>

        <table style="width: 500px;text-align: center">
            <thead>
            <th>
                id
            </th>

            <th>
                table number
            </th>

            <th>
                capacity
            </th>

            <th>
                action
            </th>
            </thead>

            <tbody>
            @foreach($tables as $table)
                <tr>
                    <td>
                        {{$table->id}}
                    </td>

                    <td>
                        {{$table->table_number}}
                    </td>

                    <td>
                        {{$table->capacity}}
                    </td>

                    <td>
                        <a href="{{route('reserve.table.form',[$table->id])}}">reserve</a>
                    </td>
                </tr>
            @endforeach
            </tbody>
        </table>

    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Conclusion

we created a simple reservation system for restaurant tables; you can extend this project as you want, and I hope you like this article. Thanks for reading my article.
Be sure to read Lara Reserve Documentation in GITHUB. I linked it at the beginning of the article.

Top comments (2)

Collapse
 
tiagofrancafernandes profile image
Tiago França

great

Collapse
 
shayan-yousefi profile image
shayan yousefi

Thanks, man.