مدیریت وابستگی ها در لاراول – آموزش لاراول

  • یکشنبه ۱۲ دی ۱۴۰۰
  • بازدید ۱۲,۰۱۷ نفر

تصویر laravel-service-container_11475 مدیریت وابستگی ها در لاراول - آموزش لاراول

مدیریت وابستگی ها در لاراول

در فریم ورک لاراول از ابزاری به نام Service Container به منظور مدیریت وابستگی ها و تزریق وابستگی ها استفاده می شود. تزریق وابستگی یعنی: وابستگی های یک کلاس از طریق سازنده (در برخی موارد از طریق از متدهای “setter”) به کلاس تزریق می شود. برای درک بهتر به مثال ساده زیر توجه کنید:

در مثال فوق UserController نیاز دارد تا اطلاعات کاربران را از یک منبع داده دریافت کند. بنابراین یک سرویسی که می تواند اطلاعات کاربران را در اختیارش بگذارد به آن تزریق شده است. در این نمونه سرویس UserRepository اغلب از Eloquent برای گرفتن اطلاعات کاربران از دیتابیس استفاده می کند اما چون سرویس UserRepository به این کلاس تزریق شده است به راحتی می توانیم آن را با پیاده سازی دیگری از سرویس که از منبع داده دیگری استفاده می کند، جایگزین کنیم. برای مثال در هنگام تست کردن پروژه به جای این که با دیتابس واقعی کار کنیم، می توانیم یک نمونه فیک از سرویس UserRepository ایجاد کرده و استفاده کنیم.

یادگیری عمیق Service Container و درک نحوه عملکرد آن در لاراول برای ساختن یک برنامه قدرتمند، بزرگ ضروری است.

در اکثر مواقع فقط با نوشتن نوع سرویس، آن سرویس به کلاس یا متد تزریق می شود و لازم نیست Service Container را برای چگونگی تزریق آن تنظیم کنید. برای مثال ممکن است در تعریف یک مسیر به یک نمونه از شیء Illuminate\Http\Request نیاز داشته باشید. برای دسترسی به آن کافیست مانند نمونه زیر یک ورودی از نوع Request تعریف کنید و Service Container به صورت خودکار آن را تزریق خواهد کرد.

اغلب به لطف تزریق خودکار و facade ها می توانید یک برنامه کامل را بدون نیاز به تنظیم دستی نحوه تزریق وابستگی ها در Service Container ایجاد کنید. با وجود موارد گفته شده شاید این سوال پیش آید: پس چه موقع باید آن را به صورت دستی تنظیم کنیم؟ در این مواقع:

  1. زمانی که کلاسی دارید که یک اینترفیس را پیاده سازی کرده است و در کلاسی دیگر می خواهید یک نمونه از آن اینترفیس را تزریق کنید، باید به Service Container بگید که چگونه باید یک نمونه از آن اینترفیس را ایجاد کند. زیرا ممکن است چندین پیاده سازی از یک اینترفیس وجود داشته باشد.
  2. زمانی که یک بسته برای لاراول می نویسید و می خواهید آن بسته را با سایر توسعه دهنده ها به اشتراک بگذارید، باید سرویس های مربوط به بسته خود را در Service Container ثبت کنید.

بایند کردن (Binding)

بایند کردن ساده

تقریبا تمام موارد مربوط به بایند کردن سرویس ها و تنظیم Service Container در داخل ارائه دهندگان سرویس انجام می شود. در داخل یک ارائه دهنده سرویس با استفاده از $this->app می توانید به Container دسترسی داشته باشید. برای تنظیم یک سرویس در داخل Container از متد bind استفاده می شود. این متد دو ورودی دارد که اولی نام کلاس یا اینترفیس و دومی نحوه resolve کردن آن کلاس یا اینترفیس است. برای نمونه:

توجه داشته باشید که در داخل خود resolver هم به container دسترسی داریم (از طریق آرگومان $app). در نتیجه می توانیم با استفاده از وابستگی های مورد نیاز کلاس اصلی را دریافت کنیم. در نمونه فوق کلاس Transistor به کلاس PodcastParser وابستگی دارد و با استفاده از Container نمونه ای از آن برای خود ایجاد می کند. همانطور که گفته شد در اغلب موارد تعامل شما با Service Container در داخل ارائه دهندگان سرویس خواهد بود. با این حال اگر لازم داشتید می توانید مانند نمونه زیر با استفاده از App که یک facade است، سرویس های خود را در خارج از ارائه دهندگان سرویس تنظیم کنید:

توجه داشته باشید که اگر کلاسی به هیچ اینترفیسی وابستگی ندارد، لازم نیست آن را در Container بایند کنید چون فقط یک نوع از آن تعریف شده است و Container می تواند با استفاده از قابلیت reflection از آن ها نمونه سازی کند.

بایند کردن Singleton

متد singleton برای بایند کردن کلاس یا اینترفیسی استفاده می شود که فقط یک نمونه از آن باید ایجاد شود. به عبارت دیگر یک نمونه ایجاد می شود و اگر در جای دیگر لازم بود از همان نمونه قبلی استفاده می شود. نحوه استفاده از آن به این شکل است:

بایند کردن Scoped Singleton

متد scoped برای بایند کردن کلاس یا اینترفیسی استفاده می شود که فقط باید یک نمونه از آن در طول یک محدوده خاص ایجاد شود. در لاراول این محدوده طول عمر یک request یا job است. کلاس ها یا اینترفیس هایی که با استفاده از این متد بایند شوند، در هنگام دریافت درخواست جدید دوباره نمونه سازی می شوند. به عبارت ساده تر محدود به پردازش یک درخواست هستند. نحوه استفاده از آن به این شکل است:

