让我们用 Laravel 构建一个超级简单的推荐系统

2025-06-07

让我们用 Laravel 构建一个超级简单的推荐系统

不久前,我被要求构建一个推荐系统,作为 Laravel Web 应用程序功能集的一部分。推荐系统对我来说并不陌生,但这是我第一次构建它。推荐系统用于鼓励应用程序的用户邀请其他用户,并在用户使用他们的推荐链接注册该应用程序时获得奖励。

我真心想把事情做得超级简单,但我在网上看到的大多数关于推荐系统的内容要么太复杂,要么对我的用例来说太复杂了。经过一番摸索,我终于想出了一个非常简单的方法,我惊讶于它竟然有效。我们将一起构建一个推荐系统,并研究在这个过程中我们必须做出的一些决策和权衡。

首先,创建一个新的 Laravel 项目。我将我的项目命名为simple-referral。让 Composer 或 Laravel 安装程序发挥它的魔力,你应该就能拥有一个基本的 Laravel 应用程序。配置应用程序数据库,运行它php artisan make:auth,然后我们就可以开始使用了。

推荐流程如下

  1. 用户单击链接即可进入应用程序注册页面。
  2. 当他们注册时,他们的注册应该链接到他们在注册时使用的推荐链接的用户。
  3. 使用推荐链接进行注册的用户应该收到通知,告知有人使用其推荐链接进行了注册。
  4. 新用户应该有自己的推荐链接。

我们可以使用这个场景来模拟我们的Eloquent关系,如下所示

  • 一个用户可以被另一个用户推荐。
  • 一个用户可以推荐多个用户。

本质上,我们之间存在一种One-To-Many关系。打开create_users_table迁移并进行以下更改。



$table->unsignedBigInteger('referrer_id');


Enter fullscreen mode Exit fullscreen mode

可是等等!并非所有用户都有引荐来源,所以让我们创建一个引荐来源列nullable。与此同时,我们还要foreign_key向表添加一个约束userscreate_users_table迁移现在应该如下所示。



    $table->bigIncrements('id');
    $table->unsignedBigInteger('referrer_id')->nullable();
    $table->foreign('referrer_id')->references('id')->on('users');
    $table->string('name');    
    $table->string('email')->unique();            
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();   


Enter fullscreen mode Exit fullscreen mode

迁移数据库并在 中进行以下更改User.php。如果您不知道,只需设置一个自引用表。




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

/**
 * A user has a referrer.
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function referrer()
{
    return $this->belongsTo(User::class, 'referrer_id', 'id');
}

/**
 * A user has many referrals.
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function referrals()
{
    return $this->hasMany(User::class, 'referrer_id', 'id');
}


Enter fullscreen mode Exit fullscreen mode

现在让我们考虑一下推荐链接以及我们希望我们的推荐链接是什么样子。

对于我正在构建的应用程序,业务需求之一是为用户提供一个易于记忆的推荐链接。随着时间的推移,我了解到,易于记忆的 URL 通常都很短。当然也有例外,但正如我所说,它们终究是例外。经过反复讨论,我们最终同意推荐链接应该如下所示https://simple-referral/register?ref=username。这需要用户拥有一个unique,unchanging用户名。

为了满足此业务需求,请修改create_users_table迁移如下



//...
$table->string('username')->unique();


Enter fullscreen mode Exit fullscreen mode

然后打开User.php并进行以下更改



protected $fillable = [
    // ...
    'username',
];

/**
 * The accessors to append to the model's array form.
 *
 * @var array
 */
protected $appends = ['referral_link'];

/**
 * Get the user's referral link.
 *
 * @return string
 */
public function getReferralLinkAttribute()
{
    return $this->referral_link = route('register', ['ref' => $this->username]);
}



Enter fullscreen mode Exit fullscreen mode

我们没有将用户的引荐链接存储在数据库中,而是使用访问器来计算它。然后,我们将该属性附加到 User 模型的数组或 JSON 格式中。要了解更多关于访问器和 Eloquent 序列化的信息,请点击这里这里

您对推荐链接的要求可能有所不同,您可以考虑以下另一种选择https://simple-referral/register?ref=referral_token。在这种情况下,请create_users_table像这样编辑迁移



 //...
 $table->string('referral_token')->unique();


Enter fullscreen mode Exit fullscreen mode

然后打开User.php

  • 添加referral_token到可填写字段。
  • 附加referral_link到模型的数组或 JSON 形式。
  • 使用用户的属性referral_token而不是的来计算引荐链接属性username

这种方法允许用户拥有可编辑的用户名,但您必须考虑如何为用户生成唯一的推荐令牌。这个问题留给您自己去解决。

