مسیریابی

مجتبی پاکزاد لاراول 5.6.29 در حال تکمیل رایگان

مسیریابی پایه

پایه‌ای‌ترین مسیرهای لاراول یک URI و یک کلوژر (فانکشن بی‌نام) می‌پذیرند، کلاس Route متد خیلی ساده و واضحی برای تعریف مسیرها ارائه می‌دهد:

Route::get('foo', function () {
    return 'Hello World';
});

فایل‌های پیش‌فرض Route

تمام مسیرهای لاراول در فایل‌های مسیر شما تعریف می‌شوند که این فایل‌ها در دایرکتوری routes قرار دارند. این فایل‌ها به صورت اتوماتیک توسط فریمورک لود می‌شوند. فایل routes/web.php مسیرهایی را تعریف می‌کند که مربوط به رابط وب (Web Interface) اپلیکیشن‌تان هستند. مسیرهای تعریف شده در این فایل، به گروهِ میدلور web اختصاص داده شده‌اند که فیچرهایی مانند session state و CSRF protection را ارائه می‌دهد. مسیرهای تعریف شده در فایل routes/api.php به گروهِ میدلور api اختصاص داده شده‌اند و stateless هستند.

برای اغلب اپلیکیشن‌ها، کار را با تعریف مسیرها در فایل routes/web.php شروع می‌کنید. مسیرهایی که در routes/web.php تعریف شده‌اند، به راحتی با وارد کردن URL مسیرِ تعریف شده، در مرورگر در دسترس هستند. برای مثال، احتمالا با مراجعه به آدرس http://your-app.test/user توسط مرورگر، به مسیر زیر دسترسی خواهید داشت:

Route::get('/user', 'UserController@index');

مسیرهایی که در فایل routes/api.php تعریف شده‌اند، با ساختاری تودرتو در داخل یک گروهِ مسیر توسط RouteServiceProvider قرار دارند. در این گروه، /api پیشوند URIای است که به صورت خودکار به همه مسیرهای داخل این فایل اعمال می‌شود، بنابراین نیازی به اعمال دستی آن ندارید. می‌توانید پیشوند و سایر آپشن‌های گروه مسیر را را با ویرایش کلاس RouteServiceProvider اپلیکیشن خود تغییر دهید.

متدهای روتر در دسترس

روتر به شما امکان ثبت روت هایی را میدهد که به هر فعل HTTP پاسخ می دهند:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

گاهی ممکن است نیاز باشد که یک مسیر ثبت کنید که به چندین فعل HTTP پاسخ دهد. این کار را با استفاده از متد match می‌توانید انجام دهید، یا حتی شاید یک مسیر ثبت کنید که به تمامی فعل های HTTP با استفاده از متد any پاسخ دهد:

Route::match(['get', 'post'], '/', function () {
    //
});

Route::any('foo', function () {
    //
});

محافظت در برابر حملات CSRF

هر فرم HTML که اشاره به مسیرهای POST و PUT و DELETE تعریف شده در فایل مسیرهای web دارد، باید دارای یک فیلد حاوی توکن CSRF باشد. درغیر اینصورت ریکوئست پذیرفته نخواهد شد. در مستندات CSRF می‌توانید درباره محافظت در برابر حملات CSRF بیشتر بخوانید. (به زودی ترجمه خواهد شد و لینک آن در این قسمت قرار خواهد گرفت.)

<form method="POST" action="/profile">
    @csrf
    ...
</form>

ریدایرکت کردن مسیرها

اگر می‌خواهید مسیری تعریف کنید که به URI دیگری ریدایرکت شود، باید از متد Route::redirect استفاده کنید. این متد یک میانبر مناسب ارائه می‌دهد به طوری که نیازی به تعریف یک کنترلر یا مسیر کامل برای اجرای یک ریدایرکت ساده نخواهید داشت:

Route::redirect('/here', '/there', 301);

مسیرهای ویو

اگر مسیرتان، تنها نیاز به بازگرداندن یک ویو دارد، می‌توانید از متد Route::view استفاده کنید. مانند متد redirect، این متد نیز یک میانبر ساده ارائه می‌دهد به طوری که نیازی به تعریف یک کنترلر یا مسیر کامل نخواهید داشت. متد view یک URI را به عنوان آرگومنت اول خود و نام یک فایل ویو را به عنوان آرگومنت دوم می پذیرد. علاوه بر این دو آرگومنت، با استفاده از آرگومنت سوم که اختیاری است، می‌توانید داده‌هایی را به شکل یک آرایه به ویو ارسال کنید.

