ثبت و ارسال داده‌های فرم در لاراول

Registration and Submission of Form Data in Laravel

25 بهمن 1399
Laravel 7.0: ثبت و ارسال داده های فرم در لاراول (قسمت 25)

ما در جلسه قبل فرمی را ساختیم تا کاربر بتواند با استفاده از آن از یک پست جدید بگذارد اما این کار را فقط در سمت client (ظاهر مرورگر) انجام دادیم و هنوز هیچ منطقی در سرور برای مدیریت آن ننوشته ایم. در این جلسه می خواهم در مورد ثبت کردن فرم در لاراول صحبت کنیم. در قدم اول دوباره به قرارداد RESTful resource controllers نگاهی می اندازیم:

قرارداد نام گذاری و مدیریت route ها بر اساس RESTful resource controller
قرارداد نام گذاری و مدیریت route ها بر اساس RESTful resource controller

همانطور که می بینید ما در مسیر p/create فرم را نشان می دهیم و باید برای store (ذخیره و ثبت) آن را به مسیر p/ ارسال کنیم. با این حساب به فایل create.blade.php رفته و action فرم را روی همین آدرس قرار می دهیم:

@section('content')
<div class="container" style="max-width: 850px">
    <form action="/p">
// بقیه کد ها //

از طرفی می دانیم که این فرم یک فایل را قبول می کند (تصویر پست) بنابراین حتما باید enctype آن را درست تنظیم کنیم:

<form action="/p" enctype="multipart/form-data">