用户模型已经准备好,数据库结构支持我们的推荐系统;让我们继续我们的控制器!

打开App\Http\Controllers\Auth\RegisterController.php。控制器使用Illuminate\Foundation\Auth\RegistersUsers特征来执行其大部分功能,这意味着我们可以在控制器中覆盖特征的方法。



/**
 * Show the application registration form.
 *
 * @return \Illuminate\Http\Response
 */
public function showRegistrationForm(Request $request)
{
    if ($request->has('ref')) {
        session(['referrer' => $request->query('ref')]);
    }

    return view('auth.register');
}

/**
 * Get a validator for an incoming registration request.
 *
 * @param  array  $data
 * @return \Illuminate\Contracts\Validation\Validator
 */
protected function validator(array $data)
{
    return Validator::make($data, [
        'name' => ['required', 'string', 'max:255'],
        'username' => ['required', 'string', 'unique:users', 'alpha_dash', 'min:3', 'max:30'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'string', 'min:8', 'confirmed'],
    ]);
}

/**
 * Create a new user instance after a valid registration.
 *
 * @param array $data
 *
 * @return \App\Models\User
 */
protected function create(array $data)
{
    $referrer = User::whereUsername(session()->pull('referrer'))->first();

    return User::create([
        'name'        => $data['name'],
        'username'    => $data['username'],
        'email'       => $data['email'],
        'referrer_id' => $referrer ? $referrer->id : null,
        'password'    => Hash::make($data['password']),
    ]);
}


Enter fullscreen mode Exit fullscreen mode

看起来很多,但我们只做三件事

  • 如果注册路线包含查询参数,则设置名为“referrer”的会话变量ref
  • 创建用户之前进行表单字段验证。
  • 创建用户时从会话中检索引荐来源,然后将其 id 设置为正在创建的用户的 referrer_id。

为了完善我们简单的推荐系统,当新用户使用推荐链接注册时,用户应该会收到通知。为了尽可能灵活和强大,我将使用Notification而不是Mailable。运行php artisan make:notification nameOfTheNotification来生成通知。我将我的命名为ReferralBonus。我将由您决定发送通知的渠道。

像这样打开RegisterController.php并覆盖方法registered



/**
 * The user has been registered.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  mixed  $user
 * @return mixed
 */
protected function registered(Request $request, $user)
{
    if ($user->referrer !== null) {
        Notification::send($user->referrer, new ReferrerBonus($user));
    }

    return redirect($this->redirectPath());
}


Enter fullscreen mode Exit fullscreen mode

这里,如果新注册的用户有引荐来源,我们会向其发送通知。然后,我们会重定向到 上定义的重定向路径RegisterController注意:不要忘记导入所有必要的类。

现在我们来处理前端。打开register.blade.php并添加一个用于输入用户名的表单字段。



//...
<div class="form-group row">
    <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Username') }}</label>

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

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


Enter fullscreen mode Exit fullscreen mode

现在,我们修改一下home.blade.php,显示一些用户信息



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

    You are logged in!

    <ul class="list-group mt-3">
        <li class="list-group-item">Username: {{ Auth::user()->username }}</li>
        <li class="list-group-item">Email: {{ Auth::user()->email }}</li>
        <li class="list-group-item">Referral link: {{ Auth::user()->referral_link }}</li>
        <li class="list-group-item">Referrer: {{ Auth::user()->referrer->name ?? 'Not Specified' }}</li>
        <li class="list-group-item">Refferal count: {{ count(Auth::user()->referrals)  ?? '0' }}</li>
    </ul>
</div>


Enter fullscreen mode Exit fullscreen mode

我们简单的推荐系统现已完成。如果您在后续操作中遇到困难,可以浏览我在 Github 上为本教程创建的仓库。

GitHub 徽标 simioluwatomi /简单推荐

使用 Laravel 构建的超级简单的推荐系统

用户详情图片

该项目演示了一个使用 Laravel 构建的超级简单的推荐系统。要阅读我为此编写的教程,请点击此处

运行项目

  • 将其克隆到您的计算机。
  • 运行composer install以安装应用程序依赖项。
  • 复制.env.example.env
  • 运行php artisan key:generate以生成应用程序密钥。
  • 将数据库凭据添加到.env
  • 运行php artisan migrate以迁移数据库。
  • 要运行所包含的测试,请将testing中定义的数据库连接的数据库凭据添加config/database.php.env
文章来源:https://dev.to/simioluwatomi/let-s-build-a-super-simple-referral-system-with-laravel-1o3h
PREV
软件架构文档的极简方法
NEXT
哪些技能造就了优秀的软件工程师?