شنبه, 06 دی 1404

ریپازیتوری در لاراول

...

” اگر با لاراول کار می‌کنی، دیر یا زود با کنترلرهای شلوغ و منطق داده‌های پراکنده مواجه می‌شی. توی این مقاله به‌صورت ساده و عملی با ریپازیتوری آشنا می‌شی.. “

اگه مدتیه با لاراول کار می‌کنی، احتمالاً وسط آموزش‌ها، مقاله‌ها یا صحبت با دیگر توسعه‌دهنده‌های لاراول یا گروه‌های حل مشکل با اصطلاحاتی مثل Repository، Service و Interface برخورد کردی که نمیدونی دقیقاً چی هستن..

توی این مقاله به‌صورت ساده و عملی با ریپازیتوری آشنا میشی..


اول از جایی شروع کنیم که معمولاً همه‌مون هستیم

اوایل کار با لاراول، معمولاً منطق مربوط به دیتابیس رو مستقیم داخل Controller می‌نویسیم.
هم سریع‌تره، هم قابل فهم‌تر.

مثلاً برای لیست مقالات:

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::where('status', 'published')
            ->orderBy('published_at', 'desc')
            ->paginate(10);

        return view('posts.index', compact('posts'));
    }
}

تا اینجای کار، هیچ چیز اشتباهی وجود نداره.
پروژه کوچیکه و همه‌چی جواب میده.


مشکل از کِی شروع میشه؟

کم‌کم که پروژه بزرگ‌تر میشه، چند تا اتفاق می‌افته:

۱. منطق تکراری

یهو می‌بینی همین منطق «پست‌های منتشرشده»
توی چند جای مختلف پروژه استفاده شده:

  • یه کنترلر دیگه

  • یه کامپوننت

  • یا حتی یه بخش دیگه از سایت

اگه یه روز شرط تغییر کنه، باید چند جا رو اصلاح کنی :)


۲. چیزی که بهش میگن «کنترلر چاق» (Fat Controller)

داستانش اینه که:
کنترلر کم‌کم پر میشه از:

  • کوئری

  • شرط

  • منطق دیتابیس

  • و تصمیم‌گیری‌های مختلف

در حالی که نقش اصلی کنترلر اینه که:

  • درخواست رو بگیره

  • یه جواب مناسب برگردونه

نه اینکه همه‌چیز رو خودش انجام بده.


کاربرد ریپازیتوری کجاست؟

ریپازیتوری کمک میکنه منطق مربوط به داده‌ها از کنترلر جدا بشه.

به زبان ساده‌تر:

ریپازیتوری یه لایهٔ میانی بین کنترلر و مدل‌هاست. کنترلر فقط میدونه چه داده‌ای لازم داره، ولی اینکه این داده‌ها چطور به دست بیان، به ریپازیتوری واگذار میشه.


قدم‌به‌قدم با یه مثال ساده

بیا مرحله به مرحله پیش بریم تا ببینیم چطور می‌تونیم ریپازیتوری رو به پروژه‌مون اضافه کنیم. مثالمون رو با همون بخش "پست‌های وبلاگ" ادامه میدیم.

۱. تعریف قرارداد (Interface)

Interface یه فایل ساده‌ست که تعریف میکنه ریپازیتوری چه کارهایی می‌تونه انجام بده و صرفاً یه «قرارداد» بین کسی که از ریپازیتوری استفاده میکنه و پیاده‌سازی ریپازیتوریه.

مسیر پیشنهادی:
app/Repositories/Contracts/PostRepositoryInterface.php

<?php

namespace App\Repositories\Contracts;

interface PostRepositoryInterface
{
    public function getPublishedPosts($perPage = 10);
    public function findById($id);
}

توضیح ساده:

اینجا فقط داریم میگیم: "هر کلاسی که قراره نقش ریپازیتوری Post رو بازی کنه، حتماً باید این دو تا متد رو داشته باشه."

یعنی یه جور قرارداد می‌بندیم که بگه کارهای اصلی ما چیا هستند.


۲. پیاده‌سازی خود ریپازیتوری

حالا یه کلاس واقعی می‌سازیم که این وظایف رو انجام بده.

مسیر پیشنهادی:
app/Repositories/PostRepository.php

<?php

namespace App\Repositories;

use App\Models\Post;
use App\Repositories\Contracts\PostRepositoryInterface;

class PostRepository implements PostRepositoryInterface
{
    protected $model;