Route::view('/welcome', 'welcome');

Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

پارامترهای مسیریابی

پارامترهای مورد نیاز

البته، گاهی اوقات نیاز به دریافت سگمنت‌های URL داخل مسیر خود دارید. برای مثال، ممکن است نیاز به دریافت ID کاربر از طریق URL داشته باشید. این کار را با تعریف پارامترهای مسیر می‌توانید انجام دهید:

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

همچنین می‌توانید مشخص کنید که چه تعداد پارامتر اجباری برای مسیر شما وجود دارد:

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

پارامترهای مسیر همیشه در داخل براکت {} قرار می‌گیرند و باید شامل حروف الفبای انگلیسی باشند، همچنین ممکن است شامل کاراکتر دَش (-) نیز باشند. به جای استفاده از کاراکتر دَش از آندراسکور (_) استفاده کنید. پارامترهای مسیر به ترتیب (نام‌های آرگومان‌های کنترلرها/کال‌بَک‌ها اهمیتی ندارند) داخل کنترلرها/کال‌بَک‌های مسیر تزریق می‌شوند.

پارامترهای اختیاری

گاهی اوقات ممکن است نیاز داشته باشید که یک پارامتر مسیر تعیین کنید، اما بخواهید که استفاده از این پارامتر اختیاری باشد. این کار را با قرار دادن یک علامت سوال (?) بعد از نام پارامتر می‌توانید انجام دهید. به متغییر متناظر با مسیر یک مقدار پیش‌فرض بدهید:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

محدودیت‌های عبارت‌های باقاعده

با استفاده از متد where برای مسیر، فرمت پارامترهای مسیر خود را می‌توانید محدود کنید. متد با استفاده از متد where برای مسیر، نام پارامتر و یک عبارت باقاعده می‌پذیرد که عبارت باقاعده نشان می‌دهد که پارامتر محدود به چه کاراکترهایی است:

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

محدودیت‌های گلوبال

اگر بخواهید یک پارامتر مسیر به یک عبارت باقاعده محدود و مقید باشد، می‌توانید از متد pattern استفاده کنید. این پترن‌ها را باید در متد boot از کلاس RouteServiceProvider تعریف کنید:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}

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

Route::get('user/{id}', function ($id) {
    // Only executed if {id} is numeric...
});

نامگذاری مسیرها

نامگذاری مسیرها امکان تولید URL مناسب یا ریدایرکت برای مسیرهای مشخص را فراهم می‌آورد. با زنجیر کردن متد name به متد تعریف مسیر، می‌توانید یک نام برای مسیر تعیین کنید:

Route::get('user/profile', function () {
    //
})->name('profile');

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

Route::get('user/profile', 'UserProfileController@show')->name('profile');

تولید URL برای مسیرهای نامگذاری شده

هنگامی که یک نام را به یک مسیر مشخص تخصیص دادید، از نام مسیر در هنگام تولید URLها یا ریدایرکت به وسیله فانکشن گلوبال route استفاده کنید:

// Generating URLs...
$url = route('profile');

// Generating Redirects...
return redirect()->route('profile');

اگر مسیر نامگذاری شده نیاز به پارامترهایی داشته باشد، پارامترها را می‌توانید به عنوان آرگومان دوم به فانکشن route پاس دهید. پارامترهای داده شده به صورت خودکار در موقعیت‌های صحیح خودشان به URL وارد می‌شوند:

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1]);

بازرسی (Inspecting) مسیر جاری

اگر می‌خواهید بررسی کنید که آیا ریکوئست جاری به یک مسیر نامگذاری شده، مسیردهی شده است، می‌توانید از متد named زنجیر شده به یک نمونه (instance) مسیر استفاده کنید. برای مثال، می‌توانید نام مسیر فعلی را از یک میدلوِ مسیر (route middleware) بررسی کنید:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) {
        //
    }

    return $next($request);
}

گروه‌بندی مسیر

