در قسمت قبل با قرارداد مربوط به RESTful Resource Controller آشنا شدیم:
و برایتان توضیح دام که action مورد نظر ما Show می باشد اما در URL مربوط به آن علامت های Curly braces (همان {}) را داشتیم که نشان دهنده وجود متغیر در URL است. بهترین راه یادگیری این موضوع کار عملی است بنابراین بیایید با من به فایل Web.php در پوشه routes رفته و بگوییم:
Route::get('/profile/{user}', 'ProfilesController@index')->name('profile.show');
همانطور که می بینید من آدرس را به {user}/Profile/ تغییر داده ام. ما می توانیم نام قسمت متغیر را خودمان انتخاب کنیم و از آنجایی که می خواهیم یک کاربر (user) را نمایش بدهیم من user را انتخاب کرده ام اما شما می توانید هر مقدار دیگری را بنویسید. همچنین اگر به تصویر بالا نگاه کنید می بینید که در ستون انتهایی جدول چیزی به نام Route Name داریم که ساختار resource.show را برای ما دارد بنابراین نام این route را profile.show گذاشته ام. قبلا توضیح داده ام که متد ()name به ما اجازه می دهد یک Route خاص را نام گذاری کنیم. حالا که این متغیر را در URL داریم، چطور باید آن را در کنترلر دریافت کنیم؟
برای این کار به کنترلر خودمان (فایل ProfilesController.php) می رویم و آن را در قالب یک آرگومان دریافت می کنیم:
class ProfilesController extends Controller { public function index($user) { dd($user); return view('home'); } }
همانطور که می بینید user$ به صورت خودکار دریافت می شود. من تابع dd را صدا زده ام که مخفف die and dump است و دو کار را انجام می دهد: ابتدا هر چه به آن پاس بدهید را در مرورگر نمایش می دهد و سپس اسکریپت را متوقف می کند (برنامه درجا می میرد). این کار را کرده ام تا ببینم درون user$ چیست. حالا بیایید به آدرس http://127.0.0.1:8000/profile/1 در مرورگر برویم. با این کار باید عدد 1 را در مرورگر دریافت کنید. آیا متوجه ساختار URL در لاراول و معنی متغیر های URL شدید؟ ساختار کلی URL ما به شکل زیر بود:
/profile/{user}
بنابراین قسمت اول ثابت و قسمت دارای {} متغیر است و هر چیزی که در مرورگر وارد شود به جای آن قرار می گیرد. مثلا اگر به آدرس http://127.0.0.1:8000/profile/roxo.ir برویم در مرورگر رشته "roxo.ir" را دریافت می کنیم. امیدوارم با این مثال مفهوم متغیر در URL را درک کرده باشید. من دیگر به دستور dd نیازی ندارم بنابراین آن را پاک می کنم.
مسئله اینجاست که ما واقعا خود کاربر را می خواهیم نه یک رشته دلخواه! چطور به خود کاربر دسترسی داشته باشیم؟ اگر یادتان باشد برایتان توضیح دادم که هر فایل یا کلاس Model نماینده یک جدول در پایگاه داده است و هر شیء ساخته شده (instance) از کلاس Model نماینده یک ردیف از آن جدول (یک کاربر) است. از طرفی در حال حاضر فقط یک Model داریم که در پوشه app قرار داشته و User.php نام دارد بنابراین برای دریافت یک کاربر خاص می توان گفت:
class ProfilesController extends Controller { public function index($user) { User::find($user); return view('home'); } }
متد find که در کد بالا استفاده کرده ایم (روی کلاس User یا همان فایل User.php که Model ما است صدا زده شده) یک آرگومان دریافت کرده و آن را به عنوان primary key در پایگاه داده جست و جو می کند. مثلا اگر user$ در کد بالا یک متغیر عددی باشد، فرض می کنیم 2، این دستور در پایگاه داده و در ستون primary key ها به دنبال ردیفی می گردد که مقدارش 2 باشد.
حالا در پروژه های عادی و غیر لاراول این primary key را خودتان در پایگاه داده MySQL تعیین می کنید (primary key ربطی به لاراول ندارد و از مباحث MySQL است بنابراین باید با آن آشنا باشید) اما در لاراول Eloquent (سیستم کار با پایگاه داده در لاراول) ستون id از جدول شما را به عنوان primary key در نظر می گیرد. اگر می خواهید این رفتار را غیرفعال کنید باید به فایل Model خود رفته و خصوصیت زیر را برایش تعریف کنید:
protected $primaryKey = 'username';
در اینجا من username را به عنوان primary key در نظر گرفته ام. مسئله بعدی اینجاست که primary key در لاراول به صورت خودکار یک عدد صحیح (integer) و auto-incrementing (افزایش خوکار عدد در هر ردیف) در نظر گرفته می شود. برای حل این مشکل باید خصوصیت زیر را نیز در فایل Model خود تعریف کنید:
public $incrementing = false;
همچنین در این مثال که primary key من عددی نیست باید خصوصیت زیر را در Model تعریف کنم:
protected $keyType = 'string';
بیایید دوباره به محتوای کنترلر خودمان (ProfilesController.php) نگاه بیندازیم. فایل User.php در namespace این فایل نیست. چرا؟ کنترلر ما در namespace کنترلرها است (namespace App\Http\Controllers) اما Model در namespace خودش است (App\User) بنابراین گفتن User::find باعث ایجاد خطا می شود (باید با مبحث namespace در php آشنا باشید) با این حساب دو راه حل داریم. اول اینکه namespace را به صورت دستی ذکر کنیم که روش جالبی نیست اما کار می کند:
\App\User\User::find($user);
اما روش بهتر این است که از ویرایشگرهای کد پیشرفته مانند Visual Studio Code یا PHPStorm استفاده کنید. اگر این کار را انجام بدهید، namespace به صورت خودکار در این فایل ثبت می شود. به ویدیوی زیر توجه کنید:
همانطور که می بینید Visual Studio Code به صورت خودکار عملیات use را برای من انجام می دهد تا به آن namespace نیز دسترسی داشته باشم. این بار به جای اینکه رشته وارد شده در URL مرورگر را به عنوان user$ دریافت کنیم، user$ را به عنوان primary key در پایگاه داده جست و جو کرده ایم و طبیعتا برای اینکه ببینیم این بار user$ چه محتوایی دارد از dd استفاده می کنیم:
public function index($user) { dd(User::find($user)); return view('home'); }
با مراجعه به مرورگر و بسته به URL آن پاسخ های مختلفی می گیرد. به طور مثال اگر به آدرس http://127.0.0.1:8000/profile/roxo.ir برویم، مقدار null را در مرورگر می بینیم. چرا؟ به دلیل اینکه roxo.ir یک primary key در پایگاه داده ما نیست و نتیجه قطعا null است (یادتان باشد که ما قسمت متغیر یا همان user$ را در پایگاه داده جست و جو می کنیم). اگر به آدرس http://127.0.0.1:8000/profile/1 برویم نتیجه زیر را می گیریم:
همانطور که می بینید اطلاعات بسیار زیادی برگردانده شده است. این نتیجه را گرفتیم چرا که قسمت متغیر URL ما که در اینجا 1 است به عنوان primary key در پایگاه داده جست و جو شده است. از طرفی می دانیم که primary key به صورت پیش فرض همان ستون id است و ما آن را عوض نکردیم بنابراین حتما ردیفی با id=1 در پایگاه داده ما وجود دارد. در قسمت بعد در مورد این نتایج صحبت خواهیم کرد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.