Heim  >  Artikel  >  PHP-Framework  >  Entwickeln Sie ein Mitgliederverteilungssystem basierend auf Laravel

Entwickeln Sie ein Mitgliederverteilungssystem basierend auf Laravel

Guanhui
Guanhuinach vorne
2020-05-28 10:16:323582Durchsuche

Entwickeln Sie ein Mitgliederverteilungssystem basierend auf Laravel

Kürzlich wurde der bestehenden Basis von Sitesauce ein neues Mitgliedschaftssystem hinzugefügt, und ich habe diesen Artikel über die spezifischen Implementierungsdetails geschrieben.

Hinweis: Ich werde dieses Programm von Grund auf neu erstellen, damit Sie den Artikel lesen können, egal in welchem ​​Stadium Sie sich befinden. Wenn Sie mit Laravel bereits sehr vertraut sind, können Sie dies natürlich auch auf einer Plattform wie Rewardful tun, was viel Zeit spart.

Um das Konzept zu verdeutlichen, wird im folgenden Text der Einladende durch den Vorgesetzten und der Eingeladene durch den Untergebenen ersetzt.

Zuerst müssen wir es klarstellen Unsere Bedürfnisse: Erstens können Benutzer Linkeinladungen über das Programm teilen. Bei der Registrierung von Freunden können sich die Eingeladenen über den Link registrieren, um die Einladungsbeziehung zu binden. Zweitens kann der Vorgesetzte die entsprechende Provision erhalten, wenn der Untergebene konsumiert.

Jetzt müssen wir festlegen, wie wir die Registrierung umsetzen. Ich hatte ursprünglich geplant, die Methode von Fathom zu verwenden. Solange der Benutzer auf eine bestimmte Seite weitergeleitet wird, wird er als spezielle Empfehlungsseite markiert. Nachdem der Benutzer die Registrierung abgeschlossen hat, wird die Beziehung gebunden. Aber am Ende wurde der Ansatz von Rewardful übernommen, indem der Parameter ?via=miguel zum Link hinzugefügt wurde, um die Empfehlungsseite zu erstellen.

Okay, jetzt erstellen wir unsere Registrierungsseite. Auf der Registrierungsseite gleicht das Programm den Vorgesetzten über den Link-Parameter ab. Der Code ist einfach: Wenn via vorhanden ist, speichern Sie ihn 30 Tage lang in einem Cookie. Da wir mehrere verschiedene Subdomains haben, die dies benötigen, fügen wir ihn unter der Hauptdomain hinzu, damit alle Subdomains das Cookie verwenden können. Der spezifische Code lautet wie folgt:

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'
    })
}

Der Vorteil davon besteht darin, dass Sie eindeutig wissen können, dass das Mitglied auf Empfehlung dieses Vorgesetzten gekommen ist, wenn sich ein Mitglied nicht über diese Freigabe, sondern später selbst registriert . Ich möchte noch einen Schritt weiter gehen und bei der Registrierung eines neuen Mitglieds einige Slogans und übergeordnete Informationen anzeigen, damit der Benutzer klar weiß, dass es sich um einen Empfehlungslink von einem Mitglied (Freund) handelt, wodurch die Erfolgsquote bei der Registrierung erhöht wird, fügte ich hinzu ein Popup-Fenster mit Aufforderung. Der Effekt ist wie folgt:

Wenn wir den oben genannten Effekt erzielen möchten, benötigen wir jetzt nicht nur das Tag der oberen Ebene, sondern auch die detaillierten Informationen der oberen Ebene. Daher benötigen wir eine API, die mit und übereinstimmt Bereitstellung detaillierter Informationen der oberen Ebene über 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')
    })
}

In der URL sehen Sie encodeURIComponent. Ihre Aufgabe besteht darin, uns vor Path Traversal-Schwachstellen zu schützen. Wenn wir eine Anfrage an /api/referral/:via senden und jemand die Linkparameter böswillig ändert, wie zum Beispiel: ?via=../../logout, kann es sein, dass sich der Benutzer nach dem Klicken abmeldet Keine Auswirkungen, aber es ist unvermeidlich, dass es andere Operationen geben wird, die unerwartete Auswirkungen haben.

Da Sitesauce an einigen Stellen Alpine verwendet, haben wir das Popup-Fenster darauf basierend in eine Alpine-Komponente geändert, die eine bessere Skalierbarkeit aufweist. Ich möchte Ryan dafür danken, dass er mir wertvolle Ratschläge gegeben hat, als meine Konvertierung nicht richtig funktionierte.