گروه‌بندی مسیر امکان اشتراک‌گذاری اتریبیوت‌های (attributes) مسیر مانند میدلور یا نیم‌اسپیس را در میان تعداد زیادی از مسیرها فراهم می‌کند، بدون اینکه نیاز به تعریف آن اتریبیوت‌ها در هر مسیر منحصر به فرد باشد. اتریبیوت‌های به اشتراک‌گذاشته شده به شکل یک آرایه در پارامتر اول متد Route::group استفاده می‌شود.

میدلور (Middleware)

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

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // Uses first & second Middleware
    });

    Route::get('user/profile', function () {
        // Uses first & second Middleware
    });
});

نیم‌اسپیس‌ها (Namespaces)

یکی از موارد دیگر استفاده از گروه‌های مسیر، تخصیص یک نیم‌اسپیس پی‌اچ‌پی به گروهی از کنترها با استفاده از متد namespace است:

Route::namespace('Admin')->group(function () {
    // Controllers Within The "App\Http\Controllers\Admin" Namespace
});

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

مسیریابی ساب دامنه

گروه‌های مسیر می‌توانند برای هندل مسیریابی ساب دامنه‌ها نیز استفاده شوند. ساب دامنه‌ها می‌توانند پارامترهای مسیر را مشابه URIهای مسیر تخصیص دهند، که به شما امکان کپچر کردن (capture) بخشی از ساب دامنه را برای استفاده در مسیر یا کنترلرتان می‌دهد. ساب دامنه می تواند با فراخوانی متد domain قبل از تعریف گروه مشخص شود.

Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

پیشوندهای مسیر

متد prefix می‌تواند برای افزودن پیشوند به هر مسیری در گروه با یک URI مشخص استفاده شود. برای مثال، ممکن است بخواهید به تمام URIهای مسیرهای داخل گروه، پیشوند admin را اضافه کنید:

Route::prefix('admin')->group(function () {
    Route::get('users', function () {
        // Matches The "/admin/users" URL
    });
});

پیشوندهای نام مسیر

متد name می‌تواند برای افزودن یک استرینگ مشخص به عنوان پیشوند هر نام مسیری در گروه استفاده شود. برای مثال، ممکن است بخواهید به تمام نام‌های مسیر گروه‌بندی شده پیشوند admin را اضافه کنید. استرینگ مذکور به نام مسیر اضافه شده، دقیقا همانطور که مشخص شده است، بنابراین دقت کنید که در پایان نام حتما کاراکتر . را قرار دهید.

Route::name('admin.')->group(function () {
    Route::get('users', function () {
        // Route assigned name "admin.users"...
    })->name('users');
});

روت مدل بایندینگ (Route Model Binding)

هنگامی که ID یک مدل به یک مسیر یا اکشن کنترلر تزریق می‌شود، اغلب برای دریافت مدل مرتبط با آن ID کوئری می‌زنید. روت مدل بایندینگِ لاراول، روشی مناسب برای تزریق اتوماتیک نمونه‌های مدل (model instances) به مسیرها را ارائه می‌دهد. برای مثال، به جای تزریق ID یک کاربر، می‌توانید کل نمونه‌ی مدل User را که با ID داده شده مطابقت دارد را تزریق کنید.

Implicit Binding

لاراول به صورت خودکار مدل‌های الوکوئنت تعریف شده در مسیرها یا اکشن‌های کنترلرها را که نام‌های متغییر با type-hint مشخص منطبق با نام سگمنتی از یک مسیر دارند را resolve می‌کند. برای مثال:

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

از آنجایی که مدل الوکوئنت App\User  به عنوان type-hint برای متغییر $user مشخص شده است و نام متغییر با سگمنت {user} از URI مطابقت دارد، لاراول به صورت خودکار نمونه مدلی را که دارای ID منطبق با مقدار متناظر از URI درخواست شده است تزریق می‌کند. اگر نمونه مدل در دیتابیس یافت نشود، به صورت خودکار یک ریسپانس HTTP با کد 404 تولید خواهد شد.

سفارشی‌سازی نام کلید

اگر می‌خواهید هنگامی که کلاس مدل معین را دریافت می‌کنید، از مدل بایندینگ برای ستونی از دیتابیس غیر از id استفاده کنید، می‌توانید متد getRouteKeyName در مدل الوکوئنت را بازنویسی (override) کنید:

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

Explicit Binding

