Saya menggunakan Laravel 6.9.0. Ini adalah pengontrol pembayaran saya:

class PaymentController extends Controller
{
    public function __construct(){
        $this->middleware('payment.test');
        $this->middleware('payment.check');
    }

    public function pay(){
        $this->payment->pay();
    }

    public function refund(){
        $this->payment->refund();
    }

    public function checkOrder(){
        $this->payment->checkOrder();
    }
}

Middleware payment.test melakukan ini:

  1. tulis log permintaan
  2. periksa apakah pedagang itu ada
  3. permintaan dekripsi

Middlware payment.check digunakan untuk memeriksa pembayarannya, seperti applepay atau googlelpay.

Tetapi dari dokumentasi resmi, middleware digunakan untuk memfilter permintaan HTTP, memverifikasi bahwa pengguna aplikasi Anda diautentikasi.

Sepertinya payment.check bukan milik ini. Jadi, saya mengubah middleware payment.check ke controller. Karena semua metode harus memeriksa pembayaran, saya memasukkannya ke konstruktor. Namun, saya harus mendekripsi permintaan sebelum saya memeriksanya, jadi konstruktor saya sekarang adalah

$this->middleware('payment.test');

$this->middleware(function ($request, $next) {
    $this->checkPayment($request);

    return $next($request);
});

checkPayment terlihat seperti ini:

private function checkPayment($request){
    if($request->aaa == 'aaa'){
        switch($request->type){
            case '001':
                $type = 'apple';
                break;
            case '111':
                $type = 'google';
                break;
            ...

        }
    }else{
        switch($request->code){
            case 'android':
                $type = 'android';
                break;
            ...
        }
    }


    $this->payment = app($type);
}

Itu membuat pengontrol saya jelek. Saya merasa menulisnya ke middleware terlihat lebih modular dan jelas. Apakah menulisnya ke controller benar-benar lebih baik daripada middleware? Atau ada saran lain?

1
patrick 11 April 2020, 23:02

1 menjawab

Jawaban Terbaik

Seperti yang saya lihat, seluruh masalah Anda adalah, untuk membuat instance implementasi yang benar meskipun logika Anda melakukannya pada akhirnya dengan memanggil $this->payment = app($type);. Konsep inti masih dalam konteks ini, penyedia mana yang Anda butuhkan. Ada banyak opsi untuk ini, layanan, pabrik, dll. Tetapi untuk melakukan versi penyedia kontainer ini, sangat kuat dan bersih ketika Anda berada di Laravel.

Bayangkan memiliki PaymentProviderInterface Anda, saya akan mengikat ini untuk menyelesaikan penyedia pembayaran mana yang akan digunakan. Gabungkan dengan itu Anda dalam konteks apa pun dapat menyelesaikan objek permintaan dan Anda dapat memindahkan semua ini ke penyedia, saya akan membuat yang baru. PaymentProvider dan daftarkan sebagai penyedia lainnya.

class PaymentsProvider {
    public const APPLE_PAYMENT_PROVIDER = 'apple';

    public const GOOGLE_PAYMENT_PROVIDER = 'google';

    public const ANDROID_PAYMENT_PROVIDER = 'android';

    public function boot() {
        $this->app->bind(PaymentProviderInterface::class, function () {
           /** @var Request $request **/
           $request = resolve(Request::class);

           $type = null;

           if($request->aaa == 'aaa') {
               $type = $this->resolvePaymentByType($request->type);
           } else {
               $type = $this->resolvePaymentByCode($request->code);
           }

           return resolve($type);
        });
    }

    private function resolvePaymentByType(string $type): string
    {
        if ($type === '001') {
            return static::APPLE_PAYMENT_PROVIDER;
        }

        if ($type === '111') {
            return static::GOOGLE_PAYMENT_PROVIDER;
        }

        throw new Exception('Invalid state');
    }

    private function resolvePaymentByCode(string $code): string
    {
        if ($type === static::ANDROID_PAYMENT_PROVIDER) {
            return static::ANDROID_PAYMENT_PROVIDER;
        }

        throw new Exception('Invalid state');
    }
}

Secara umum saya tidak suka kasus sakelar, Anda dapat menggunakannya jika Anda suka, saya pikir ini lebih bersih. Pengoptimalan kecil lainnya alih-alih memiliki string ajaib menggunakan konstanta, itu lebih mudah dibaca dan memiliki banyak keuntungan. Karena kami mengikat semuanya ke PaymentProviderInterface, ini akan membuat pengontrol Anda benar-benar bersih dengan menyelesaikan penyedia Anda seperti ini. Untuk menghindari kondisi di mana Anda tidak memiliki permintaan, saya akan menyuntikkan di setiap metode.

class PaymentController extends Controller
{
    public function pay(PaymentProviderInterface $payment){
        $payment->pay();
    }
0
mrhn 12 April 2020, 12:48