中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于Laravel開發會員分銷系統的示例

發布時間:2021-01-25 12:35:55 來源:億速云 閱讀:320 作者:小新 欄目:編程語言

小編給大家分享一下基于Laravel開發會員分銷系統的示例,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

為了概念明確,下文中 邀請者用上級替代,被邀請者使用下級替代

首先,我們要明確我們的需求:首先用戶可以通過程序分享鏈接邀請好友注冊,被邀請者可以通過鏈接注冊,從而綁定邀請關系,其次在下級消費的時候,上級都可以獲得相應的傭金。

現在我們要確定如何實現注冊。我原本打算使用 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 ,在我的轉換無法正常工作時,給我提出了寶貴建議。

<div x-data="{ ...component() } x-cloak x-init="init()">
    <template x-if="affiliate">
        <div>
            <img :src="affiliate.avatar" class="h-8 w-8 rounded-full mr-2">
            <p>Your friend <span x-text="affiliate.name"></span> has invited you to try Sitesauce</p>
            <button>Start your trial</button>
        </div>
    </template>
</div>
<script>
import axios from 'axios'
import Cookies from 'js-cookie'
// 使用模板標簽 $nextTick ,進行代碼轉換,這里特別感謝下我的朋友 Ryan 
window.component = () => ({
    affiliate: null,
    via: new URL(location.href).searchParams.get('via')
    init() {
        if (! this.via) return this.$nextTick(() => this.affiliate = Cookies.getJSON('sitesauce.affiliate'))
        axios.post(`https://app.sitesauce.app/api/affiliate/${encodeURIComponent(this.via)}`).then(response => {
            this.$nextTick(() => this.affiliate = response.data)
            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')
        })
    }
})
</script>

現在,完善 API,使其可以獲取有效數據。 除此之外,我們還需要新增幾個個字段到我們現有的數據庫,這個我們將在之后說明。下面是遷移文件:

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開發會員分銷系統的示例”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

达州市| 凌源市| 白朗县| 马龙县| 长白| 伊金霍洛旗| 石楼县| 集贤县| 莲花县| 府谷县| 石嘴山市| 明星| 五华县| 鹿邑县| 金沙县| 林州市| 苗栗县| 亳州市| 册亨县| 城市| 余姚市| 嘉祥县| 临高县| 突泉县| 德安县| 佳木斯市| 柘荣县| 虹口区| 三明市| 廊坊市| 富平县| 宣汉县| 兴城市| 岫岩| 洪江市| 林州市| 普洱| 洪湖市| 乐清市| 岚皋县| 佛冈县|