Fitur Middleware dan Pipeline di Laravel



Laravel adalah sistem yang benar-benar besar dan kompleks yang mencoba menyelesaikan sebagian besar tugas sehari-hari seorang pengembang web dengan cara yang paling elegan dan mengumpulkan sebanyak mungkin alat dan, yang sangat penting, dengan sebanyak mungkin antarmuka manusia.

Dan hari ini kita akan fokus pada salah satu alat ini, atau lebih tepatnya pada penggunaan dan implementasinya oleh programmer. Kurangnya dokumentasi lengkap, serta kurangnya artikel berbahasa Rusia dan sangat sedikit artikel asing, mendorong saya untuk memutuskan untuk mengungkapkan tabir kerahasiaan tertentu tentang fitur menarik kerangka kerja ini dan memilih topik ini sebagai artikel pertama saya tentang Habré.

Middleware


Artikel ini mengasumsikan bahwa pembaca sudah terbiasa dengan penggunaan dasar fungsi kerangka ini, jadi saya tidak akan membahas hal ini untuk waktu yang lama.

Di luar kotak, Laravel memberi kami fungsionalitas yang cukup kuat untuk memfilter permintaan HTTP yang masuk ke aplikasi kami. Kita berbicara tentang Middleware yang dicintai semua orang (atau tidak) - pengembang menjumpai kelas-kelas ini dengan cepat dalam penguasaan Laravel, sambil membaca bagian “Dasar-Dasar” dari dokumentasi resmi, dan ini tidak mengejutkan - Middleware adalah salah satu yang utama dan paling penting batu bata atas dasar di mana seluruh sistem dibangun.

Contoh kasus standar pengguna komponen ini di Laravel adalah: EncryptCookies / RedirectIfAuthenticated / VerifyCsrfToken , dan sebagai contoh implementasi kustom, Anda dapat mengutip lokalisasi aplikasi middleware (mengatur lokalisasi yang diperlukan berdasarkan pada data permintaan tertentu) sebelum mentransfer permintaan lebih lanjut.

Lebih dalam ke jurang


Putuskan harapan semua orang yang datang ke sini


Nah, sekarang setelah poin utama selesai - kita bisa menyelidiki tempat yang mengerikan bagi banyak orang - dalam alfa dan omega, awal dan akhir - dalam sumber Laravel . Mereka yang berusaha segera menutup artikel - luangkan waktu Anda. Bahkan, dalam kode sumber kerangka kerja ini hampir tidak ada yang benar-benar rumit dari sisi konseptual - pencipta jelas berusaha tidak hanya untuk membuat antarmuka yang jelas dan nyaman untuk bekerja dengan gagasan mereka, tetapi mereka juga sangat berusaha melakukan hal yang sama secara langsung pada tingkat kode sumber, yang tidak dapat tidak untuk menyenangkan.

Saya akan mencoba menjelaskan konsep tentang bagaimana Middleware dan Pipeline bekerja pada tingkat kode dan logika sesederhana dan dapat diakses mungkin, dan saya akan mencoba untuk tidak masuk ke dalamnya - di mana itu tidak perlu dalam kerangka artikel. Jadi, jika di komentar ada orang yang tahu semua baris kode sumber dengan hati - saya meminta Anda untuk tidak mengkritik narasi dangkal saya. Tetapi setiap rekomendasi dan koreksi ketidakakuratan hanya diterima.

Middleware - melintasi barikade


Saya percaya bahwa belajar apa pun selalu lebih mudah ketika diberikan contoh yang baik. Karena itu, saya mengundang Anda dan saya untuk mempelajari binatang misterius ini dengan nama Pipeline . Jika para pemberani seperti itu benar-benar ada, maka sebelum membaca lebih lanjut kita perlu menginstal proyek Laravel kosong versi 5.7 - versi ini hanya disebabkan oleh fakta bahwa itu adalah yang terakhir pada saat penulisan, semua hal di atas harus identik setidaknya untuk versi 5.4. Mereka yang hanya ingin mengetahui esensi dan kesimpulan artikel dapat dengan aman melewati bagian ini.

Apa yang bisa lebih baik daripada mempelajari perilaku komponen, kecuali mempelajari perilaku yang sudah ada di dalam sistem? Mungkin sesuatu dapat, tetapi kami akan melakukannya tanpa komplikasi yang tidak perlu dan memulai analisis kami dengan standar Middleware - yaitu, dengan yang paling sederhana dan paling dapat dipahami dari seluruh geng - RedirectIfAuthenticated :

