آموزش Bind کردن در Service Container لاراول
در این مقاله قراره بریم با هم روش Bind کردن در Service Container لاراول با هم بررسی کنیم.
Binding ساده
ما برای Binding در لاراول به کلاس Application داخل هسته لاراول نیاز داریم، برای این کار شما میتونید داخل سرویس پروایدر (Service Provider) هاتون از پراپرتی "app$" استفاده کنید.
برای بایند کردن میتونیم از متد bind استفاده کنیم، متد bind از ما یک کلاس یا اینترفیس (interface) میگیره و برای ورودی دوم یک Closure میگیره:
use IlluminateContractsFoundationApplication;
$this->app->bind(DeveloperInterface::class, function (Application $app) {
return new MilwadDeveloper;
});
در این مثال ما اینترفیس DeveloperInterface به کلاس MilwadDeveloper وصل کردیم، یعنی هر بار ما در اپلیکیشن خودمون اینترفیس DeveloperInterface صدا بزنیم کلاس MilwadDeveloper برامون ساخته میشه و برمیگرده.
ممکنه براتون سوال باشه چرا باید این کار کنیم، جلوتر بیشتر توضیح بدم اما در یک کلمه اینکه با به راحتی میتونی کلاس MilwadDeveloper با یک کلاس دیگه عوض کنیم بدون هیچ خطا و مشکلی.
همینطور ما میتونیم به صورت مستقیم با کلاس Application ارتباط برقرار کنیم، فقط کافیه از فساد "App" استفاده کنیم:
use IlluminateSupportFacadesApp;
App::bind(YourClassOrInterface::class, function (Application $app) {
return new YourClassToWantCalled;
});
کار با BindIf
خب با تا الان Bind کردن یاد گرفتیم حالا یک سری متد ها لاراول داره که به ما کمک میکنه راحت تر bind کنیم، یکی از این متد ها bindIf هست. این متد کارش اینه که اگه اون کلاس یا اینترفیس ما قبلا رجیستر نشده باشه میاد bind میکنه، بریم یک مثال ببینیم تا بهتر متوجه بشیم:
$this->app->bindIf(YourClassOrInterface::class, function (Application $app) {
return new YourClassToWantCalled;
});
کار با Singleton Binding
تا به حال با دیزاین پترن singleton کار کردی؟ لاراول در سرویس کانتینر خودش یه همچین قابلیتی داره که یک کلاس یک بار Resolve بشه و دیگه نیاز به resolve شدن نباشه. خب حالا روش کارش چطوره هست؟ خیلی سادس مثل همیشه یک متد داره به نام "singleton" و کافیه مثل بخش Binding باهاش رفتار کنید:
$this->app->singleton(YourClassOrInterface::class, function (Application $app) {
return new YourClassToWantCalled;
});
همینطور با یک متدی به نام "singletonIf" داریم که مثل bindIf عمل میکنه:
$this->app->singletonIf(YourClassOrInterface::class, function (Application $app) {
return new YourClassToWantCalled;
});
کار با Binding Scoped Singletons
در بخش بعدی با متد جدیدی به نام "scope" آشنا میشیم. این متد مثل متد "singleton" رفتار میکنه اما با این تقاوت اینکه اما با درخواست جدید از سمت لاراول، binding ها پاک میشن. ممکنه منظور از درخواست جدید از سمت لاراول متوجه نشید اما من براتون توضیح میدم. درخواست جدید به این معنی هست که مثلا Laravel Octane یک ریکويست جدید براش ارسال بشه یا Queue ها روی یک جاب کار کنند میشه درخواست جدید. حالا بریم ببینیم چطور میشه باهاش کار کرد:
$this->app->scoped(YourClassOrInterface::class, function (Application $app) {
return new YourClassToWantCalled;
});
کار با Binding Interfaces to Implementations
این قابلیت بهترین قابلیت سرویس کانتیر لاراول هست که بالا بهش اشاره کردم اینجا بیشتر براتون توضیح میدم. یکی از اهداف استفاده از سرویس کانتیر لاراول این هست که بتونیم به سادگی سرویس ها جا به جا کنیم، برای بهتر متوجه شدن این موضوع بریم یک مثال ببینیم و بیشتر صحبت کنیم:
$this->app->bind(Gateway::class, ZarinpalGateway::class);
در این مثال با اینترفیس Gateway به کلاس ZarinpalGateway وصل کردیم، حالا ما هر جای از برنامه اینترفیس Gateway صدا بزنیم کلاس ZarinpalGateway به ما برمیگردونه. شاید در نگاه اول بگید خب این چه کار بیهوده ای هست، به جای مستقیم کلاس ZarinpalGateway صدا بزنیم، اما این یک اشتباهه در واقعه، چون در آینده ممکن هست درگاه پرداخت شما از زرین پال به پی پینگ عوض بشه اون موقع نیاز هست کل برنامه اتون رو تغییر بدید و این اصل Open-Close Principle اصول سالید رو نقض میکنه.
حالا چطور ما میتونیم از کلاس Gateway استفاده کنیم؟ خیلی ساده با استفاده از Automate Injection خوده لاراول:
/**
* Create a new class instance.
*/
public function __construct(
protected Gateway $gateway // ZarinpalGateway
) {}
کار با Contextual Binding
این قابلیت واقعا خفنههههه. فرض کنید دو یا .. کلاس دارید که از یک اینترفیس استفاده میکنند اما شما میخواید مشخص کنید یک کلاس زمانی که از این اینترفیس استفاده میکنه یه سرویس دیگه برگردونه و یک کلاس دیگه یک سرویس دیگه! بریم یک مثال بزنیم تا بهتر متوجه بشیم. فرض کنید با دو تا کنترلر داریم یکی به نام PhotoController و اون یکی به نام VideoController. ما میخوایم بگیم که PhotoController بیاد از درایور dropbox
استفاده کنه همینطور VideoController از درایور s3 استفاده کنه. خب این قابلیت به صورت عادی نشدنی هست ولی لاراول یک راه کار خیلی زیبا و خفن جلو پای ما قرار داده:
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('dropbox');
});
$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});
در واقع هر موقع در داخل PhotoController از اینترفیس FileSystem استفاده کنیم برای ما به صورت اتوماتیک درایور dropbox ست میشه و برای VideoController درایور s3.
کار با Binding Primitives
ما میتونیم کار کنیم که بگیم زمانی که یک کلاس به یه متغیر خاصی (که کدوم مشخص میکنیم) نیاز داره بیا این مقدار بده و به راحتی میتونیم اینها مدیریت کنیم، بریم یه مثال ببینیم:
$this->app->when(ProductService::class)
->needs('$variableName')
->give($value);
در این مثال ما گفتیم زمانی که ProductService به متغیر نیاز داشت به یه مقدار بده حالا میتونی این مقدار خودمون مشخص کنیم چی باشه.
همینطور با یک متدی داریم به نام giveConfig که به صورت مستیقیم میره از کانفیگ دیتا به متغیر میده:
$this->app->when(AuthService::class)
->needs('$token')
->giveConfig('app.token');
کار با Binding Typed Variadics
بعضی اوقات شما میخواید یک آرایه از کلاس رو به سرویس یا ... بفرستید، لاراول این امکان مشخص کرده برای مثال فرض کنید یک کلاس User دارید و در داخل اون میخواید دولوپر ها رو بگیرید:
<?php
class User
{
/**
* Create a new class instance.
*/
public function __construct(
protected Developer ...$developers,
) {}
}
حالا کافیه شما توی سرویس پروایدر بیاید از کلاس ها بفرستید داخل یک آرایه:
$this->app->when(User::class)
->needs(Developer::class)
->give([
MilwadDeveloper::class,
TaylorDeveloper::class,
HrkDeveloper::class,
]);
کار با Tagging
بعضی اوقات نیاز دارید یک یک دسته بندی درست کنید و اون رو برام تزریق وابستگی و.. بفرستید، برای این کار میتونید از قابلیت Tagging استفاده کنید در لاراول:
$this->app->tag([RedisLogger::class, DataLogger::class], 'loggers');
$app->tagged('loggers'); // Array of loggers
کار با Extending Bindings
بعضی اوقات نیاز دارید که بعد از Resolve شدن کلاس بیاید یک سری کانفیگ و تغییرات (Decorate) بدید، برای این کار میتونید از متد "extend" استفاده کنید:
$this->app->extend(Service::class, function (Service $service, Application $app) {
return new DecoratedService($service);
});
متد extend یک کلاس و یک Closure میگیره که در Closure کلاس ما در دسترسی هست.
دوره های مرتبط
ما در پرانتز یک سری دوره های مربوط به Service Container و اصول SOLID در لاراول داریم که اگه دوست داشتید میتونید اونها ببینید و در مصاحبه ها به راحتی قبول بشید:
0 نظر