توی این مقاله میخواهیم درباره الگوی ریپازیتوری (Repository pattern) در لاراول صحبت کنیم.
فرض میکنیم شما یک آشنایی اولیه با فریمورک لاراول و زبان phpدارید و برای همین مورد میتوانیم بیشتر با این الگوی برنامهنویسی کارکنیم.
قبل از اینکه وارد بحث شویم باید بدانیم که الگوی ریپازیتوری (Repository pattern) اصلاً به چه معنا هست:
الگوی ریپازیتوری (Repository pattern) کلاس یا مؤلفههایی هستند که دسترسی به دادهها را برای ما محصور یا بهاصطلاح کپسوله میکنند. این الگو دسترسیهای مشترک به دادهها را متمرکزتر میکند که همین امر باعث میشود، نگهداری کد را برای ما راحتتر شود. در کل منظور ما این هست که این الگو زیرساخت یا فناوری اتصال به پایگاه داده را از لایه دامنه (DDD) و مدلهای آن برای ما جدا میکند.
سورس کامل پروژه در لینک زیر قرار دارد:
شاید این موضوع کمی برای شما گیجکننده باشد، برای همین نیاز هست کمی بیشتر در این رویکرد شیرجه بزنیم و در قالب یک پروژه این طراحی را یاد بگیریم.:)
قضیه ازاینقرار هست که ما برای توسعه این پروژه از سه لایه استفاده خواهیم کرد:
· لایه سرویس
· لایه دامین
· لایه زیرساخت (که شامل ریپازیتوری ها هست)
این نوع معماری که دولایه را به لایه ریپازیتوری اضافه کردهایم، کاملاً سلیقهای هست و به شما بستگی دارد که چگونه معماری پروژه خود را برحسب نیاز بچینید. توی این آموزش ما از این معماری استفاده میکنیم.
در این پروژه با لایه اول و دوم خیلی کاری نداریم و نیاز نیست خیلی درگیر این دولایه شوید ولی در کل بخواهیم توضیح دهیم لایه اول مربوط به سرویسهای ما بوده و لایه دوم مربوط به طراحی دامنه محور یا Domain-Driven Design (DDD)هست.
خب برای شروع یک پروژه تازه لاراولی را میسازیم:
composer create-project laravel/laravel laravel-repository-pattern
سپس پروژه را با VS Code یا IDE موردنظر خودتان بازکنید.
این مقاله درباره نحوه نصب لاراول نیست. اگر با مشکلی هنگام نصب این فریمورک جذاب روبهرو شدید، میتوانید به داکیومنتیشن این فریمورک مراجعه کنید.
ابتدا اقدام به طراحی لایه زیرساخت خواهیم کرد.
لایه Infrastructure یا زیرساخت (که ریپازیتوری ها در آن قرار خواهند داشت) را بهعنوان لایه اول نرمافزار میسازیم. ابتدا در پوشه app یک دایرکتوری به نام Infrastructure بسازید، سپس دایرکتوری EloquentRepository را ایجاد کنید. حالا که پوشه نوع ریپازیتوری را هم ساخته ایم، نوبت به ساخت فایل BaseRepository.php و پوشه User میرسد. پس از ساخت دایرکتوری User فایل UserRepository.php را میسازیم. حال باید ساختار پوشه بندی شما به شکل زیر باشد.
- app
- Infrastructure
-- EloquentRepository
--- User
---- UserRepository.php
---BaseRepository.php
اینترفیس مربوط به این دو فایلی که ساختیم را در لایه دامین خواهیم ساخت. اکشنهای اولیه هر مدل برای اضافه، حذف، ویرایش و ... که معمولاً برای هر مدلی اضافه میشوند را در فایل BaseRepository.php طبق عکس زیر قرار خواهیم داد.
طبق این کد باید متدها بهاصطلاح self-describingباشند و بتوانند اقداماتی را که انجام میدهند توسط اسم خود معرفی کنند. به همین منظور از کلمات کلیدی 'find'، 'get'، 'remove'، 'update' و ... برای تعریف نام متدها استفاده میکنیم.
سپس به سراغ دایرکتوری یا پوشه User میرویم و در فایل UserRepository.php از BaseRepository.php ارثبری میکنیم و درنهایت کد این فایل طبق تصویر زیر خواهد شد.
خب به سراغ لایه بعدی یعنی لایه دامنه میرویم تا اینترفیس های مربوط به لایه ریپازیتوری را در آن تعریف کنیم.
در پوشه app یک دایرکتوری به نام DomainService بسازید، سپس ۳ فایل BaseDomain.php، DomainInterface.php و RepositoryInterface.php را بسازید. سپس اقدام به ساخت پوشه User میکنیم و سه فایل زیر را در آن میسازیم:
· UserDomain.php
· UserDomainInterface.php
· UserRepositoryInterface.php
اولین فایلی که در این لایه میخواهیم درباره آن صحبت کنیم، RepositoryInterface.php هست که در لایه ریپازیتوری در فایل BaseRepository.php واقع در دایرکتوری Infrastructure ایمپلمنت شده است.
اگر یک توضیح کوتاه بخواهیم درباره اینترفیس ها بدهیم، باید بگوییم که اینترفیس کاری به نحوه اجرای تابع ندارد و فقط ورودی و خروجی هر تابع کلاس را تعیین میکند و بهاصطلاح یک قرارداد میباشد. برای مثال اگر در آینده بخواهیم پایگاه داده خود را عوض کنیم فقط کافی است کلاسی جدید بر طبق اینترفیس موردنظر ساخته شود و نیازی به تغییر کد درجاهایی که اینترفیس را فراخوانی کردهاند نیست.
حال به ادامه بحث خود میپردازیم و کلاس RepositoryInterface.php را طبق عکس زیر پیادهسازی میکنیم:
سپس به سراغ DomainInterface.php میرویم که اینترفیس کلی دامنههای این لایه را تعریف میکند.
و BaseDomain.php را که کلاس DomainInterface.php را اجرا میکند طبق عکس زیر خواهیم ساخت.
به سراغ پوشه User میرویم و کلاس UserRepositoryInterface.php را طبق عکس زیر میسازیم.
این کلاس در دایرکتوری Infrastructure و در فایل UserRepository.phpایمپلمنت شده است.
و در کلاس UserDomain.php مطابق عکس زیر ایمپلمنت مینماییم.
اگر طبق ساختار گفتهشده دایرکتوریها و فایل ها را ساخته باشید در این لایه باید فایل های شما بهصورت زیر ساختهشده باشند:
- DomainService
-- User
--- UserDomain.php
--- UserDomainInterface.php
--- UserRepositoryInterface.php
-- BaseDomain.php
-- DomainInterface.php
-- RepositoryInterface.php
وارد پوشه app شوید و یک دایرکتوری به نام ApplicationServiceبسازید. در این پوشه دو فایل بهنامهای BaseService.php و ServiceInterface.phpبسازید. سپس یک پوشه به نام Userساخته و دو فایل بهنامهای UserService.php و UserServiceInterface.phpدرون آن بسازید. اگر مسیر را بهدرستی طی کرده باشید ساختار پوشه بندی شما باید به شکل زیر باشد:
- ApplicationService
-- User
--- UserServiceInterface.php
--- UserService.php
-- ServiceInterface.php
-- BaseService.php
اگر بخواهیم یک توضیح خلاصه درباره ساختار لایه ApplicationServiceبدهیم این هست که این لایه برای سرویسهای اولیه طراحیشده است. مثل بررسی اولیه ورودیهایی که از طریق کنترلر وارد لایف سایکل درخواستهای لاراول میشوند.
در این دایرکتوری ما یک اینترفیس (InterFace) ServiceInterface.php کلی برای تمام سرویسها ایجاد کردهایم که قرار است اینترفیس هر موجودیت از این اینترفیس ارثبری نماید و بهنوعی از تکرار در کد نویسی پرهیز کنیم. همچنین فایل BaseService.php هم در همین دایرکتوری قرار دارد تا سرویسهای موجودیتها از این سرویس پایه ارثبری کنند.
ابتدا کدهای کلاس ServiceInterface.php را طبق تصویر زیر خواهیم داشت:
سپس کدهای کلاس BaseService.php طبق تصویر زیر خواهد بود:
حال به سراغ ساختن کلاس UserServiceInterface.php میرویم و طبق تصویر زیر خواهیم داشت:
و آخرین کلاس این لایه UserService.php که مطابق تصویر زیر پیادهسازی میشود:
خب حالا که سه لایه را ساختهایم، نیاز داریم تا اینترفیس (InterFace) ها را به کلاسهایی که آنها را ایمپلمنت یا اجرا میکنند وصل کنیم.
برای این کار باید برای هر لایه یک سرویس پروایدر بسازیم.
سه دستور زیر را در دایرکتوری اصلی پروژه به ترتیب و جداگانه ران کنید:
php artisan make:provider RepositoryServiceProvider
php artisan make:provider ApplicationServiceProvider
php artisan make:provider DomainServiceProvider
فایل ها در مسیر laravel-repository-pattern\app\Providers ساخته میشوند.
سپس وارد هر کلاس میشویم و در تابع register هرکدام عملیات بایندینگ را طبق روالی که در ادامه توضیح میدهیم، انجام خواهیم داد.
کلاس RepositoryServiceProvider
بهصورت زیر پیادهسازی خواهد شد:
کلاس DomainServiceProvider
را بهصورت زیر خواهیم داشت:
و درنهایت کلاس ApplicationServiceProvider
مطابق تصویر زیر خواهد بود:
سپس به آدرس
laravel-repository-pattern\app\Providers\AppServiceProvider.php
رفته و سه سرویس پروایدری را که بالا تعریف کردهایم در تابع register طبق عکس زیر ثبت میکنیم:
اگر عملیات موفقیتآمیز نبود به مسیر زیر بروید و بهصورت دستی کش ها را پاککنید:
- app
-- bootstrap
--- cache (Delete these files below)
---- config.php
---- packages.php
---- services.php
ساخت UserController و اعمال Dependency Injection
برای ساخت کنترلر ابتدا دستور زیر را اجرا نمایید:
php artisan make:controller UserController
و سپس در routes/api.php طبق عکس زیر یک روت برای دسترسی به این کنترلر تعریف نمایید:
سپس در درون کنترلر کد زیر را قرار می دهیم:
در این کلاس متد index لیست کاربرانی که قرار است بسازیم را با استفاده از اینجکت کردن userServiceفراخوانی میکند.
استفاده از چندلایه مثل الگوی ریپازیتوری پترن به ما این اجازه را میدهد تا کنترلر های خود را تمیزتر نگهداریم و کدها را دستهبندی نماییم.
حالا جداول اولیه را با دستور زیر میسازیم:
php artisan migrate:fresh
سپس با دستور زیر چند کاربر را وارد پایگاه داده خواهیم نمود:
php artisan tinker
و سپس دستور زیر را برای نهایی کردن این عملیات انجام میدهیم:
User::factory(10)->create()
اگر پروژه را اجرا کنیم و وارد آدرس زیر در مرورگر شویم کاربران ساختهشده را خواهیم دید:
http://localhost:8000/api/users
شاید کار ما بهظاهر وقتگیر باشد ولی برای پروژههای بزرگ استفاده از این دیزاین پترن میتواند بسیار مفید واقع شود.