<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 &#39;axios&#39;
import Cookies from &#39;js-cookie&#39;
// 使用模板标签 $nextTick ,进行代码转换,这里特别感谢下我的朋友 Ryan 
window.component = () => ({
    affiliate: null,
    via: new URL(location.href).searchParams.get(&#39;via&#39;)
    init() {
        if (! this.via) return this.$nextTick(() => this.affiliate = Cookies.getJSON(&#39;sitesauce.affiliate&#39;))
        axios.post(`https://app.sitesauce.app/api/affiliate/${encodeURIComponent(this.via)}`).then(response => {
            this.$nextTick(() => this.affiliate = response.data)
            Cookies.set(&#39;sitesauce.affiliate&#39;, response.data, {
                expires: 30, domain: &#39;.sitesauce.app&#39;, secure: true, sameSite: &#39;lax&#39;
            })
        }).catch(error => {
            if (!error.response || error.response.status !== 404) return console.log(&#39;Something went wrong&#39;)
            console.log(&#39;Affiliate does not exist. Register for our referral program here: https://app.sitesauce.app/affiliate&#39;)
        })
    }
})
</script>

Verbessern Sie jetzt die API, damit sie gültige Daten erhalten kann. Darüber hinaus müssen wir auch mehrere Felder zu unserer bestehenden Datenbank hinzufügen, was wir später erläutern werden. Das Folgende ist die Migrationsdatei:

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

Implementieren Sie die Parameterbindung über die Routing-Funktion für benutzerdefinierte Schlüsselnamen (kann auf Laravel 7.X verwendet werden), um unser API-Routing zu erstellen.

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

Bevor Sie mit der Registrierung beginnen, lesen Sie zunächst unser Cookie. Da es nicht verschlüsselt ist, müssen wir es zum Ausnahmefeld von EncryptCookies hinzufügen, um es auszuschließen.

// 中间件: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 = [
        &#39;sitesauce_referral&#39;,
    ];
}

Führen Sie nun die entsprechende Registrierungslogik über die authentifizierte Methode von RegisterController aus. Während dieser Zeit erhalten wir den Cooke über die obige Methode, finden den entsprechenden Vorgesetzten über den Cooke und verknüpfen schließlich den Untergebenen mit dem Vorgesetzten .

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

Wir benötigen außerdem eine Methode, um die Liste meiner untergeordneten Benutzer abzurufen, was leicht durch die hasMany-Methode des ORM erreicht werden kann.

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

Jetzt erstellen wir unsere Registrierungsseite. Wenn sich Benutzer registrieren, können sie die Registerkarte „Einstellungen“ auswählen und von ihnen verlangen, ihre PayPal-E-Mail-Adresse für spätere Auszahlungsvorgänge anzugeben. Das Folgende ist eine Vorschau auf den Effekt:

Nach der Mitgliederregistrierung müssen wir auch die Änderung der E-Mail-Adresse und den entsprechenden Eingang für die Etikettenänderung bereitstellen. Nachdem es seine Bezeichnung geändert hat, müssen wir die Bezeichnungen seiner untergeordneten Benutzer kaskadierend aktualisieren, um die Einheit der beiden sicherzustellen. Dies beinhaltet Datenbanktransaktionsvorgänge. Um die Atomizität des Vorgangs sicherzustellen, müssen wir die beiden oben genannten Vorgänge in der Transaktion abschließen. Der Code lautet wie folgt:

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

Als nächstes müssen wir die Berechnungsmethode für das Mitgliedereinkommen festlegen. Der Prozentsatz aller Verbrauchsbeträge von Benutzern mit niedrigerem Level kann zur Vereinfachung von zurückerstattet werden Bei der Berechnung berechnen wir nur ab dem letzten Abrechnungsdatum. Wir verwenden eine Erweiterung des Prozentpakets von Mattias, um die Berechnungen einfach und unkompliziert zu gestalten.

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, [&#39;created&#39; => [&#39;gte&#39; => optional($this->cashed_out_at)->timestamp]]))
            ->flatten()
            ->map(fn (\Stripe\Invoice $invoice) => $invoice->subtotal)
            ->sum()
    );
}

Abschließend verteilen wir die Provision in Form einer monatlichen Abrechnung an den Vorgesetzten und aktualisieren das Feld „cashed_out_at“ mit dem Zeitpunkt der Provisionsverteilung. Der Effekt ist wie folgt:

An dieser Stelle hoffe ich, dass die oben genannten Dokumente für Sie hilfreich sein werden. Ich wünsche dir jeden Tag Glück.

Empfohlenes Tutorial: „Laravel Tutorial

Das obige ist der detaillierte Inhalt vonEntwickeln Sie ein Mitgliederverteilungssystem basierend auf Laravel. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:learnku.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen