您的位置 首页 php

Laravel通过监听和注册登录和邮箱验证实现积分功能

如果你的网站有积分功能,往往会给新注册激活的用户一定的初始积分,每日签到/登录积分奖励等,在 Laravel 框架驱动的应用中,我们可以通过监听相应的事件来设置用户积分,下面我们就来简单演示其实现过程,并以此为例介绍用户注册登录事件监听及处理。

用户注册、登录和邮箱验证事件类 Laravel 框架底层已经提供,我们只需要通过事件监听器或订阅者来监听处理这些事件即可。

注:关于事件类的定义、监听和订阅,可以查看事件文档了解明细。
 

由于我们之前在模型事件教程中已经创建一个用户事件订阅者类 UserEventSubscriber,这里,我们在其基础上编写用户注册登录相关事件及其处理。

为用户表新增积分字段

要实现积分功能,首先需要新增一个数据库迁移类为用户表新增一个积分字段:

 php artisan make:migration alter_users_add_point --table=users
 

编写对应的迁移文件代码如下:

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AlterUsersAddPoint extends Migration
{
 /**
 * Run the migrations.
 *
 * @return void
 */
 public function up()
 {
 Schema::table('users', function (Blueprint $table) {
 $table->integer('point')-> unsigned ()->default(0)->after('password');
 });
 }
 /**
 * Reverse the migrations.
 *
 * @return void
 */
 public function down()
 {
 Schema::table('users', function (Blueprint $table) {
 $table->dropColumn('point');
 });
 }
}
 

登录到数据库所在环境,运行 php artisan migrate 让上述迁移生效。这样,users 表中就有 point 字段了:

新增用户积分日志表

此外,我们还要创建一张积分日志表,用于记录用户积分变更明细,通过如下命令创建积分日志模型类及对应迁移类:

php artisan make:model PointLog -m
 

该命令会创建一个 PointLog 模型类及对应数据库迁移文件,编写迁移文件代码如下:

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePointLogsTable extends Migration
{
 /**
 * Run the migrations.
 *
 * @return void
 */
 public function up()
 {
 Schema::create('point_logs', function (Blueprint $table) {
 $table->increments('id');
 $table->integer('user_id')->unsigned();
 $table->tinyInteger('type')->unsigned()->comment('操作类型');
 $table->smallInteger('value')->comment('积分变动值');
 $table->timestamps();
 $table->index('user_id');
 });
 }
 /**
 * Reverse the migrations.
 *
 * @return void
 */
 public function down()
 {
 Schema::dropIfExists('point_logs');
 }
}
 

登录到数据库所在环境,运行 php artisan migrate 让上述迁移生效。这样,就会在数据库中新增 point_logs 数据表。

然后在初始化 PointLog 模型类代码如下:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class PointLog extends Model
{
 const OPT_USER_REGISTER = 1; // 用户注册
 const OPT_EMAIL_VERIFY = 2; // 邮箱验证
 const OPT_USER_LOGIN = 3; // 用户登录
 // 不同操作对应积分映射关系
 public static $OPT_POINT = [
 self::OPT_USER_REGISTER => 30,
 self::OPT_EMAIL_VERIFY => 20,
 self::OPT_USER_LOGIN => 5
 ];
}
 

在该模型类中,我们主要设置了一些常量属性用于标识不同的操作类型,并定义了不同操作类型映射的积分变动值。对于本例而言,业务逻辑比较简单,所以通过一个静态属性数组来映射这个关系,对于复杂应用,映射值很多,这样做就不合适了,可以通过新增一张表来存储不同操作对应积分值,也方便管理。

定义模型类之间的关联关系

最后,我们还要在 User 模型类中通过如下方法定义其与 PointLog 之间的一对多关联:

public function pointLogs()
{
 return $this->hasMany(PointLog::class);
}
 

新用户注册

准备好数据结构之后,接下来,我们来处理事件监听。

