کانال بله, جهت پشتیبانی و اطلاع رسانی کانال بله, جهت پشتیبانی و اطلاع رسانی
عضویت

آموزش Contract ها در لاراول

Contract ها

  1. مقدمه
  2. استفاده از Contract ها چه مزایایی دارد و به چه علت توصیه می شود؟
  3. مرجع Contract ها
  4. نحوه ی استفاده از Contract ها

مقدمه

Contract های لاراول یک مجموعه interface هستند که سرویس های هسته ی فریم ورک لاراول را تعریف می کنند. برای مثال می توان به کانترکت های Illuminate\Contracts\Queue\Queue و Illuminate\Contracts\Mail\Mailer اشاره کرد که هر یک به ترتیب متدهای لازم برای زمان بندی اجرای عملیات (job queue) و ارسال ایمیل ها را برعهده دارند.
هر کانترکت یک پیاده سازی (implementation) متناظر دارد که طبیعتا توسط لاراول در اختیار برنامه نویس قرار داده می شود. به عنوان مثال، لاراول یک پیاده سازی از queue با مجموعه ای از driver ها و یک پیاده سازی از سرویس mailer که توسط SwiftMailer طراحی شده، فراهم می نماید.
لازم به ذکر است که تمامی contract های لاراول در GitHub repository مختص به خود نگهداری می شوند. این امکان نه تنها یک نقطه ی مرجع و قابلیت دسترسی آسان برای کلیه ی contract های موجود مهیا کرده، بلکه آن ها (contract ها) را به صورت یک پکیج کاملا مستقل و مجزا در آورده که به راحتی توسط توسعه دهندگان و package developer ها قابل استفاده می باشد.

Contract در مقابل Facade

Facade ها در چارچوب نرم افزاری لاراول این زمینه را فراهم می کنند تا بدون نیاز به type-hint کردن و دسترسی به Contractها از طریقService Container، از سرویس های این فریم ورک استفاده نمایید. علارغم آنچه گفته شد استفاده از Contract ها به شما اجازه می دهد تاdependency های صریح (explicit) برای کلاس های خود ایجاد کنید.
باید گفت که استفاده از facade ها در بیشتر برنامه ها نیاز شما را برطرف می سازد. اما اگر مایلید از امکان اتصال سست (به انگلیسی loose coupling) که توسط contract ها در اختیار شما قرار داده می شود بهره بگیرید، می بایست مبحث حاضر را ادامه دهید.

استفاده از Contract ها چه مزایایی دارد و به چه علت توصیه می شود؟

ممکن است پرسش های متعددی درباره ی contract ها در ذهن شما شکل گرفته باشد. چرا اصلا باید از interface استفاده کرد؟ آیا استفاده ازinterface ها کار را پیچیده تر نمی کنند؟ در این بخش دلایل استفاده از interface ها را تحت دو عنوان مجزا loose coupling و simplicityمورد بررسی قرار می دهیم.

loose coupling(وابستگی کم)

ابتدا به تشریح کدی که بسیار به یک پیاده سازی cache (cache implementation) وابسته (tightly coupled) می باشد، می پردازیم. کد زیر را درنظر داشته باشید:

<?php
namespace App\Orders;
class Repository
{
   /**
    * The cache instance.
    */
   protected $cache;
   /**
    * Create a new repository instance.
    *
    * @param \SomePackage\Cache\Memcached $cache
    * @return void
    */
   public function __construct(\SomePackage\Cache\Memcached $cache)
   {
       $this->cache = $cache;
   }
   /**
    * Retrieve an Order by ID.
    *
    * @param int $id
    * @return Order
    */
   public function find($id)
   {
       if ($this->cache->has($id))   {
           //
       }
   }
}

در کلاس حاضر همان طور که مشاهده می کنید، کد به پیاده سازی cache بسیار وابسته می باشد. علت اینکه گفته می شود کد بسیار به پیاده سازیcache متصل و وابسته است را می توان در این جمله خلاصه کرد: ما کلاس غیرانتزاعی (از نوع Concrete) Cache خود را از package vendor(ارائه دهنده پکیج) تهیه کرده و مستقیما به آن وابسته هستم. بدین معنی که در صورت تغییر یافتن API پکیج مورد نظر، کد ما نیز باید همراه با آن تغییر کند.
به همین ترتیب اگر بخواهیم تکنولوژی زیرساختی cache خود را (که در این مثال Memcached می باشد) با تکنولوژی دیگر (Redis) جایگزین کنیم، بار دیگر می بایست repository خود را ویرایش کنیم. لازم نیست Repository اطلاعات زیادی مبنی بر اینکه داده ها توسط که یا چگونه در اختیار آن ها قرار می گیرد داشته باشد.
بجای استفاده از این روش، می توانیم کد خود را با بهره گیری از یک interface از نوعvendor agnostic (غیر وابسته به ارائه دهنده) بهبود بخشیده و بهینه تر نماییم:

<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Repository
{
   /**
    * The cache instance.
    */
   protected $cache;
   /**
    * Create a new repository instance.
    *
    * @param Cache $cache
    * @return void
    */
   public function __construct(Cache $cache)
   {
       $this->cache = $cache;
   }
}