RedirectIfAuthenticated.php
class RedirectIfAuthenticated { /**      * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param string|null $guard * @return mixed */ public function handle($request, Closure $next, $guard = null) { if (Auth::guard($guard)->check()) { return redirect('/'); } return $next($request); } } 


Di kelas middleware klasik mana pun, ada metode utama yang harus secara langsung memproses permintaan dan meneruskan pemrosesan ke yang berikutnya dalam rantai - dalam kasus kami, ini adalah metode pegangan . Di kelas khusus ini, pemrosesan permintaan cukup sederhana - "jika pengguna diotorisasi, kemudian arahkan dia ke halaman utama dan, dengan demikian, mengakhiri rantai."

Jika kita melihat pendaftaran Middleware ini di app / Http / Kernel.php , kita akan melihat bahwa itu terdaftar di 'route middleware'. Agar kami dapat mengetahui cara kerja sistem dengan middleware ini, mari kita pergi ke kelas dari mana aplikasi / Http / Kernel kita mewarisi - dan itu mewarisi dari kelas Illuminate \ Foundation \ Http \ Kernel . Pada tahap ini, kita akan langsung membuka gerbang ke neraka kode sumber kerangka kerja kita, atau lebih tepatnya, ke bagian paling penting dan utama darinya - ke inti bekerja dengan HTTP. Ngomong-ngomong, siapa yang peduli - Laravel didasarkan pada banyak komponen Symfony , khususnya di bagian ini - pada HttpFoundation dan HttpKernel .

Definisi dan implementasi middleware kami di konstruktor kernel adalah sebagai berikut:

Illuminate \ Foundation \ Http \ Kernel (Aplikasi $ app, Router $ router)
  /**    HTTP Kernel . * Create a new HTTP kernel instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @param \Illuminate\Routing\Router $router * @return void */ public function __construct(Application $app, Router $router) { $this->app = $app; $this->router = $router; $router->middlewarePriority = $this->middlewarePriority; foreach ($this->middlewareGroups as $key => $middleware) { $router->middlewareGroup($key, $middleware); } foreach ($this->routeMiddleware as $key => $middleware) { $router->aliasMiddleware($key, $middleware); } } 


Kode ini cukup sederhana dan mudah - untuk setiap middleware dalam array kami mendaftarkannya dengan alias / indeks di router kami. Metode aliasMiddleware dan middlewareGroups dari kelas Route kami hanya menambahkan middleware ke salah satu array dari objek router. Tetapi ini tidak termasuk dalam konteks artikel, jadi kami akan melewatkan momen ini dan melanjutkan.

Yang benar-benar kami minati adalah metode sendRequestThroughRoute , yang secara harfiah menerjemahkan cara mengirim Permintaan melalui Rute :

