با درود. با یکی دیگه از فصلهای آموزش لاراول به زبان فارسی در خدمت شما عزیزان هستیم. اگر چنانچه فصل ۱ و ۲ این مجموعه آموزشی را مطالعه نکردهاید همین الان از منوی بالای صفحه مسیر «برنامهنویسی -> Laravel» را انتخاب کرده و از ابتدا شروع کنید. چون فرآیند نصب و معرفی لاراول در دو فصل گذشته آموزش دادهشده است. خب بسیار عالی! وارد فصل ۳ شدیم. مباحث این فصل شامل بحث کنترلرها (Controllers) و مسیریابی یا مسیردهی (Routing) است که این دو مبحث مهم را به صورت کامل از ۰ تا ۱۰۰ توضیح خواهیم داد و تا جاییکه ممکنه سعی کردهایم تمام جزئیات رآموزش دهیم.
بسیاری از توابع کاربردی در هر نرمافزار تحت وب که با فریمورک نوشته میشود دریافت درخواست از کاربر و ارسال پاسخ است که معمولا توسط پروتکلهای HTTP یا HTTPS صورت میپذیرد. این بدین معنیست که طراحی مسیرهایی که کاربر وارد آن میشود و درخواستی برای سرور ارسال میکند بسیار مهم و از اصلیترین و اولین مقدمهی هر نرمافزار تحت وب است. بگونهای که بدون مسیرها (Routes) نرمافزار شما هیچ قابلیتی نخواهد داشت. در ادامه به توضیح دقیق نحوهی تعریف مسیرها و همچنین کنترل آنها توسط فریمورک قدرتمند لاراول میپردازیم.
در لاراول ۵.۴ مسیرها (Routes) در پوشهی routes تعریف شدهاند. البته در نسخههای قبلی این مسیر به صورت app/Http/routes.php بود. سادهترین راه برای تعریف یک مسیر انطباق یک URI مانند "/" به یک Clouser (بستار) است:
یک سوال: URI چیست؟
پاسخ: URI به مجموعهی URLها و URN ها گفته میشود. برای روشنتر شدن این موضوع یک مثال خیلی مشخص میزنیم:
تعریف URI: هر آدرسی که منبع مشخصی نداشته باشد. (مثل آدرس درایوها در ویندوز و ...) به نمونهی زیر توجه کنید:
Files/main/page.html
تعریف URL: هر آدرسی که دارای منابع باشند مانند منبع http, https و ftp و ... . (مثل آدرس وب سایتها و ...) به نمونهی زیر توجه کنید:
http://www.roxo.ir/laravel/page.html
تعریف URN: هر آدرسی که منبع آن یک نام باشد. (مثل بارکد کتابها و ...) به نمونهی زیر توجه کنید:
ISBN 1-2345-678-9
نکته قابل توجه: هر URL میتواند یک URI باشد و هر URN نیز مجددا میتواند یک URI باشد ولی هیچگاه یک URL نمیتواند یک URN باشد یا بالعکس.
یک سوال: Clouser چیست؟
پاسخ: توابعی هستند که عنوان شیء، پارامتر و متغییر به سایر توابع، متدها یا رویدادها ارسال میشوند.
حال که با تعاریف Clouser و URI آشنا شدید اولین مثال لاراولی خود را ارائه داده تا شما را با مسیردهی لاراول آشنا کنیم. بنابراین مسیر routes/web.php را باز کرده و دستورهای موجود در آن را به حالت غیرفعال (کلید میانبر /+ctrl) درآورده و کدهای زیر را اضافه کنید:
Route::get("/",function(){ return "Hello Roxo"; });
این دستور به سیستم مسیردهی لاراول فرمان میدهد که هر گاه کاربر مسیر /http://www.roxo.ir را وارد کرد پیغام Hello Roxo را نمایش دهد. یا به اصطلاح هرگاه کاربر مسیر روت اصلی وب سایت را مشاهده کرد پیام موردنظر چاپ شود. شاید این سوال برای شما پیش بیاید که چرا بجای استفاده از Echo یا Print از دستور return برای نمایش رشتهها استفاده کردیم. نکته قابل توجه این است که درخواستها و پاسخهای کاربران از یک کانال به نام MiddleWare یا میانافزار عبور میکنند و سپس به کاربر بازگردانده میشوند. بنابراین دستور return مستقیما به کاربر ارسال نمیشود. بلکه از فیلتر میانافزار یا MiddleWare میگذرد.
همچنبن توجه داشته باشید که در فایل web.php و یا هر فایل Route دیگری میتوان چندصد Route تعریف کرد. به مثال زیر توجه کنید:
Route::get('/', function () { return view('welcome'); }); Route::get('about', function () { return view('about'); }); Route::get('products', function () { return view('products'); }); Route::get('services', function () { return view('services'); });
فراخوانی استاتیک (ساکن)
اگر شما تجربهی برنامهنویسی به زبان PHP را داشته باشید، شاید از نحوهی فراخوانی استاتیک متدها (مثلا متد get) در کلاسها (مثلا کلاس ::Route) حیرتزده باشید. ولی در حقیقت این متدها Static نیستند بلکه لاراول از مفهومی به نام Facade استفاده میکند. به عنوان نمونه اگر شما مثال اول را با بدون Facade بنویسید به صورت زیر خواهد بود:
$router->get('/', function(){ return 'Hello Roxo'; });
یک سوال: Facade چیست؟
پاسخ: یک Interface است که وابستگیهای خارجی یک کلاس را به حداقل رسانده و باعث خواناتر شدن کدها و برنامهها میشود.
همراهان گرامی جهت تسط به مباحث مسیردهی لاراول باید به متدهای پروتکل HTTP تسلط کامل داشته باشید. برای این منظور مقالهای به زبان ساده و روان آماده کردهایم که مطالعه آن خالی از لطف نیست:
همانطور که در بالا اشاره کردیم برای متوجه شدن مفاهیم متدهای پروتکل HTTP حتما مقاله فوق را مطالعه بفرمایید. در نتیجه لاراول نیز با استفاده از Facade مسیردهی (::Route) تمام متدها را به زیباترین شکل ممکن پشتیبانی میکند. متدها به شرح زیر میباشند:
همانطور که در جریان هستید شکل ظاهری استفاده از Closure ها مناسب یک وب اپلیکیشن قدرتمند نیست چون بعدها فرمانها گسترش پیدا کرده و صفحهی Route ما بسیار ناخوانا خواهد شد. یک راه معمول برای مسیردهی استفاده از نام کنترلرها برای تعریف مسیردهی است:
Route::get('/', 'WelcomController@inedx');
این عبارت و دستور در واقع درخواست را به آدرس URI که معادل App\Http\Controllers\WelcomeController و در نهایت متد ()indexارسال میکند. این متد دقیقا مشابه یک Clouser در مثالهای بالاست.
اگر داخل URI یک پارامتر وجود داشته باشد میتوان آن را مستقیما به Clouser یا متد ارسال کرد. به مثال زیر توجه کنید:
Route::get('users/{id}/friends', function ($id) { // });
همچنین میتوان از پارامترهای پیشفرض استفاده کرد. به عنوان مثال پارامتر پیشفرض id$ در مثال فوق برابر fallbackId است:
Route::get('users/{id?}', function ($id = 'fallbackId') { // });
و میتوان از عبارات باقاعده (Regular Expression) استفاده کرد. این عبارات مانند یک شرط عمل میکنند بدین صورت که اگر شرط برقرار باشد Route مخصوص به آن اجرا میشود:
Route::get('users/{id}', function ($id) { // })->where('id', '[0-9]+'); Route::get('users/{username}', function ($username) { // })->where('username', '[A-Za-z]+'); Route::get('posts/{id}/{slug}', function ($id, $slug) { // })->where(['id' => '[0-9]+', 'slug' => '[A-Za-z]+']);
برای خروجی فوق اگر کاربر آدرس users/abc را وارد کند route دوم اجرا خواهد شد و اگر عبارت posts/abc/123 در مرورگر وارد شود Route اول اجرا خواهد شد.
در حالت پیشفرض میتوان با استفاده از تابع ()url هر جای نرمافزار خود از مسیردهی ها استفاده کنید. به عنوان مثال:
<a href="<?php echo url('/'); ?>">
اما لاراول برای شما امکانی را فراهم کرده است که برای هر Route یا مسیر خود یک نام دلخواه انتخاب کرده تا در صورت لزوم مسیرهای پیچیده را با نام اختصاری آنها معرفی کنید. به مثال زیر توجه کنید:
Route::get('members/{id}', [ 'as' => 'members.show', 'uses' => 'MembersController@show' ]); // فایل View <a href="<?php echo route('members.show', ['id' => 14]); ?>">
در این مثال به برخی مفاهیم باید اشاره کرد. اولین مبحث تخصیص آرگومان دوم به شکل آرایه به متد get در سیستم مسیردهی Route است. لاراول آرگومان دوم Route را چک میکند و اگر Clouser بود آن را به صورت هوشمند اجرا میکند یا اگر رشته باشد آن را به عنوان یک معرف کنترل و متدهای همراه آن، میشناسد یا در صورت وجود یک آرایه (مانند مثال فوق) لاراول انتظار دریافت پارامترهایی دارد تا بتواند روی سیستم مسیردهی اعمال کند. پس در زیر به صورت خلاصه و تیتروار انواع پارامترهایی که به عنوان آرگومان دوم به Route و متدهای مرتبط به آن ارسال میشوند را بررسی میکنیم:
همانطور که در مثال فوق مشاهده میکنید یک نام مستعار برای این مسیردهی (route) تحت عنوان members.show اختصاص داده شده است. که این نامگذاری از یک قاعده و قانون کلی تبعیت میکند که توسط لاراول ایجاد شده است. این قانون بدین صورت است: resourcePlural.action، یعنی قسمت اول نام کنترلر به صورت جمع و camel-case است و قسمت دوم نام اکشن یا متد.
بنابراین با استفاده از ویژگی (Property)تحت عنوان "as" نام این روت (route) یا مسیر را "members.show" قرار داده ایم. سپس با استفاده از ویژگی "uses" نام کنترلر مربوطه را به این مسیر معرفی کردهایم.
در نظر داریم که اختصاص نام مستعار مسیر برای یک Coluser امکانپذیر است. به مثال زیر توجه کنید:
Route::get('/members/{id}/edit', [ 'as' => 'members.edit', function ($id) { // } ]);
بسیار عالی! حال به معرفی توابع موردنیاز برای لینک دادن به این مسیرها، اشاره میکنیم. این توابع معمولا در view مورد استفاده قرار میگیرد:
()url
این تابع و متد زمانی استفاده میشود که روتها پارامتری نداشته باشند. به عبارت دیگر نام مستعاری برای آنها تعریف نشده باشد.
()route
این تابع زمانی استفاده میشود که روت و مسیر ما دارای نام مستعار باشد و یا پارامتری برای آن تعریف کرده باشیم.
یک مثال جامع برای مبحث پارامترهای Route ارائه میدهیم تا این مبحث رو به اتمام برسانیم:
درنظر بگیرید که شما آدرسی به صورت زیر دارید:
users/{userId}/comments/{commentId}
حال میخواهیم برای userId=1 و commentsId=2، انواع پارامترها را به همراه کاربرد آنها در View نمایش دهیم:
Route::get('users/{userId}/comments/{commentId}, [ 'as' => 'users.comments.show', 'uses' => 'UsersCommentsController' ]); =================================== حالت ۱: route('users.comments.show', [1, 2]) خروجی: // http://www.roxo.ir/users/1/comments/2 =================================== حالت ۲: route('users.comments.show', ['userId' => 1, 'commentId' => 2]) خروجی: // http://www.roxo.ir/users/1/comments/2 =================================== حالت ۳: route('users.comments.show', ['commentId' => 2, 'userId' => 1]) خروجی: // http://www.roxo.ir/users/1/comments/2 =================================== حالت ۴: route('users.comments.show', ['userId' => 1, 'commentId' => 2, 'opt' => 'a']) خروجی: // http://www.roxo.ir/users/1/comments/2?opt=a
گروهبندی مسیرها یکی از امکانات فوقالعادهایست که لاراول در اختیار شما قرار میدهد تا از تکرار یک سری پسوند و فضای نامها (namespace) خودداری نمایید. همچنین از این گروهبندیها برای اعمال برخی کامپوننتهای امنیتی و تایید هویت کاربری (authentication) بر روی یک دسته مسیر (routes) استفاده میشود. این امر از تکرار بسیاری از route ها جلوگیری میکند و مسیردهی اپلیکیشن شما را بسیار منظم و مرتب میکند.
برای تعریف کردن یک یا چندین گروه باید از متد group به صورت زیر استفاده کنید:
Route::group([], function () { Route::get('hello', function () { return 'Hello'; }); Route::get('world', function () { return 'World'; }); });
مثال بالا هیچ فرقی با حالت route عادی ندارد. زیرا مقدار آرگومان اول group نباید هرگز خالی باشد.
همانطور که قبلا اشاره کردیم، میانافزارها (Middleware) را میتوان به عنوان یک فیلتر و با استفاده از عبارت group یا Route::middleware به مسیردهی خود اضافه کنیم. به مثال زیر توجه کنید:
Route::group(['middleware' => 'auth'], function () { Route::get('dashboard', function () { return view('dashboard'); }); Route::get('account', function () { return view('account'); }); });
در این مثال میانافزار تایید هویت (authentication) به مسیرهای http://www.roxo.ir/dashboard و http://www.roxo.ir/account اعمال شده است که باعث میشود کاربر بدون ورود و عضویت نتواند وارد بخشهای داشبورد و اکانت شود.
گاهی نیاز داریم که برای نرمافزار خود یک API تولید کنیم و آن را در اختیار سایر افراد قرار دهیم در این صورت باید مسیر API به صورت http://www.roxo.ir/api/help باشد. حال برای اینکه مسیر api/ را مدام تکرار نکنیم از یک پسوند استفاده کرده و مسیرهای درون آن را گروهبندی میکنیم. این مفهوم را با مثال زیر شفافتر توضیح میدهیم:
Route::group(['prefix' => 'api'], function () { Route::get('/', function () { // }); Route::get('help', function () { // }); });
در این حالت همانطور که مشاهده میکند پسوند api/ به تمام زیر گروهها اضافه میشود.
این امر همانند پسوند دادن به نرمافزار است با این تفاوت که ساب دامین را به عنوان یک پسوند به مسیرها اعمال میکنیم. مثال زیر را مشاهده کنید:
Route::group(['domain' => 'api.roxo.ir'], function () { Route::get('/', function () { // }); });
برای کنترلرهایی که فضاینام (namespaces) مشترکی دارند میتوان مسیردهی را گروهبندی کرد. در مثال زیر کنترلرهای موجود در فولدر API با فضای نام تعیین شده دیگر تکرار نخواهند شد:
// بدون اعمال کردن namespace // App\Http\Controllers\ControllerA Route::get('/', 'ControllerA@index'); // همراه با اعمال namespace Route::group(['namespace' => 'API'], function () { // App\Http\Controllers\API\ControllerB Route::get('/', 'ControllerB@index'); });
از این نوع گروهبندی برای جلوگیری از تکرار URI از نامهای مستعار استفاده میکنیم. بنابراین عبارت users/comments/5 توسط یک نام مستعار مشابه users.comments.show نمایش داده خواهد شد. به مثال زیر دقت کنید:
Route::group(['as' => 'users.', 'prefix' => 'users'], function () { Route::group(['as' => 'comments.', 'prefix' => 'comments'], function () { Route::get('{id}', ['as' => 'show', function () { // }]); }); }); // در نهایت کل این مسیر در خروجی با عبارت: //users.comments.show // در دسترس است.
به شما تبریک میگوییم، با آموزش فوق شما به راحتی میتوانید مسیردهیهای وب اپلیکیشن خود را ایجاد کرده و در نهایت امر به تولید یک محصول کارآمد و بدون نقص بپردازید. مسیردهی (routing) به شما کمک میکند تا نرمافزاری تمیز و بدون نقص ایجاد کرده تا در صورت امکان در برههای از زمان بتوانید آن را بروزرسانی کنید و دچار سردرگمی نشوید! در جلسهی آینده به توضیح مفصل کنترلرها میپردازیم. با ما همراه باشید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.