0

0

基于 Laravel 开发会员分销系统

Guanhui

Guanhui

发布时间:2020-05-28 10:16:32

|

3994人浏览过

|

来源于learnku

转载

基于 Laravel 开发会员分销系统

最近,在 Sitesauce 现有基础上新增会员系统,就具体实现细节写了这篇文章。

笔记:我将从零开始构建该程序,这样无论你处于什么阶段都可以读懂该文章。 当然如果你已经非常熟悉 Laravel ,你可以在此 Rewardful 之类的平台上完成该工作,这样会节省不少时间。

为了概念明确,下文中 邀请者用上级替代,被邀请者使用下级替代

首先,我们要明确我们的需求:首先用户可以通过程序分享链接邀请好友注册,被邀请者可以通过链接注册,从而绑定邀请关系,其次在下级消费的时候,上级都可以获得相应的佣金。

现在我们要确定如何实现注册。我原本打算使用 Fathom 的方法,只要将用户引导到特定页面,该用户将会被标记为 special referral page ,待用户完注册,并将关系绑定。 但最终采用的是 Rewardful 的做法,通过向链接添加参数 ?via=miguel 来实现推荐页面的构建。

好了,现在让我们创建我们的注册页面,在注册页面程序会通过链接参数 via 匹配上级。 代码很简单,如果 via 存在那么将其存储到 Cookie 30 天,由于我们有几个不同子域名都需要该操作,所以我们将其添加到主域名下,这样所有子域均可使用该 Cookie。下面视具体代码:

import Cookies from 'js-cookie'
const via = new URL(location.href).searchParams.get('via')
if (via) {
    Cookies.set('sitesauce_affiliate', via, {
        expires: 30,
        domain: '.sitesauce.app',
        secure: true,
        sameSite: 'lax'
    })
}

这样做的好处是当会员未通过此次分享注册,而是事后自己注册的时候,可以明确地知道该会员是通过那个上级的引荐而来的。我想更进一步,在新会员注册的时候通过显示一些标语以及上级者信息,从而使用户明确知道这是来自会员(好友)的一个引荐链接,从而使注册成功率更高,所以我添加了提示弹窗。效果如下:

想要实现上面效果的话,现在我们需要的不仅仅是上级标签,还需要上级详细信息,所以我们需要一个 API,该 API 会通过 via 匹配并提供上级详细信息。

import axios from 'axios'
import Cookies from 'js-cookie'
const via = new URL(location.href).searchParams.get('via')
if (via) {
    axios.post(`https://app.sitesauce.app/api/affiliate/${encodeURIcomponent(this.via)}`).then(response => {
        Cookies.set('sitesauce_affiliate', response.data, { expires: 30, domain: '.sitesauce.app', secure: true, sameSite: 'lax' })
    }).catch(error => {
        if (!error.response || error.response.status !== 404) return console.log('Something went wrong')
        console.log('Affiliate does not exist. Register for our referral program here: https://app.sitesauce.app/affiliate')
    })
}

在 URL 中你可以看到 encodeURIComponent,他的作用是保护我们不在受 Path Traversal vulnerability 的影响。 在我们发送请求到 /api/referral/:via,如果过有人恶意修改链接参数,像这样: ?via=../../logout ,用户在点击之后可能会注销,当然这可能没有什么影响,但是不可避免得会有些其他的会带来不可预期影响的操作。

由于 Sitesauce 在一些地方使用了 Alpine,所以我们在此基础之上,将弹窗修改为 Alpine 组件,这样有更好的扩展性。 这里要感谢下 Ryan ,在我的转换无法正常工作时,给我提出了宝贵建议。

现在,完善 API,使其可以获取有效数据。 除此之外,我们还需要新增几个个字段到我们现有的数据库,这个我们将在之后说明。下面是迁移文件:

yershop开源网店系统
yershop开源网店系统

yershop开源网店系统是一款基于tp5.1优化版的商城系统,具有建站便捷、扩展丰富、二次开发灵活,以及支持云服务的特点,适合企业及个人快速构建个性化网上商店.系统分为开源版和商业版

下载
class AddAffiliateColumnsToUsersTable extends Migration
{
    /**
     * 迁移执行
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('affiliate_tag')->nullable();
            $table->string('referred_by')->nullable();
            $table->string('paypal_email')->nullable();
            $table->timestamp('cashed_out_at')->nullable();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('affiliate_tag', 'referred_by', 'paypal_email', 'cashed_out_at');
        });
    }
}

通过路由自定义键名功能实现参数绑定 (可在 Laravel 7.X 上使用),构建我们的 API 路由。

Route::post('api/affiliate/{user:affiliate_tag}', function (User $user) {
    return $user->only('id', 'name', 'avatar', 'affiliate_tag');
})->middleware('throttle:30,1');

在开始注册操作之前,首先读取我们的 Cookie,由于未进行加密,所以我们需要将其加入到 EncryptCookies 的 except 字段中,将其排除。

// 中间件:app/Http/Middleware/EncryptCookies.php
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
    /**
    * The names of the cookies that should not be encrypted
    *
    * @var array
    */
    protected $except = [
        'sitesauce_referral',
    ];
}

现在通过 RegisterController 的 authenticated 方法执行注册相应的逻辑,其间,我们通过上面的方式获取 Cooke,并通过该 Cooke 找到相应的上级,最终实现将下级与上级关联。