Illuminate \ Foundation \ Http \ Kernel :: sendRequestThroughRouter ($ request)
  /**     middleware / router. * Send the given request through the middleware / router. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ protected function sendRequestThroughRouter($request) { // *    * return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); } 


Sebagai parameter, metode ini menerima permintaan. Pada titik ini, kita harus melihat kembali kode RedirectIfAuthenticated kami. Kami juga mendapatkan permintaan dalam metode pegangan middleware kami, kami akan membutuhkan catatan ini nanti.

Kode di atas memiliki antarmuka yang sangat jelas dan mudah dibaca - "Pipeline", yang mengirimkan permintaan melalui masing-masing middleware terdaftar, dan kemudian "mentransfer" ke router . Menawan dan indah. Saya pikir pada tahap ini kami tidak akan mencoba untuk menguraikan bagian kode ini lebih lanjut, saya hanya akan menjelaskan secara singkat peran bagian ini dalam keseluruhan sistem:

Sebelum permintaan masuk ke pengontrol Anda, banyak tindakan dilakukan, mulai dari hanya mengurai url itu sendiri, dan diakhiri dengan inisialisasi kelas Permintaan . Middleware juga terlibat dalam rantai aksi ini. Kelas middleware sendiri menerapkan (hampir) pola perancangan Chain of Responsibility , atau Chain of Responsibility , sehingga setiap kelas midleware konkret hanyalah tautan dalam rantai.

Di atas, kami tidak hanya kembali ke kelas RedirectIfAuthenticated kami yang semula dianggap. Permintaan "beredar" di sepanjang rantai, termasuk yang melewati semua yang diperlukan untuk rute middleware. Momen ini akan membantu kita bekerja dengan tautan kita sendiri dalam rantai kita sendiri, lebih lanjut tentang itu nanti.

Pipeline - menyalurkan aplikasi kita


Salah satu contoh implementasi Pipeline yang kami lihat di atas. Tetapi tujuan artikel ini bukan hanya untuk menjelaskan operasi komponen ini pada tingkat integrasi dengan Laravel, tetapi juga untuk menjelaskan prinsip dasar bekerja dengan kelas ini dalam kode kita sendiri.

Kelas itu sendiri dapat ditemukan dengan definisi lengkapnya dengan namespace:
Menerangi \ Pipeline \ Pipeline

Mungkin ada cukup banyak aplikasi untuk komponen ini, tergantung pada tugas khusus yang harus Anda selesaikan, tetapi salah satu motivasi yang paling jelas adalah persyaratan untuk membuat rantai penangan permintaan Anda sendiri, yang tidak mengganggu proses seluruh sistem dan ditentukan secara eksklusif pada tingkat logika bisnis Anda. Juga, antarmuka kelas memiliki tingkat abstraksi yang cukup dan memiliki fungsi yang cukup untuk mengimplementasikan berbagai jenis antrian.

Contoh implementasi di Laravel


Kami menerapkan rantai kueri yang paling sederhana dan jauh dari kenyataan. Kami akan menggunakan string "HELLO WORLD" sebagai data, dan dengan bantuan dua penangan, kami akan membentuk string "Halo Pengguna" darinya. Kode ini sengaja disederhanakan.

Sebelum implementasi "Pipa" kita sendiri, kita perlu mengidentifikasi elemen-elemen dari pipa ini. Elemen ditulis dengan analogi dengan middleware:

Menentukan Penangan
StrToLowerAction.php:
 use Closure; class StrToLowerAction { /** * Handle an incoming request. * * @param string $content * @param Closure $next * @return mixed */ public function handle(string $content, Closure $next) { $content = strtolower($content); return $next($content); } } 

SetUserAction.php:

 use Closure; class SetUserAction { /** * Handle an incoming request. * * @param string $content * @param Closure $next * @return mixed */ public function handle(string $content, Closure $next) { $content = ucwords(str_replace('world', 'user', $content)); return $next($content); } } 


Lalu kami membuat "jalur pipa", menentukan jenis data apa yang ingin kami kirimkan, menentukan melalui kumpulan prosesor mana kami ingin mengirim data ini, dan juga menentukan panggilan balik, yang menerima sebagai argumen data kami melewati seluruh rantai. Jika data di seluruh rantai tetap tidak berubah, bagian dengan panggilan balik dapat dihilangkan:

 $pipes = [ StrToLowerAction::class, SetUserNameAction::class ]; $data = 'Hello world'; $finalData = app(Pipeline::class) ->send($data) // ,       ->through($pipes) //   ->then(function ($changedData) { return $changedData; //  ,    }); var_dump($finalData); //      $finalData 

Juga, jika Anda memiliki keinginan atau kebutuhan untuk mendefinisikan metode Anda sendiri dalam penangan, antarmuka Pipeline menyediakan metode khusus via ('method_name') , maka pemrosesan rantai dapat ditulis dengan cara ini:

 $finalData = app(Pipeline::class) ->send($data) ->through($pipes) ->via('handle') //      ,         ->then(function ($changedData) { return $changedData; }); 

Secara langsung, data yang kami lewati prosesor dapat berupa apa saja, serta interaksi dengan mereka. Mengetik petunjuk dan mengatur tipe objek yang dikembalikan dalam rantai akan membantu menghindari kesalahan integritas data.

Kesimpulan


Laravel menyediakan sejumlah besar kelas bawaan, dan fleksibilitas banyak dari mereka memungkinkan kami untuk mengembangkan sesuatu yang kompleks dengan kesederhanaan yang cukup. Artikel ini membahas kemungkinan membuat antrian sederhana untuk permintaan berdasarkan kelas Pipeline yang dibangun ke Laravel. Implementasi kelas ini dalam kode final bisa sangat berbeda, dan fleksibilitas alat ini memungkinkan Anda untuk menyingkirkan banyak tindakan yang tidak perlu saat membangun algoritma tertentu.

Cara khusus menggunakan fitur kerangka kerja ini tergantung pada tugas yang diberikan kepada Anda.

Source: https://habr.com/ru/post/id429214/


All Articles