بایند کردن نمونه ها

با استفاده از متد instance می توانید یک نمونه از قبل ایجاد شده را بایند کنید. با این کار هر زمان که آن سرویس درخواست شود، نمونه بایند شده بازگشت داده می شود. نحوه استفاده از آن به این شکل است:

بایند کردن اینترفیس به پیاده سازی

یکی از ویژگی های Service Container امکان بایند کردن یک اینترفیس به یک پیاده سازی خاص است. برای مثال فرض کنید یک اینترفیس با نام EventPusher و یک پیاده سازی از آن با نام RedisEventPusher داریم. با استفاده از متد bind می توانیم آن را مانند نمونه زیر در Container ثبت کنیم:

با این کار به Container می گویم که هر موقع به یک پیاده سازی از EventPusher نیاز داشتیم، یک نمونه از RedisEventPusher را تزریق کند. مثال:

بایند کردن شرطی

گاهی اوقات ممکن است از یک اینترفیس پیاده سازی های مختلفی داشته باشید و در جای های مختلف بخواهید از پیاده سازی های خاصی استفاده کنید. برای مثال ما کنترلرهایی با نام های PhotoController، VideoController و UploadController داریم که همه آن ها به Illuminate\Contracts\Filesystem\Filesystem وابستگی دارند. حال فرض کنید می خواهیم PhotoController از درایور local استفاده کند و بقیه از s3. برای اینکار می توانیم از قابلیت Contextual Binding مانند نمونه زیر استفاده کنیم:

گاهی اوقات ممکن است کلاسی داشته باشید که به یک مقدار خاص مثلا از نوع integer وابستگی داشته باشد. برای تزریق این وابستگی می توانید از Contextual Binding مانند نمونه زیر استفاده کنید:

همچنین ممکن است گاهی اوقات کلاسی داشته باشید که به آرایه ای از نمونه های برچسب خورده (Tagged Instances) وابستگی داشته باشد. با استفاده از متد giveTagged می توانید نمونه هایی را که برچسب خاصی دارند را تزریق کنید. برای مثال:

اگر نیاز داشتید که مقداری را از تنظیمات برنامه تزریق کنید به راحتی می توانید با استفاده از متد giveConfig این کار را انجام دهید:

بایند کردن ورودی از نوع Variadics

گاهی اوقات ممکن است کلاسی داشته باشید که با استفاده از سازنده variadic آرایه ای از اشیاء را به عنوان ورودی بگرید. برای مثال:

با استفاده از قابلیت Contextual Binding و متد give می توانیم این نوع وابستگی را نیز تزریق کنیم. برای نمونه:

کد فوق را به شکل زیر هم می توان نوشت:

برچسب زدن

گاهی اوقات ممکن است نیاز داشته باشید که سرویس های خاصی را دسته بندی کنید. فرض کنید می خواهید یک سرویس گزارش دهی ایجا کنید و پیاده سازی های مختلفی از اینترفیس Report را در Container ثبت کرده اید:

بعد از ثبت آن ها می توانید با استفاده از متد tag بر روی آن ها برچسب بزنید. برای مثال دسته reports:

با این کار هر زمان که به پیاده سازی های فوق نیاز داشتید، می توانید با استفاده از متد tagged آن ها را دریافت کنید. برای نمونه:

به عبارت ساده تر با استفاده از قابلیت برچسب زدن می توانید سرویس های مختلف را دسته بندی کنید.

متد extend

این متد امکان اعمال تغییرات بر روی سرویس های resolve شده را فراهم می کند. برای مثال زمانی که یک سرویس resolve می شود ممکن است بخواهید قبل از رسیدن به دست درخواست کننده، تغییراتی بر روی آن اعمال کنید. متد extend یک closure به عنوان ورودی می گیرد که باید نسخه تغییر یافته سرویس را بازگرداند. این closure سرویس resolve شده و نمونه ای از Service Container را به عنوان ورودی دریافت می کند:

متد make

متد make به منظور resolve کردن نمونه ای از یک کلاس از Container استفاده می شود. این متد نام کلاس یا اینترفیس را عنوان ورودی می گیرد و نمونه ای از آن را باز میگرداند:

اگر سرویس مورد نظر برای نمونه سازی نیاز به ورودی خاصی داشته باشد می توانید از متد makeWith مانند نمونه زیر استفاده کنید:

همانطور که قبلا هم گفتیم برای دسترسی به Service Container در جایی که به آن به صورت $app دسترسی ندارید، می توانید از facade آن مانند نمونه زیر استفاده کنید:

اگر در داخل کلاسی به خود Container نیاز داشتید می توانید مانند سرویس های دیگر آن را تزریق کنید. مثال:

فراخوانی متد و تزریق

گاهی اوقات ممکن است بخواهید یک متد از یک نمونه (شیء) را فراخوانی کنید در حالی که لازم دارید تا وابستگی های مورد نیازش نیز تزریق شود. برای مثال:

برای اینکار می توانید مانند نمونه زیر از متد App::call استفاده کنید:

متد call می تواند وابستگی های مورد نیاز یک closure را نیز resolve کند. برای مثال:

رویدادهای Container

در لاراول Service Container هر زمان که یک سرویس را resolve می کند، یک رویداد را به اصطلاح fire می کند. برای گوش دادن به این رویداد می توانید مانند نمونه زیر از متد resolving استفاده کنید:

ثبت نظر
ریفریش کنید!
نظرات کاربران (۰ مورد)

هیچ نظری ثبت نشده است