در این مقاله میخواهم کاربرد و نحوهی استفاده از دیزاین پترن Repository را در لاراول را توضیح دهم.
مشکل: فرض کنید شما یک سایت نوبت دهی برای بیماران دارید، شما یک جدول دارید به نام users که اطلاعات بیمار و پزشک را در آن ذخیره میکنید و تنها از طریق نقش آنها میتوانید تفاوت بیمار و پزشک را تشخیص دهید. شما برای هر کاربر (بیمار و پزشک) یک کنترلر در سمت کاربر نیاز دارید حتی یک کنترلر هم سمت پنل ادمین، شاید حتی بخواهید صفحهی ورود و ثبت نام متفاوت هم داشته باشید در این صورت احتمالا به دلیل اینکه هر دو کاربر در یک جدول ذخیره میشوند خیلی از کدهای شما تکراری میشود و خوانایی کد شما پایین میآید، در اینجا الگوی طراحی repository به کمک شما میآید و خوانایی کدهای شما را بهتر میکند.
در اینجا من دو کنترلر از نوع resource دارم که یکی مربوط به پزشک و دیگری مربوط به بیمار میباشد.
حال میخواهم برای این کنترلرهای خود متودهای لازم را بنویسم، توجه داشته باشید که موجودیت هر دو کاربر یکی میباشد یعنی هر دو از نوع users میباشند مثلا برای هردو کاربر متودی برای تغییر آواتار لازم داریم که برای هردو یک کار را انجام میدهد لذا برای برای جلوگیری از تکرار کدها و خوانایی بالاتر من یک repository برای کاربران خود ایجاد میکنم و تمامی متودهای لازم را در آن قرار میدهم و تنها از آنها در هر کنترلری که بخواهم استفاده میکنم، اینجوری تمامی متودهای مربوط به user ها در یکجا قرار میگیرد و ما لازم نیست در کنترلرهای متفاوت دنبال آن بگردیم.
در ابتدا میخواهم یک interface ایجاد بکنم پس یک پوشه برای interface های خود در مسیر App/Http ایجاد میکنم (شما میتوانید این پوشه را به دلخواه خود در هر مسیری که دوست داشتید ایجاد کنید) سپس یک interface به نام UserRepositoryInterface درون آن ایجاد میکنم.
حال متودهایی که لازم دارم را درون آن تعریف میکنم.
حالا من در مسیر App/Http یک abstrac class ایجاد میکنم که implement شده از interface بالا (البته این بخش رو من خودم اضافه کردم شما میتوانید این abstract را اضافه نکنید، دلیل اینکارم این است که بتوانم بعدا در صورت نیاز متودها را در UserRepository که در پایین ایجاد میکنم بازنویسی کنم)
حالا یک کلاس UserRepository در مسیر App/Http و در پوشهای به نام Repository ایجاد میکنم که extends شده از UserRepositoryAbstract (اگر شما نخواستید abstract بالا را ایجاد کنید میتوانید کلاس UserRepository را مستقیما از interface ایجاد شده implement کنید)
حالا لازم است کلاس ایجاد شده را در service container لاراول اضافه کنیم.
برای این کار یک service provider مجزا ایجاد میکنیم که از این پس تمامی repository های خود را در آن bind کنیم.
php artisan make:provider RepositoryServiceProvider
حالا در provider ایجاد شده Repository و interface خود را bind میکنیم.
حالا باید provider ایجاد شده را در مسیر config/app.php در بخش providers ثبت کنیم.
حالا دیگه تقریبا کار تموم شده و فقط باید بدنهی متودهای خود را در UserRepositoryAbstract ایجاد کنیم و در صورت نیاز در UserRepository بازنویسی کنیم اگر هم که نیازی به بازنویسی نبود دقیقا همانها را در کنترلر خود فراخوانی میکنیم.
namespace App\Http\Repository; use App\Http\Abstracts\UserRepositoryAbstract; class UserRepository extends UserRepositoryAbstract { public function loginDoctor($request) { return Parent::loginDoctor(); } public function loginPatient($request) { // TODO: Implement loginPatient() method. } public function registerDoctor($request) { // TODO: Implement registerDoctor() method. } public function registerPatient($request) { // TODO: Implement registerPatient() method. } public function avatar($avatarFile) { // TODO: Implement avatar() method. } public function updateAvatar() { // TODO: Implement updateAvatar() method. } public function getAllDoctor() { // TODO: Implement getAllDoctor() method. } public function updateDoctor($request) { // TODO: Implement updateDoctor() method. } public function updatePatient($request) { // TODO: Implement updatePatient() method. } }
برای اینکه از متودهای UserRepository در کنترلر خود استفاده کنیم ابتدا باید interface آن را به کلاس کنترلر خود inject کنیم. اینکار را با تعریف یک property به نام userRepository و inject آن به متود construct انجام میدهیم.
namespace App\Http\Controllers; use App\Http\Interfaces\UserRepositoryInterface; class DoctorController extends Controller { private UserRepositoryInterface $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function index() { return $this->userRepository->getAllDoctor(); } public function avatar(Request $request) { return $this->userRepository->avatar($request); } }
همانطور که در کدهای بالا مشخص است ما در متود index خود، متود getAllDoctor را از UserRepository فراخوانی کردیم و همین کار را برای کنترلر بیمار و حتی سایر کنترلرهای مربوط به user انجام میدهیم و از تکرار کدها جلوگیری و خوانایی کدها را افزایش میدهیم. (درکنترلر بالا و پایین متود avatar مشترک است که برای هر دو کنترلر از متود avatar در UserRepository استفاده شده است و نیازی به تکرار این متود نبود)
namespace App\Http\Controllers; use App\Http\Interfaces\UserRepositoryInterface; use Illuminate\Http\Request; class PatientController extends Controller { private UserRepositoryInterface $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function avatar(Request $request) { return $this->userRepository->avatar($request); } }
امیدورام این مقاله مفید بوده باشد، اگر سوالی داشتید کامنت بگذارید در اسرع وقت پاسخ خواهم داد.