استفاده از Controller

اصول آموزش Laravel

تاریخ : جمعه 13 بهمن 1396

به جای تعریف منطق مدیریت درخواست‌های برنامه به عنوان تابع Closure در فایل‌های مسیر لاراول، می‌توانید این کارها را با استفاده از کلاس‌های کنترلر انجام دهید. کنترلرها منطق پردازش درخواست‌های مرتبط به هم را در یک کلاس واحد دسته بندی می‌کنند. کنترلرها در دایرکتوری app/Http/Controllers قرار می‌گیرند. در ادامه چگونگی کار با کنترلرها و مسیردهی به آن‌ها را با هم بررسی می‌کنیم.


پایه در لاراول


تعریف Controllers

در مثال زیر نمونه‌ای از کلاس کنترلر پایه را مشاهده می‌کنید. توجه کنید که کنترلرهای برنامه از کلاس کنترلر پایه که به صورت پیش‌فرض در لاراول قرار دارد، ارث بری می‌کنند. کلاس پایه چندین متد ارائه می‌دهد، برای مثال متد middleware برای اتصال middleware به اکشن‌های کنترلر مورد استفاده قرار می‌گیرد:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

می‌توان یک مسیر مانند مثال زیر برای این کنترلر تعریف کرد:

Route::get('user/{id}', '[email protected]');

زمانی که یک درخواست ورودی با URI مربوط به مسیر مطابقت داشته باشد، متد show در کلاس UserController اجرا خواهد شد. همچنین پارامترهای موجود در مسیر نیز به متد ارسال می‌شوند.

کنترلرها را می‌توان بدون نیاز به ارث بری از یک کلاس پایه تعریف کرد. اما در این صورت به امکاناتی مانند استفاده از متدهای middleware ، validate و dispatch دسترسی نخواهید داشت.


استفاده از controller و namespace در لاراول

نکته مهمی که باید به آن توجه داشته باشیم این است که در هنگام تعیین مسیر کنترلر، نیازی نیست که فضای نامی کنترلر را به صورت کامل تعریف کنیم. از آنجا که RouteServiceProvider فایل‌های مسیر را در یک گروه مسیر که فضای نامی ریشه را شامل می‌شود، بارگزاری می‌کند؛ فقط آن بخش از نام کلاس که بعد از بخش App\Http\Controllers در فضای نامی قرار دارد را مشخص می‌کنیم.

اگر بخواهید کنترلرها توسط فضای نامی در دایرکتوری App\Http\Controllers به صورت تودرتو گروه بندی کنید، می‌توانید به سادگی از نام کلاس خاصی نسبت به فضای نامی ریشه App\Http\Controllers استفاده کنید. بنابراین، اگر کلاس کامل کنترلر شما App\Http\Controllers\Photos\AdminController است، باید مانند مثال زیر مسیر را برای کنترلر ثبت کنید:

Route::get('foo', 'Photos\[email protected]');


کنترلرهای تک اکشن (Single Action Controllers) در لاراول

اگر بخواهید کنترلری تعریف کنید که فقط یک اکشن داشته باشد، باید یک متد __invoke را در کنترلر قرار دهید:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Controllers\Controller;

class ShowProfile extends Controller
{
    /**
     * Show the profile for the given user.
     *
     * @param  int  $id
     * @return Response
     */
    public function __invoke($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

در هنگام ثبت مسیر، مشخص کردن متد تعریف شده برای کنترلرهای single action نیاز نیست. به مثال زیر توجه کنید:

Route::get('user/{id}', 'ShowProfile');


Controller Middleware در لاراول

می‌توان یک middleware را به مسیرهای کنترلر در فایل‌های مسیر به صورت زیر اختصاص داد:

Route::get('profile', '[email protected]')->middleware('auth');

با این حال، برای راحتی کار می‌توان middleware را در سازنده کنترلر تعریف کرد. با استفاده از متد middleware در سازنده کنترلر، می‌توان به راحتی middleware را به اکشن کنترلر اختصاص داد. حتی می‌توان middleware را به متدهای خاصی در کلاس کنترلر محدود کرد:

class UserController extends Controller
{
    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('log')->only('index');

        $this->middleware('subscribed')->except('store');
    }
}

همچنین کنترلر امکان ثبت middleware با استفاده از Closure را فراهم می‌کند. این موضوع روش مناسبی جهت تعریف middleware برای یک کنترلر بدون نیاز به تعریف کلاس کلی middleware است.

$this->middleware(function ($request, $next) {
    // ...

    return $next($request);
});
می‌توان middleware را به زیرمجموعه‌ای از اکشن‌های یک کنترلر اختصاص داد؛ با این حال، این موضوع نشان دهنده رشد بیش از حد کنترلر است. می‌توان به جای این کار، کنترلر را به کنترلرهای کوچکتر تقسیم کرد.


کنترلر منابع یا resource controllers در لاراول

در مسیریابی منابع لاراول، مسیرهای معمول عملیات CRUD را می‌توان با یک خط کد به یک کنترلر اختصاص داد. برای مثال، اگر بخواهید کنترلری ایجاد کنید که تمام درخواست‌های HTTP برای عکس‌های ذخیره شده توسط برنامه را مدیریت کند، می‌توان به سرعت و با استفاده از دستور make:controller این کنترلر را ایجاد کرد:

php artisan make:controller PhotoController --resource

این دستور کنترلر را در app/Http/Controllers/PhotoController.php ایجاد می‌کند. این کنترلر برای هر یک از عملیات مربوط به منابع موجود، یک متد را شامل می‌شود.

سپس، می‌توان یک مسیر خوب برای کنترلر مانند مثال زیر ثبت کرد:

Route::resource('photos', 'PhotoController');

این اعلان ساده مسیر، مسیرهای متعددی را برای مدیریت انواع عملیات بر روی منابع (عکس‌ها) ایجاد می‌کند. اکنون کنترلر ایجاد شده متدهایی را برای هر کدام از این عملیات، ارائه کرده است. این متدها شامل یادداشت‌هایی هستند که مشخص می‌کند کدام درخواست‌های HTTP و URIها توسط آن‌ها مدیریت می‌شوند.

می‌توان چند کنترلر منابع را در یک زمان بوسیله انتقال یک آرایه به متد resources ثبت کرد:

Route::resources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);


