Simple Laravel referral system using referral code

Nov 09, 2023
laravel
php
webdev

So i was working on a project and decided. "heyy, why not add a referral system and encourage users to share the application". Searched the web but all solutions weren't what i wanted, I mean referral systems aren't new to me but this is going to be my first time building one with laravel and this is also my going to be my first blog post ūüéČ. So lets get to it,

The referral is going to work like this:

- A user signs up and a code gets auto generated as their referral code which they can give to others 

- When a user registers, they're prompted to add a referral code

- The user whose referral code was used would be notified that someone registered with their code

We are going to be creating 2 migration tables. The user table and the referral table.
Our eloquent Model should be a case where a user can be refered by another user and a user can refer many users but it's going to be (One to One) while we have a column that adds each time a new user uses an existing user referral code. 
First of, we create our laravel application

 laravel new referral-app

After installing laravel, we make the referral model, migration and controller

php artisan make:model Referral -mc

Now we edit our migration table, first the users table ūüĎá

public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->string('referral_status')->default('off');
            $table->string('referral_by')->nullable();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

Now we edit the referral table

 public function up(): void
    {
        Schema::create('referrals', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('referral_code')->unique()->nullable();
            $table->integer('total_referred_users')->default(0);
            $table->timestamps();
        });
    }

We are using foreignId cause of our Eloquent relationship with the users table One-To-Many.
Let's not forget our auth ūüėČ

composer require laravel/ui
php artisan ui bootstrap
php artisan ui bootstrap --auth 

Let's edit our models, starting with the User Model

protected $fillable = [
        'name',
        'email',
        'password',
        'referral_status',
        'referral_by'
];

public function referral(){
    return $this->hasOne(Referral::class);
}

We did we just do?

- First we added referral_status and referral_by to the $fillable in the User model

- Then we specified the eloquent relationship hasOne

On the other hand the Referral model eloquent relationship should belongsTothe User model and we add user_id, referral_code and total_referred_users to the Referral model $fillable

 protected $fillable = [
        'user_id',
        "referral_code",
        "total_referred_users"
    ];


    public function user(){
        return $this->belongsTo(User::class);
    }

Using MySql, we're going to create a database referral_app and link it to through our .env file.

Now we migrate and the add Auth route to our routes/web.php file

php artisan migrate

In the web.php file add thisūüĎá

Auth::routes();

Now let's add referral code to every user who signs up but first we need a page for users to enter their referral code after signing up. We would create a new file in our view/auth folder called referral.blade.php and place this code below in it

@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 card">
    <div class="card-header">{{ __('Referral') }}</div>

    <div class="card-body">
    <form method="POST" action="{{ route('referral.verify') }}">
        @csrf
        @method('PATCH')

        <div class="row mb-3">
            <label for="referral" class="col-md-4 col-form-label text-md-end">{{ __('Referral Code') }}</label>

            <div class="col-md-6">
                <input id="referral" type="text" class="form-control @error('referral') is-invalid @enderror" name="referral" value="{{ old('referral') }}" required autocomplete="referral" autofocus>

                @error('referral')
                    <span class="invalid-feedback" role="alert">
                        <strong>{{ $message }}</strong>
                    </span>
                @enderror
            </div>
        </div>

        <div class="row mb-0">
            <div class="col-md-8 offset-md-4">
                <button type="submit" class="btn btn-primary">
                    {{ __('Proceed') }}
                </button>
            </div>
        </div>
    </form>
    </div>
</div>
</div>
</div>
@endsection

The form is being submitted to a patch route referral.store which we are going to add the web.php file later on, for now let's add this to the web.php

Route::get('/referral', function(){ return view('auth.referral');})->name('referral');

Now we let's get back to generating a referral code to every user who signs up

Locate the  RegisterController , we're going to edit the protected function create(array $data)

Replace the function with this edited version

protected function create(array $data)
    {
        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => Hash::make($data['password']),
        ]);
        Referral::create([
            'user_id'=> $user->id,
            'referral_code'=>Str::random(6),
        ]);

        return $user;

    }

Also in your view/home.blade.php replace the existing code with this

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
        <div class="card">
            <div class="card-header">{{ __('Dashboard') }}</div>

            <div class="card-body">
                @if (session('status'))
                    <div class="alert alert-success" role="alert">
                        {{ session('status') }}
                    </div>
                @endif

                <p>Your referral code is {{ auth()->user()->referral->referral_code }}</p>
            </div>
        </div>
        </div>
    </div>
</div>
@endsection

Now let's add the referral part. First locate  App/Providers/RouteServiceProvider  and edit

Change from this:

public const HOME = '/home';

To this:

  public const HOME = '/referral';

Now it's time to add our route referral.store and verify referrals.
In your web.php file, add the patch route for storing the referrals

Route::patch('/referral/store', [App\Http\Controllers\ReferralController::class, 'store'])->name('referral.store');

In the ReferralController add the store function

public function store(Request $request){
     $user = User::find(Referral::where("referral_code", $request->referral)->first()->user_id);
     $total_referred_users = $user->referral->total_referred_users + 1;
     $user->referral->update(['total_referred_users'=> $total_referred_users]);
     DB::table('users')->where('id', auth()->user()->id)->update(['referral_by' => $request->referral]);
     Notification::route('mail', $user->email)->notify(new UserNotification());
     return redirect()->action([HomeController::class,'index']);
 }

Let me explain the code

- First we got the user using the referral code that was submitted then we added to it counts of user

- We then proceeded to update the new user's referral_by  column to add a referral code

- Finally, we send a notification to the user who referred that someone signed up with their referral code

Don't forget to make notification to generate the email notification

php artisan make:notification UserNotification

Edit the contents and replace with this code

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use App\Models\User;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class UserNotification extends Notification
{
    use Queueable;

    /**
     * Create a new notification instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the notification's delivery channels.
     *
     * @return array<int, string>
     */
    public function via(object $notifiable): array
    {
        return ['mail'];
    }

    /**
     * Get the mail representation of the notification.
     */
    public function toMail(object $notifiable): MailMessage
    {
        return (new MailMessage)
                    ->line("A user just joined ".getenv('APP_NAME')." using your referral code")
                    ->line('Thank you for using our application!');
    }

    /**
     * Get the array representation of the notification.
     *
     * @return array<string, mixed>
     */
    public function toArray(object $notifiable): array
    {
        return [
            //
        ];
    }
}

Our Laravel referral system using referral code is now done, don't forget

php artisan serve
npm install
npm run dev

You can check the code out on my github.
https://github.com/hen8y/laravel-referral-system
In case you want to make the notifcation mail send faster, make sure to check laravel queue

© 2023 Ogbonna Henry. All rights reserved.