حتما چنین کدی رو قبلا دیدین:
public function index() : JsonResponse
{
$cars = Car::with('facilities', 'type', 'color', 'rentalDetail')->all();
return response()->json($cars, 200);
}
هوم... . مورد بدی توش دیده نمیشه. یک سرویس ساده که لیست خودرو ها رو میده. اما منطق/logic توی کنترلر نوشته شده. هر چند به عقیده من آوردن منطق در کنترلر برای app های کوچک مشکلی به وجود نمیاره اما با رشد نرم افزار بیشتر و بیشتر نیاز به یک ساختار منسجم و متمرکز رو حس میکنید.
به عنوان یک روش جایگزین و بهتر میشه از الگوی طراحی مخزن یا بهتر هست بگیم Repository Design Pattern استفاده کرد. مثل همیشه ساده بگم، در این روش مسئولیت ارتباط و استخراج داده ها رو از روی دوش مدل برمیداریم و اون رو در کلاس های Repository پیاده میکنیم، داخل کنترلر هم فقط متد هاشون رو صدا میزنیم.
public function index() : JsonResponse
{
$cars = $this->carRepository->get();
return response()->json($cars, 200);
}
این روش مزیت های زیادی داره از جمله:
- ایجاد ساختاری منسجم و متمرکز
- حذف کد های تکراری
- توسعه و نگهداری آسانتر
- کاهش خطا و خطایابی سریعتر
- از بین بردن وابستگی های بین مدل و کنترلر
- کد تمیز و واضحتر
خب به نظرم توضیحات تا همین اندازه کافی هست و بهتره بریم سراغ یک نمونه ساده از پیاده سازی این روش تا مزایایی که بهمون میده رو بیشتر درک کنید.
برای مخازن چنین ساختاری رو در نظر میگیریم.
-- app
---- Repositories
------ CarRepository.php
------ BaseRepository.php
------ RepositoryInterface.php
با استفاده از RepositoryInterface الگو و ساختار پیشفرض کارمون تعریف میشه. متد هایی که تمام مخازن باید یک نمونه پیاده سازی اون رو داشته باشن.
interface RepositoryInterface
{
public function get();
public function find($id);
public function create($data);
public function update($data, $id);
public function delete($id);
}
در BaseRepository متدهای مشترک بین تمام مخازن رو پیاده میکنیم. مخازن از این کلاس extend میشن. این کلاس به حذف کدهای تکراریمون کمک میکنه.
class BaseRepository implements RepositoryInterface
{
protected $model;
public function __construct($model)
{
$this->model = $model;
}
public function get()
{
return $this->model->get();
}
public function find($id)
{
return $this->model->find($id);
}
public function create($data)
{
return $this->model->create($data);
}
public function update($data)
{
return $this->model->update($data);
}
public function delete()
{
return $this->model->delete();
}
}
و مخزن خودرو. همون مثالی که زدیم.
class CarRepository extends BaseRepository
{
public function __construct(Car $model)
{
parent::__construct($model);
}
public function get()
{
$cars = $this->model->with('facilities', 'type', 'color', 'rentalDetail')
->orderByDesc('id');
return $cars;
}
}
استفاده.
class CarController extends Controller
{
private $carRepository;
public function __construct(User $model)
{
$this->carRepository = new CarRepository($model);
}
public function index(): JsonResponse
{
$cars = $this->carRepository->get();
return response()->json($cars, 200);
}
public function create(CarRequest $request) : JsonResponse
{
$cars = $this->carRepository->create($request->all());
return response()->json(null, 204);
}
.
.
.
}
نکات آخر.
- این یک نمونه ساده از پیاده سازی Laravel Repository Pattern به منظور درک سریع و بهتر موضوع بود. طبیعتا روش های پیاده سازی متفاوتی رو با گشتن در اینترنت خواهید دید.
- همونطور که توضیح دادم مخازن کار با دیتا رو انجام میدن و دیگه از مدل استفاده نمیکنیم.
- توی مثال ها چند متد رایج رو آوردم. هر نوع درخواست(کوئری) باید در مخازن تعریف و داخل کنترلر صدا زده بشه.
- در استفاده از این روش اجباری نیست.
- در مدل پیاده سازی این روش قانون سختگیرانه ای وجود نداره.
موفق باشید.