عملیاتی که توسط کنترلر منابع مدیریت می‌شود:

Verb URI Action Route Name
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy


تعیین مدل منابع (Resource Model) در لاراول

اگر از binding مدل مسیر استفاده می‌کنید و مایلید متدهای کنترلر منابع را به یک نمونه مدل type-hint کنید، می‌توانید از گزینه --model هنگام ایجاد کنترلر استفاده کنید:

php artisan make:controller PhotoController --resource --model=Photo


متدهای فرم جعلی در لاراول

از آنجا که فرم‌های HTML نمی‌توانند درخواست‌های PUT ، PATCH یا DELETE را ایجاد کنند، باید یک فیلد پنهان _method برای ایجاد جعلی این درخواست‌های HTTP اضافه کنید. تابع کمکی method_field این فیلد را برای شما ایجاد می‌کند:

{{ method_field('PUT') }}


اعلان مسیر‌های منابع به صورت سفارشی در لاراول

هنگام اعلان یک مسیر منابع، می‌توان زیرمجموعه‌ای از عملیاتی که کنترلر باید مدیریت کند را به جای مجموعه کامل عملیات پیش‌فرض تعریف کرد:

Route::resource('photo', 'PhotoController', ['only' => [
    'index', 'show'
]]);

Route::resource('photo', 'PhotoController', ['except' => [
    'create', 'store', 'update', 'destroy'
]]);


اعلان مسیرهای منابع API در لاراول

هنگام اعلان مسیرهای منابعی که توسط APIها استفاده می‌شوند، معمولا مسیرهای مربوط به عملیات create و edit را در قالب های HTML حذف می‌کنید. برای راحتی کار، می‌توانید متد apiResource را استفاده کنید که به صورت خودکار این دو مسیر را حذف می‌کند:

Route::apiResource('photo', 'PhotoController');

می‌توان چندین کنترلر API را در یک زمان با انتقال یک آرایه به متد apiResource ثبت کرد:

Route::apiResources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);


نام‌گذاری مسیرهای منابع در لاراول

در حالت پیش‌فرض تمام اکشن‌های کنترلر منابع دارای یک نام مسیر یا route name هستند؛ با این حال، می‌توانید این نام‌ها را با انتقال یک آرایه names با گزینه‌های موردنظر خود بازنویسی کنید:

Route::resource('photo', 'PhotoController', ['names' => [
    'create' => 'photo.build'
]]);


پارامترهای مربوط به نام‌گذاری مسیرهای منابع در لاراول

در حالت پیش‌فرض، Route::resource پارامترهای مسیر را برای مسیرهای منابع بر اساس نام‌های یکتا سازی شده منابع ایجاد می‌کند. می‌توان این نام‌ها را براساس هر منبع، توسط انتقال آرایه گزینه‌های parameters بازنویسی کرد. آرایه parameters باید یک آرایه ترکیبی از نام‌های منابع و نام‌های پارامترها باشد:

Route::resource('user', 'AdminUserController', ['parameters' => [
    'user' => 'admin_user'
]]);

مثال فوق URIهای زیر را برای مسیر show منابع ایجاد می‌کند:

/user/{admin_user}


ایجاد URLهای منابع به صورت محلی در لاراول