اکنون code مورد نظر دیگر به vendor یا ارائه دهنده ی خاصی، حتی لاراول، وابسته و متصل نیست. از آنجایی که پکیج contract ها حاوی هیچdependency و implementation ای نیست، شما به راحتی می توانید یک پیاده سازی جایگزین برای contract دلخواه خود بنویسید. این کار به شما اجازه می دهد پیاده سازی (implementation) cache خود را جایگزین نمایید، آن هم بدون اینکه لازم باشد کدهایی که از cache استفاده می کنند و به آن وابسته هستند را ویرایش نمایید.

Simplicity (سادگی)

به قطع یقیین زمانی که سرویس های Laravel به طور واضح داخل interface هایی تعریف شده باشند، تشخیص کارایی و قابلیت هر یک (سرویس) بسیار آسان تر می شود. Contract ها به عنوان مستنداتی مختصر و صریح برای آشنایی با قابلیت ها و امکانات فریم ورک لاراول ایفای نقش می کنند.
علاوه بر آنچه گفته شد، زمانی که از interface های ساده در کد خود استفاده می کنید متعاقبا فهم و نگهداشت آن کد برای شما آسان تر می شود. بجای اینکه داخل یک کلاس بزرگ و پیچیده بگردید و ببینید که چه متدهایی در اختیار شما قرار دارد، می توانید برای رفع این نیاز به یک interface خوانا و ساده مراجعه نمایید.

مرجع Contract ها

در زیر مرجعی برای بیشتر Contract های لاراول به همراه همتای facade آن ها ارائه شده:

References Facade
Contract
Auth
Illuminate\Contracts\Auth\Guard
Password
Illuminate\Contracts\Auth\PasswordBroker
Bus
Illuminate\Contracts\Bus\Dispatcher
Illuminate\Contracts\Broadcasting\Broadcaster
Cache
Illuminate\Contracts\Cache\Repository
Cache::driver()
Illuminate\Contracts\Cache\Factory
Config
Illuminate\Contracts\Config\Repository
App
Illuminate\Contracts\Container\Container
Cookie
Illuminate\Contracts\Cookie\Factory
Cookie::queue()
Illuminate\Contracts\Cookie\QueueingFactory
Crypt
Illuminate\Contracts\Encryption\Encrypter
Event
Illuminate\Contracts\Events\Dispatcher
Illuminate\Contracts\Filesystem\Cloud
File
Illuminate\Contracts\Filesystem\Factory
File
Illuminate\Contracts\Filesystem\Filesystem
App
Illuminate\Contracts\Foundation\Application
Hash
Illuminate\Contracts\Hashing\Hasher
Log
Illuminate\Contracts\Logging\Log
Mail::queue()
Illuminate\Contracts\Mail\MailQueue
Mail
Illuminate\Contracts\Mail\Mailer
Queue::driver()
Illuminate\Contracts\Queue\Factory
Queue
Illuminate\Contracts\Queue\Queue
Redis
Illuminate\Contracts\Redis\Database
Route
Illuminate\Contracts\Routing\Registrar
Response
Illuminate\Contracts\Routing\ResponseFactory
URL
Illuminate\Contracts\Routing\UrlGenerator
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Validator::make()
Illuminate\Contracts\Validation\Factory
Illuminate\Contracts\Validation\Validator
View::make()
Illuminate\Contracts\View\Factory
Illuminate\Contracts\View\View

نحوه ی استفاده از Contract ها

چگونه می توان به پیاده سازی (implementation) یک contract دسترسی داشت و از آن استفاده کرد؟ بسیار ساده می باشد.
بسیاری از کلاس های Laravel از جمله controller ها، event listener، middleware، queued jobs و route Clousre ها از طریقservice container تهیه شده و در دسترس قرار می گیرد (resolve می شوند). بنابراین برای دسترسی به پیاده سازی یک contract، کافی استinterface مورد نظر را در constructor کلاسی که از طریق container در دسترس قرار می گیرد (resolve می شود)، type hint (اعلان نوع) نمایید.
(در اینجا منظور از فرایند resolve کردن این است که ما به service container می گوییم " Foobar را در اختیار ما قرار بده " و container هم به رجیستری داخلی خود مراجعه کرده و تشخیص می دهد یا درمی یابد (resolve می کند) که دقیقا چه شی ای باید ساخته شود. در زیر تصویری از این پروسه را مشاهده می کنید:

برای مثال می توانید به event listener زیر توجه کنید:

<?php
namespace App\Listeners;
use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;
class CacheUserInformation
{
   /**
    * The Redis database implementation.
    */
   protected $redis;
   /**
    * Create a new event handler instance.
    *
    * @param Database $redis
    * @return void
    */
   public function __construct(Database $redis)
   {
       $this->redis = $redis;
   }
   /**
    * Handle the event.
    *
    * @param NewUserRegistered $event
    * @return void
    */
   public function handle(NewUserRegistered $event)
   {
       //
   }
}

پس از اینکه event listener مورد نظر مشخص (resolve) شد، service container تمامی type-hint های داخل تابع سازنده ی کلاس (constructor) را خوانده و سپس مقادیر مربوطه را تزریق می کند.

1395/02/22 4621 1629
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...