برای ثبت یک explicit binding، از متد model مسیریاب برای مشخص کردن کلاس یک پارامتر مشخص استفاده کنید. باید explicit model bindingهای خود را در متد boot کلاس RouteServiceProvider تعریف کنید:

public function boot()
{
    parent::boot();

    Route::model('user', App\User::class);
}

سپس، یک مسیر تعریف کنید که دارای یک پارامتر {user} باشد.

Route::get('profile/{user}', function (App\User $user) {
    //
});

از آنجایی که تمام پارامترهای {user} را به مدل App\User محدود کرده‌ایم، یک نمونه از User به مسیر تزریق خواهد شد. بنابراین، برای مثال، یک درخواست به profile/1 نمونه User از دیتابیس که ID آن 1 است را تزریق خواهد کرد.

اگر نمونه مدلی دارای مطابقت در دیتابیس یافت نشود، به صورت خودکار یک ریسپانس HTTP با کد 404 تولید خواهد شد.

سفارشی‌سازی رزولوشن لاجیک (Customizing The Resolution Logic)

اگر می‌خواهید از رزولوشن لاجیک خودتان استفاده کنید، باید از متد Route::bind استفاده کنید. کلوژری که به متد bind پاس می‌دهید، مقدار سگمنت URI را دریافت خواهد کرد و باید نمونه‌ای از کلاس را برگرداند که باید به مسیر تزریق شده باشد:

public function boot()
{
    parent::boot();

    Route::bind('user', function ($value) {
        return App\User::where('name', $value)->first() ?? abort(404);
    });
}

مسیرهای جایگزین (Fallback Routes)

با استفاده از متد Route::fallback، می‌توانید مسیری را تعریف کنید تا هنگامی که ریکوئست ورودی با هیچ مسیر دیگری مطابقت نداشت، اجرا شود. معمولا، ریکوئست‌های هندل‌نشده، به وسیله اکسپشن هندلر اپلیکیشن به صورت اتوماتیک یک صفحه 404 را رندر می‌کنند. گرچه، از آنجایی که ممکن است مسیر fallback را درون فایل routes/web.php اپلیکیشن خود تعریف کنید، تمام میدلورها در گروه میدلور web به این مسیر اعمال خواهند شد. البته، در صورت نیاز در افزودن میدلورهای اضافه به این مسیر آزاد هستید:

Route::fallback(function () {
    //
});

محدودیت نرخ ترافیک ارسالی و دریافتی (Rate Limiting)

لاراول دارای میدلوری برای محدودیت نرخ دسترسی به مسیرهای داخل اپلیکیشن دارد. برای شروع، میدلور throttle را به یک مسیر یا گروهی از مسیرها اختصاص دهید. میدلور throttle دو پارامتر قبول می‌کند که حداکثر تعداد ریکوئست‌هایی که می‌تواند در زمان معینی بر حسب دقیقه ساخته شوند را تعیین می‌کند. برای مثال، اگر تعیین کنیم که یک یوزر احراز هویت شده، حداکثر 60 بار در دقیقه می‌تواند به مسیرهای گروه زیر دسترسی داشته باشد:

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

محدودیت نرخ ترافیک داینامیک (Dynamic Rate Limiting)

حداکثر تعداد ریکوئست‌های داینامیکی را بر اساس یک اتریبیوت مدل User تایید هویت شده، می‌توانید تعیین کنید. برای مثال، اگر مدل User حاوی یک اتریبیوت rate_limit باشد، می‌توانید نام اتریبیوت را به میدلور throttle ارسال کنید تا از آن برای محاسبه حداکثر تعداد ریکوئست‌ها استفاده کند:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

کلک تغییر متد فرم (Form Method Spoofing)

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

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

از دستورالعمل @method مربوط به blade نیز می‌توانید برای تولید فیلد _method استفاده کنید:

<form action="/foo/bar" method="POST">
    @method('PUT')
    @csrf
</form>

دسترسی به مسیر جاری

از متدهای current و currentRouteName و currentRouteAction در فساد Route می‌توانید درباره مسیری که ریکوئست ورودی را هندل می‌کند، اطلاعات به دست آورید.

$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();

برای بازبینی تمام متدهای در دسترس، به داکیومنت API بخش underlying class of the Route facade و Route instance مراجعه کنید.

منبع
Routing