در حالت پیش‌فرض، URLهای منابع توسط Route::resource با استفاده از کلمات انگلیسی ایجاد می‌کند. برای مثال، اگر نیاز به محلی سازی کلمات اکشن‌های create و edit دارید، می‌توانید از متد Route::resourceVerbs استفاده کنید و در متد boot مربوط به AppServiceProvider این عمل را انجام دهید:

use Illuminate\Support\Facades\Route;

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);
}

زمانی که کلمات محلی سازی شدند، URIهای زیر توسط ثبت منابع مسیر Route::resource('fotos', 'PhotoController') ، تولید می‌‌شود:

/fotos/crear

/fotos/{foto}/editar


اضافه کردن مسیرهای اضافی به کنترلر منابع در لاراول

اگر نیاز به اضافه کردن مسیرهای اضافی، علاوه بر مجموعه پیش‌فرض مسیرهای منابع به یک کنترلر منابع دارید، قبل از فراخوانی Route::resource شما باید این مسیرها را تعریف کنید، در غیر این صورت، مسیرهای تعریف شده توسط متد resource بر روی مسیرهای اضافی که قصد اضافه کردن آن‌ها را داریم، اولویت خواهند داشت:

Route::get('photos/popular', '[email protected]');

Route::resource('photos', 'PhotoController');

Remember to keep your controllers focused. If you find yourself routinely needing methods outside of the typical set of resource actions, consider splitting your controller into two, smaller controllers.


تزریق وابستگی و Controller در لاراول

از service container لاراول برای resolve کردن تمام کنترلرهای لاراول استفاده می‌شود. در نتیجه، قادر خواهیم بود، هر وابستگی که ممکن است کنترلر در سازنده به آن نیاز داشته باشد را اعلان نوع یا type-hint کنیم. وابستگی‌های اعلان شده به صورت خودکار resolve می‌شوند و تزریق وابستگی به نمونه‌ی کنترلر انجام می‌شود:

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * The user repository instance.
     */
    protected $users;

    /**
     * Create a new controller instance.
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }
}

همچنین می‌توانید هر قرارداد لاراول را نیز اعلان نوع یا type-hint کنید. اگر container می‌تواند آن را resolve کند، می‌توانید آن را اعلان نوع کنید. بسته به برنامه، تزریق وابستگی‌ها به کنترلر، ممکن است تست پذیری بهتری را فراهم کند.


تزریق وابستگی به متد در لاراول

علاوه بر تزریق وابستگی در سازنده، می‌توانید وابستگی‌ها را در متدهای کنترلر نیز type-hint کنید. یک مورد استفاده معمول برای روش تزریق در متد، تزریق نمونه Illuminate\Http\Request به متد کنترلر مانند مثال زیر است:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->name;

        //
    }
}

اگر متد کنترلر انتظار دریافت ورودی از یک پارامتر مسیر را دارد، می‌توانید به سادگی آرگومان‌های مسیر را پس از وابستگی‌ها لیست کنید. برای مثال، اگر مسیر شما به صورت مثال زیر تعریف شده باشد:

Route::put('user/{id}', '[email protected]');

می‌توانید Illuminate\Http\Request را اعلان نوع کنید و با تعریف متد کنترلر خود به صورت زیر به پارامتر id دسترسی داشته باشید:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Update the given user.
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}


ذخیره سازی مسیر در حافظه نهان (route caching) در لاراول

مسیرهای مبتنی بر Closure با مسیرهای ذخیره شده در کش سازگاری ندارند. برای استفاده از route caching، بایستی هر مسیر مبتنی بر Closure را به کلاس‌های کنترلر تبدیل کنید.

اگر برنامه شما به صورت انحصاری از مسیرهای مبتنی بر کنترلر استفاده می‌کند، می‌توانید به راحتی از route caching در لاراول استفاده کنید. استفاده از route cache به میزان قابل توجهی زمان لازم برای ثبت تمام مسیرهای برنامه در لاراول را کاهش می‌دهد. در برخی موارد، با استفاده از این روش ثبت مسیر می‌تواند حتی تا 100 برابر سریع‌تر انجام شود. برای ساخت یک route cache، باید دستور آرتیسان route:cache را اجرا کنید:

php artisan route:cache

پس از اجرای این دستور، فایل مسیرهای کش شده بر روی هر درخواست بارگزاری می‌شود. توجه کنید، اگر بخواهید هر مسیر جدیدی را اضافه کنید، باید یک route cache جدید ایجاد کنید. به همین دلیل، توصیه می‌شود، دستور route:cache را در هنگام استقرار و نصب پروژه اجرا نمایید.

می‌توانید از دستور route:clear مانند مثال زیر برای پاک کردن route cache استفاده کنید:

php artisan route:clear

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


منابع مورد مطالعه جهت جمع آوری این مطلب:
https://laravel.com/docs/5.5/controllers
https://www.lydaweb.com/article/courses/laravel-5-5-tutorial/230/controller-لاراول


نظرات