用户注册对应的事件类是 Registered,对应事件类如下:

<?php
namespace Illuminate\Auth\Events;
use Illuminate\Queue\SerializesModels;
class Registered
{
 use SerializesModels;
 /**
 * The authenticated user.
 *
 * @ var  \Illuminate\Contracts\Auth\Authenticatable
 */
 public $user;
 /**
 * Create a new event instance.
 *
 * @param \Illuminate\Contracts\Auth\Authenticatable $user
 * @return void
 */
 public function __construct($user)
 {
 $this->user = $user;
 }
}
 

该事件会在用户注册成功后触发,打开 UserEventSubscriber.php,在 subscribe 添加用户注册事件及对应的处理函数:

// 在文件顶部引入事件类完整命名空间
use Illuminate\Auth\Events\Registered;
$events->listen(
 Registered::class,
 UserEventSubscriber::class . '@onUserRegistered'
);
 

然后编写用户注册事件处理函数 onUserRegistered:

// 在文件定义引入 PointLog
use App\PointLog;
/**
 * 处理用户注册成功事件
 * @param $event
 */
public function onUserRegistered($event) {
 // 用户注册成功后初始积分为30
 $event->user->point += PointLog::$OPT_POINT[PointLog::OPT_USER_REGISTER];
 $event->user->save();
 // 保存积分变更日志
 $pointLog = new PointLog();
 $pointLog->type = PointLog::OPT_USER_REGISTER;
 $pointLog->value = PointLog::$OPT_POINT[PointLog::OPT_USER_REGISTER];
 $event->user->pointLogs()->save($pointLog);
}
 

这里,我们在用户注册成功后将其积分字段值初始化为注册奖励积分,并通过关联模型插入方式记录积分变更日志。

新用户邮箱验证

如果开启了邮箱验证功能,需要等到用户验证邮箱后,该用户才算真正激活,可以正常登录。验证邮箱事件框架底层也提供了,对应事件类是 Verified,实现代码如下:

<?php
namespace Illuminate\Auth\Events;
use Illuminate\Queue\SerializesModels;
class Verified
{
 use SerializesModels;
 /**
 * The verified user.
 *
 * @var \Illuminate\Contracts\Auth\MustVerifyEmail
 */
 public $user;
 /**
 * Create a new event instance.
 *
 * @param \Illuminate\Contracts\Auth\MustVerifyEmail $user
 * @return void
 */
 public function __construct($user)
 {
 $this->user = $user;
 }
}
 

该事件会在用户验证邮箱后触发,我们在订阅者 UserEventSubscriber 的 subscribe 方法中新增对该事件的订阅:

// 在文件顶部引入事件类完整命名空间
use Illuminate\Auth\Events\Verified;
$events->listen(
 Verified::class,
 UserEventSubscriber::class . '@onEmailVerified'
);
 

然后编写 onEmailVerified 方法来处理用户验证邮箱事件:

/**
 * 处理验证邮箱事件
 * @param $event
 */
public function onEmailVerified($event) {
 // 用户验证邮箱后增加20积分
 $event->user->point += PointLog::$OPT_POINT[PointLog::OPT_EMAIL_VERIFY];
 $event->user->save();
 // 保存积分变更日志
 $pointLog = new PointLog();
 $pointLog->type = PointLog::OPT_EMAIL_VERIFY;
 $pointLog->value = PointLog::$OPT_POINT[PointLog::OPT_EMAIL_VERIFY];
 $event->user->pointLogs()->save($pointLog);
}
 

验证邮箱后,为该用户新增 20 积分值,并记录积分变更日志。

用户每日登录

最后,我们来看用户登录事件的处理。用户登录事件类 Login 定义如下:

<?php
namespace Illuminate\Auth\Events;
use Illuminate\Queue\SerializesModels;
class Login
{
 use SerializesModels;
 /**
 * The authentication guard name.
 *
 * @var string
 */
 public $guard;
 /**
 * The authenticated user.
 *
 * @var \Illuminate\Contracts\Auth\Authenticatable
 */
 public $user;
 /**
 * Indicates if the user should be "remembered".
 *
 * @var bool
 */
 public $remember;
 /**
 * Create a new event instance.
 *
 * @param string $guard
 * @param \Illuminate\Contracts\Auth\Authenticatable $user
 * @param bool $remember
 * @return void
 */
 public function __construct($guard, $user, $remember)
 {
 $this->user = $user;
 $this->guard = $guard;
 $this->remember = $remember;
 }
}
 

该事件会在用户登录成功后触发,同样,我们在订阅者 UserEventSubscriber 的 subscribe 方法中新增对该事件的订阅:

// 在文件顶部引入事件类完整命名空间
use Illuminate\Auth\Events\Login; 
$events->listen(
 Login::class,
 UserEventSubscriber::class . '@onUserLogin'
);
 

然后编写事件处理函数 onUserLogin:

// 在文件顶部引入 Carbon
use Carbon\Carbon;
/**
 * 处理用户登录事件
 * @param $event
 */
public function onUserLogin($event) {
 $pointLog = PointLog::where('user_id', $event->user->id)->where('type', PointLog::OPT_USER_LOGIN)->orderBy('created_at', 'desc')->first();
 $firstLoginToday = false;
 if (!$pointLog) {
 // 注册后首次登录
 $firstLoginToday = true;
 } else {
 $lastLoginTime = new Carbon($pointLog->created_at);
 if ($lastLoginTime->isYesterday()) {
 // 上次登录时间是昨天
 $firstLoginToday = true;
 }
 }
 if ($firstLoginToday) {
 // 用户每日首次登录成功后增加5积分
 $event->user->point += PointLog::$OPT_POINT[PointLog::OPT_USER_LOGIN];
 $event->user->save();
 // 保存积分变更日志
 $pointLog = new PointLog();
 $pointLog->type = PointLog::OPT_USER_LOGIN;
 $pointLog->value = PointLog::$OPT_POINT[PointLog::OPT_USER_LOGIN];
 $event->user->pointLogs()->save($pointLog);
 }
}
 

该处理函数相对复杂一点,因为我们只在每日首次登录才会对用户进行积分奖励,这个包含两种情况的判断,一种是用户首次登录,一种是上次登录时间是昨天,只有在这两种场景下,才会更新用户积分,同时记录积分变更日志。

测试用户登录注册流程积分变更

接下来,我们来演示一个新用户从注册到登录过程中的积分变更,并以此验证相应事件处理函数是否监听到对应事件并处理成功。

在浏览器访问新用户注册页面 ,填写注册表单:

点击注册按钮提交表单进行注册,页面跳转到邮箱验证页面:

说明注册成功。我们去查看 users 表和 point_logs 新增记录:

users 表中 point 字段值是 35,point_logs 中有两条记录,一条表示注册,一条表示登录,这意味着虽然邮箱未验证,但用户已经登录成功,只是未验证邮箱被中间件拦截,不能访问认证页面罢了。

下面我们来验证邮箱,登录到注册邮箱,在收件箱点开收到的验证邮件:

点击验证邮箱按钮进行验证,验证成功后会跳转到如下页面:

表示邮箱已验证,用户已激活,这个时候再到数据库查看 users 表和 point_logs 表记录:

会看到用户积分已变更,对应积分记录已生成,正是验证邮箱事件对应处理函数实现的。

为了验证用户每日登录只奖励一次积分,我们退出登录状态重新登录,如果用户积分没有变动,则表示代码是没有问题的。

点击了解更多去学习:非常使用的代码优化,怎么才能写好代码

文章来源:智云一二三科技

文章标题:Laravel通过监听和注册登录和邮箱验证实现积分功能

文章地址:https://www.zhihuclub.com/152201.shtml

关于作者: 智云科技

热门文章

网站地图