    // به ریپازیتوری می‌گیم با کدوم مدل کار کنه
    public function __construct(Post $model)
    {
        $this->model = $model;
    }

    // این متد پست‌های منتشرشده رو برمی‌گردونه
    public function getPublishedPosts($perPage = 10)
    {
        return $this->model
            ->where('status', 'published')
            ->orderBy('published_at', 'desc')
            ->paginate($perPage);
    }

    // این متد یه پست رو با آیدی پیدا می‌کنه
    public function findById($id)
    {
        return $this->model->findOrFail($id);
    }
}

اینجا داریم یک کلاس واقعی می‌سازیم که عملاً کارها رو انجام میده. کلیدواژه implements یعنی این کلاس متعهد میشه که تمام متدهایی که در Interface تعریف کردیم رو داشته باشه و پیاده‌سازی کنه.

مثل این میمونه که بگیم: "من (کلاس PostRepository) قول میدم تمام وظایفی که توی لیست کارها (PostRepositoryInterface) نوشتیم رو انجام بدم."

همون کدهای کار با دیتابیس که قبلاً مستقیم توی کنترلر می‌نوشتیم، الان به این کلاس منتقل شدن. تفاوت اینه که الان همه این کدها توی یه جای مشخص و مرتب جمع شدن، نه اینکه پراکنده باشن.


۳. معرفی ریپازیتوری به لاراول

کافیه تو فایل AppServiceProvider.php و داخل متد register() این کد رو بنویسیم:

$this->app->bind(
    \App\Repositories\Contracts\PostRepositoryInterface::class,
    \App\Repositories\PostRepository::class
);

با این کار، لاراول هر جا که PostRepositoryInterface استفاده بشه (مثلاً داخل کنترلر)، به‌صورت خودکار کلاس PostRepository رو می‌سازه و تزریق می‌کنه.


۴. استفاده در کنترلر

حالا می‌تونیم کنترلرمون رو تمیز کنیم:

<?php

namespace App\Http\Controllers;

use App\Repositories\Contracts\PostRepositoryInterface;

class PostController extends Controller
{
    protected $postRepository;

    // لاراول خودش کلاس PostRepository رو می‌سازه و اینجا میده
    public function __construct(PostRepositoryInterface $postRepository)
    {
        $this->postRepository = $postRepository;
    }

    public function index()
    {
        // خیلی تمیز شد! فقط میگیم چی می‌خوایم
        $posts = $this->postRepository->getPublishedPosts();

        return view('posts.index', compact('posts'));
    }
}

کنترلر:

  • ساده‌تر شده

  • خواناتر شده

  • فقط مسئول رسیدگی به درخواست و پاسخ‌دهی شده


چرا از ریپازیتوری استفاده می‌کنیم؟

  • وقتی کد پروژه شلوغ میشه

  • وقتی تغییر دادن منطق‌ها سخت میشه

  • وقتی کنترلرها بیش از حد مسئولیت میگیرن

ریپازیتوری به عنوان یه لایهٔ میانی، کمک می‌کنه این مسئولیت‌ها از هم جدا بشن و مسیر پروژه مرتب و قابل نگهداری باقی بمونه.


✍️ حرف آخر

ریپازیتوری یه راه حل ساده برای مدیریت داده‌ها و منطق مدل‌هاست.
حتی برای پروژه‌های کوچیک، شاید لازم نباشه ازش استفاده کنی، ولی وقتی پروژه بزرگ‌تر میشه، ارزشش مشخص میشه.

من این مقاله رو نوشتم تا تجربه‌م رو باهاتون به اشتراک بذارم؛
تخصص اصلی من بک‌اند نیست، ولی دوس دارم چیزایی که تو مسیر بک‌اند باهاش برخورد کردم رو برای شما هم بنویسم.

اگه جایی مقاله سوتی داشت یا نکته‌ی اضافه‌ای به ذهنت رسید، حتماً تو نظرات برام بنویس تا همه استفاده کنن 🙏

ارسال دیدگاه

دیدگاه و یا پرسش خود را برای ما ارسال کنید.

وارد شوید

برای ارسال دیدگاه یا پرسش خود ابتدا وارد سایت شوید

ورود یا ثبت نام

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

هنوز دیدگاه یا پرسشی ایجاد نشده است :/

تازه‌ترین نوشته‌ها

دیدن همه

تجربه‌ها، دیدگاه‌ها و نکات الهام‌بخشی که با شما به اشتراک می‌گذاریم.