/**
 * 上级用户已经注册
 *
 * @param \Illuminate\Http\Request $request
 * @param \App\User $user
 */
protected function registered(Request $request, User $user)
{
    if (! $request->hasCookie('sitesauce.referral')) return;
    $referral = json_decode($request->cookie('sitesauce_referral'), true)['affiliate_tag'];
    if (! User::where('affiliate_tag', $referral)->exists()) return;
    $user->update([
        'referred_by' => $referral,
    ]);
}

我们还需要一个方法来获取我的下级用户;列表,通过 ORM 的 hasMany 方法很简单的就实现了。

class User extends Model
{
    public function referred()
    {
        return $this->hasMany(self::class, 'referred_by', 'affiliate_tag');
    }
}

现在,让我们构建我们的注册页面,在用户注册时候,他们可以选择喜好标签,并需要他们提供 PayPal 电子邮件 以以便之后的提现操作。下面是效果预览:

会员注册后,我们还需要提供电子邮箱的变更,以及标签变更的相关入口。在其变更标签之后,我们需要级联更新其下级用户的的标签,以确保两者的统一。这涉及到了数据库的事务操作,为保证操作的原子性,我们需要在事务中完成以上两个操作。代码如下:

public function update(Request $request)
    {
        $request->validate([
            'affiliate_tag' => ['required', 'string', 'min:3', 'max:255', Rule::unique('users')->ignoreModel($request->user())],
            'paypal_email' => ['required', 'string', 'max:255', 'email'],
        ]);
        DB::transaction(function () use ($request) {
            if ($request->input('affiliate_tag') != $request->user()->affiliate_tag) {
                User::where('referred_by', $request->user()->affiliate_tag)
                    ->update(['referred_by' => $request->input('affiliate_tag')]);
            }
            $request->user()->update([
                'affiliate_tag' => $request->input('affiliate_tag'),
                'paypal_email' => $request->input('paypal_email'),
            ]);
        });
        return redirect()->route('affiliate');
    }

下面我们需要确定会员收益的计算方式,可以通过下级用户的所有消费金额的百分比作为佣金返给上级,为了计算方便,我们仅仅计算自上次结款日期之后的数据。我们使用扩展 Mattias’ percentages package 使计算简单明了。

use Mattiasgeniar\Percentage\Percentage;
const COMMISSION_PERCENTAGE = 20;
public function getReferralBalance() : int
{
    return Percentage::of(static::COMISSION_PERCENTAGE,
        $this->referred
            ->map(fn (User $user) => $user->invoices(false, ['created' => ['gte' => optional($this->cashed_out_at)->timestamp]]))
            ->flatten()
            ->map(fn (\Stripe\Invoice $invoice) => $invoice->subtotal)
            ->sum()
    );
}

最后我们以月结的方式向上级发放佣金,并更新 cashed_out_at 字段为本次佣金发放时间。效果如下:

至此,希望以上文档对你有帮助。祝你快乐每天。

推荐教程:《Laravel教程

基于 Laravel 开发会员分销系统

相关专题

更多
laravel组件介绍
laravel组件介绍

laravel 提供了丰富的组件,包括身份验证、模板引擎、缓存、命令行工具、数据库交互、对象关系映射器、事件处理、文件操作、电子邮件发送、队列管理和数据验证。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

313

2024.04.09

laravel中间件介绍
laravel中间件介绍

laravel 中间件分为五种类型:全局、路由、组、终止和自定。想了解更多laravel中间件的相关内容,可以阅读本专题下面的文章。

270

2024.04.09

laravel使用的设计模式有哪些
laravel使用的设计模式有哪些

laravel使用的设计模式有:1、单例模式;2、工厂方法模式;3、建造者模式;4、适配器模式;5、装饰器模式;6、策略模式;7、观察者模式。想了解更多laravel的相关内容,可以阅读本专题下面的文章。

363

2024.04.09

thinkphp和laravel哪个简单
thinkphp和laravel哪个简单

对于初学者来说,laravel 的入门门槛较低,更易上手,原因包括:1. 更简单的安装和配置;2. 丰富的文档和社区支持;3. 简洁易懂的语法和 api;4. 平缓的学习曲线。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

363

2024.04.10

laravel入门教程
laravel入门教程

本专题整合了laravel入门教程,想了解更多详细内容,请阅读专题下面的文章。

80

2025.08.05

laravel实战教程
laravel实战教程

本专题整合了laravel实战教程,阅读专题下面的文章了解更多详细内容。

63

2025.08.05

laravel面试题
laravel面试题

本专题整合了laravel面试题相关内容,阅读专题下面的文章了解更多详细内容。

62

2025.08.05

cookie
cookie

Cookie 是一种在用户计算机上存储小型文本文件的技术,用于在用户与网站进行交互时收集和存储有关用户的信息。当用户访问一个网站时,网站会将一个包含特定信息的 Cookie 文件发送到用户的浏览器,浏览器会将该 Cookie 存储在用户的计算机上。之后,当用户再次访问该网站时,浏览器会向服务器发送 Cookie,服务器可以根据 Cookie 中的信息来识别用户、跟踪用户行为等。

6408

2023.06.30

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

0

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Laravel---API接口
Laravel---API接口

共7课时 | 0.6万人学习

PHP自制框架
PHP自制框架

共8课时 | 0.6万人学习

PHP面向对象基础课程(更新中)
PHP面向对象基础课程(更新中)

共12课时 | 0.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号