این ربطی به لاراول ندارد و از مباحث HTML است بنابراین امیدوارم با encryption type ها یا همان enctype آشنا باشید (اطلاعات بیشتر در https://www.w3schools.com/tags/att_form_enctype.asp). در مرحله بعد باید متد ارسال اطلاعات را نیز روی POST بگذاریم چرا که enctype فقط روی فرم هایی با متد POST کار می کند. دلیل دیگر و مهم تر نیز این است که طبق قرارداد های RESTful (ردیف سوم در تصویر بالا) باید متد ما POST باشد:

<form action="/p" enctype="multipart/form-data" method="POST">

در مرحله بعدی باید به فایل web.php برویم تا این مسیر جدید را تعریف کنیم:

Route::get('/p/create', 'PostsController@create');
Route::post('/p', 'PostsController@store');

یادتان باشد که مسیر get و post حتی برای یک URL با هم تفاوت دارند. در کد بالا گفته ام که در مسیر p/ باید متد store صدا زده شود. هنوز چنین متدی وجود ندارد بنابراین به کنترلر PostsController.php رفته و می گوییم:

class PostsController extends Controller
{
    public function create()
    {
        return view('posts.create');
    }

    public function store()
    {
        dd(request()->all());
    }
}

من در اینجا تمام داده های درخواست را dd کرده ام تا در مرورگر نمایش داده شود. متد کمکی request به شما اجازه می دهد به instance درخواست فعلی دسترسی داشته باشید اما متد کمکی all نیاز به توضیح کوچکی دارد. ما برای دریافت داده ها از سمت پایگاه داده روی یک کوئری دو متد داریم:

  • ()get: این متد، متدی روی شیء Eloquent\Builder است که مستقیما به کوئری وصل شده و روی آن اجرا می شود بنابراین می توان گفت که در سمت پایگاه داده اجرا می شود. به زبان ساده این متد یک query builder است.
  • ()all: این متد یک متد static در Eloquent\Model است و کارش ساختن یک شیء query و سپس صدا زدن get روی آن است بنابراین پس از اجرا شدن روی پایگاه داده اجرا می شود و طبیعتا نمی تواند کارهایی مثل ویرایش کوئری را انجام بدهد. به زبان ساده این متد یک Laravel collection است.

مثالی از نحوه استفاده از این دو متد:

$activeCustomers = Customer::where('active', 1)->get(); //query builder
$activeCustomers = Customer::all()->where('active', 1); //Laravel collection

بنابراین در کنترلر خودمان با صدا زدن ()all گفته ایم که تمام داده های درخواست را به ما بده. در برنامه های عادی همیشه بهتر است که از get استفاده کنید چرا که سریع تر است اما اینجا برایمان اهمیتی ندارد (همچنین داده ها از سمت پایگاه داده نمی آیند بلکه یک درخواست از فرم HTML ما است).

حالا برای تست این کد ها به فرم خود می رویم (مسیر http://127.0.0.1:8000/p/create) و فرم را ثبت می کنیم (با هر تصویر و هر Caption ای که دوست دارید). با ثبت فرم یک خطای 419 با متن Page Expired می گیریم. آیا می دانید مشکل کجاست؟ این خطا یک خطای CSRF است که در جلسات قبل در مورد آن صحبت کرده بودیم (مراجعه کنید به قسمت 11). برای یادآوری می گویم که CSRF مخفف cross-site request forgery (به فارسی: جعل درخواست میان‌وب‌گاهی) است که یک نوع حمله توسط هکر ها می باشد که طی آن یک فرد (هکر) خودش را به جای شما (کاربر) جا می زند. لاراول به صورت خودکار از این نوع حملات جلوگیری می کند. برای این کار باید دستور csrf@ را در تک تک فرم های خود قرار دهید بنابراین این کار را در create.blade.php انجام می دهیم:

    <form action="/p" enctype="multipart/form-data" method="POST">
        @csrf
        <div class="row">
// بقیه کد ها //

یادتان باشد که csrf@ باید درون تگ <form> باشد. پس از ذخیره کردن فایل دوباره به صفحه http://127.0.0.1:8000/p/create رفته و از dev tools مرورگر (کلید f12 یا گزینه inspect) به محتویات فرم نگاه کنید. باید چیزی شبیه به input زیر را ببینید:

<input type="hidden" name="_token" value="iYPauE8Hjkq1BhYAF0CLfZAc66I4dP2tdMNG2OEC">

این فیلد مخفی (hidden) به صورت خودکار توسط همان دستور scrf@ تولید شده است. value آن یک رشته طولانی و رمزنگاری شده است که به لاراول اجازه می دهد کاربر را تایید صلاحیت کند تا مطمئن شود این درخواست از سمت مرورگر کاربر آمده است نه از سمت فرد دیگری. حالا دوباره فرم را ثبت کنید. این بار بدون مشکل نتیجه زیر را می گیرید که همان ()dd ما است:

فرم ثبت شده ی ما در سمت سرور با استفاده از ()dd چاپ شده است
فرم ثبت شده ما در سمت سرور با استفاده از ()dd چاپ شده است

در تصویر بالا فقط token_ (رشته CSRF) و image را داریم و خبری از caption نیست. آیا می دانید چرا؟ ما برای فیلد caption این name ای را ننوشته ایم بنابراین باید attribute آن را در HTML اضافه کنیم:

<input id="caption" type="text" class="form-control @error('caption') is-invalid @enderror" name="caption" value="{{ old('caption') }}" autocomplete="caption" autofocus>

من اشتباها به جای name=caption مقدار caption=caption را نوشته بودم. حالا اگر دوباره فرم را ثبت کنید همه چیز به خوبی کار می کند. حالا اگر دوباره به تصویر بالا نگاه کنید متوجه خواهید شد که image ما تبدیل به یک کلاس شده است! یعنی لاراول برای راحتی ما فایل تصویر را در یک کلاس قرار داده و ابزاری را هم به همراهش به ما داده است که به وقت خود از آن ها استفاده خواهیم کرد.

در جلسه بعد در رابطه با اعتبارسنجی (validation) صحبت خواهیم کرد.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری ساخت اینستاگرام با Laravel 7 توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

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

محمد
09 خرداد 1400
با سلام و تشکر از اموزش های خوب و کاملتون میخواستم بدونم این سری کی تموم میشه ؟ چند درس دیگه مونده ؟

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