Laravel Validation ขั้นพื้นฐาน มีอะไรบ้าง

1 กุมภาพันธ์ 2564
Laravel Validation ขั้นพื้นฐาน มีอะไรบ้าง

สิ่งสำคัญอย่างนึงในการพัฒนาโปรเจคใน Laravel คือการรู้ว่าเราจะทำการ validate ข้อมูลที่ผู้ใช้ป้อนเข้ามาได้อย่างไรบ้าง Laravel รองรับวิธีการทำ validation ได้หลายแบบในบทความนี้เราจะมาดูวิธีการทำ validation ใน Controller, Form Request และ Rule

Validation ใน Controller

โดยปกติแล้ว Controller ใน Laravel สืบทอดมาจาก Base Controller ที่มีการใช้งาน trait ValidatesRequests

Trait ValidatesRequests ทำให้เราสามารถเรียกใช้ method validate() ใน Controller ได้โดยตรง

ตัวอย่างเช่น ผู้ใช้กำลังจะเพิ่มบทความ Article เข้ามาในระบบใน form อาจมีการระบุชื่อ เนื้อหา และวันที่เผยแพร่ การทำ validation ใน controller จะเขียนแบบใดก็ได้ตามตัวอย่างนี้

// ระบุ validation rules แบบ String โดยใช้ | คั่น
public function store(Request $request) {
    $request->validate([
        'name' => 'required|string',
        'body' => 'required|string',
        'publish_at' => 'required|date_format:Y-m-d H:i:s'
    ]);

    // ...
}

// ระบุ validation rules แบบ array
public function store(Request $request) {
    // Note: the array syntax is also available
    $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // ...
}

// ใช้ request() helper function แทนการ Inject $request
public function store() {
    request()->validate([
      // Validation Rules...
    ]);

    // ...
}

// ใช้ method validate() ใน controller โดยตรง
public function store() {
    $this->validate(request(), [
      // Validation Rules...
    ]);

    // ...
}

ข้อสังเกตอย่างหนึ่งคือ ค่าที่ return มาจาก method validate() จะเป็นข้อมูลที่ถูก validate ออกมาเท่านั้น

public function store(Request $request) {
    $validatedData = $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // ['name' => ..., 'body' => ..., 'publish_at' => ...]
    $this->articleService->store($validatedData);
}

อีกวิธีหนึ่ง เราสามารถเขียนแบบนี้ได้

public function store(Request $request) {
    $request->validate([
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ]);

    // I know that the only keys in validated data are the ones that were successfully validated, i.e.: name, body, published_at
    $this->articleService->store($request->only('name', 'body', 'published_at'));
}

Validation rules ทั้งหมด ที่มากับ Laravel สามารถดูได้ที่  Laravel document

Validation ใน Form Request

ถ้า Logic การทำ Validation เริ่มมีความซับซ้อน เราควรแยกการทำ validation ออกจาก Controller โดยเราสามารถทำการ validation ได้ผ่านทางคลาส Form Request

เราสามารถใช้ Artisan command เพิ่มสร้างคลาส Form Request ให้เราได้ ตามตัวอย่างคำสั่งนี้

php artisan make:request StoreArticleRequest

คลาสที่ถูกสร้างาขึ้นจะอยู่ใน app/Http/Requests 

class StoreArticleRequest extends FormRequest
{

    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            //
        ];
    }
}

คลาส Form request จะมาพร้อมกับ 2 method คือ  authorize และ rules.

authorize()

method authorize() จะป้องกันการ run code ใน controller ถ้า method นี้ return false Laravel จะ throw 401 unauthorized exception

ตัวอย่างการทำ authorize อาจเป็นประมาณนี้

public function authorize()
{
    return $this->user()->can('create', Article::class);
}

rules()

เราสามารถทำการระบุ array ของ field ที่เราต้องการทำ validation ได้ใน method rules() วิธีการระบุสามารถระบุได้เหมือนกับที่เราระบุใน Controller

public function rules()
{
    return [
      'name' => ['required', 'string'],
      'body' => ['required', 'string'],
      'publish_at' => ['required', 'date_format:Y-m-d H:i:s'],
    ];
}

หมายเหตุ: เราสามารถทำการ Type-hint คลาส dependency ที่เราต้องการใช้ใน method rules() ได้

ทีนี้เราสามารถใช้คลาส Form Request ที่เราสร้างขึ้นใน controller ได้ด้วยการ Type-hint ใน method

public function store(StoreArticleRequest $request) {
    // Validation and Rules passed
}

ถ้า validation fail ผู้ใช้จะถูก redirect พร้อมข้อมูล error flash ลง session ถ้าเป็น AJAX request จะเป็น Response status 422 Unprocessable Entity

เราสามารถใช้ข้อมูลที่ validate มาได้เหมือนก่อนหน้านี้

public function store(StoreArticleRequest $request) {
    $validatedData = $request->validated();

    // Insert into database
    ...
}

สร้างคลาส Custom Rule

ถ้าเราต้องการทำ Validation ที่ไม่มีมาพร้อมกับ Laravel เราสามารถสร้าง คลาส Validation Rule ขึ้นมาใหม่ได้

เราสามารถสร้างคลาส Rule ได้โดยช้ Artisan command

php artisan make:rule IsValidStateInUSA

คลาส Rule ที่ถูกสร้างขึ้นจะอยู่ใน app/Rules

class IsValidStateInUSA implements Rule
{

    public function passes($attribute, $value)
    {
        //
    }

    public function message()
    {
        return 'The validation error message.';
    }
}

เราสามารถระบุ code เพื่อทำการตรวจสอบ validation ได้ใน method passes() โดย return true ถ้าผ่านการ validation ส่วน method message() ไว้ทำการแสดงข้อความกรณีที่ validation fail

ใช้ตัวอย่างจากคลาส Is a valid State in the USA, เราอาจเขียน code ออกมาได้หน้าตาประมาณนี้

class IsValidStateInUSA implements Rule
{

    public function passes($attribute, $value)
    {
        return in_array(strtoupper($value), [
          'AL',
          'AK',
          'AZ',
          ...
        ]);
    }

    public function message()
    {
        return 'This is not a valid state code in the USA.';
    }
}

วิธีการใช้งานคลาส Validation Rule ที่เราสร้างขึ้นสามารถทำได้โดยการ new คลาสขึ้นมา ใน array ของ rule ที่เราต้องการ validate ใน field ที่กำหนด

public function store(Request $request) {
    $request->validate([
      'state' => ['required', new IsValidStateInUSA],
    ]);

    ...
}

การจัดการกับ Validation Error

Laravel จะทำการ redirect ให้เราโดยอัตโนมัติถ้ามีการ fail validation โดยจะมีตัวแปร $errors ที่ถูกส่งให้ view ทุกครั้งอยู่แล้ว

เราสามารถสร้าง blade view messages.blade.php แล้ว include ใน layout ของเรา เพื่อแสดง validation error message ได้

@if($errors->any())
    <div class="alert alert-danger" role="alert">
        <button type="button" class="close" data-dismiss="alert" aria-label="Close">
            <span aria-hidden="true">×</span>
        </button>

        @foreach($errors->all() as $error)
            {{ $error }}<br/>
        @endforeach
    </div>
@endif

ซึ่งจะแสดง error ทั้งหมดที่เก็บใน session ถ้าเราต้องการแสดง error ทีละ field เราะสามารถใช้ helper @error ช่วยได้

@error('title')
    <div class="alert alert-danger">{{ $message }}</div>
@enderror

ใน @error tag จะมีตัวแปร $message ให้เราใช้งานได้โดยอัตโนมัติ

การแก้ไขข้อความ Error

เวลาที่เราทำงานกับ method validate() เราสามารถ override ข้อความ error ได้โดยการส่ง parameter ตัวที่สาม

public function store(Request $request) {
    $this->validate($request, [
        'name' => 'required|string',
        'body' => 'required|string',
        'publish_at' => 'required|date_format:Y-m-d H:i:s'
    ], [
      'name.required' => 'A article name is required',
      'body.required'  => 'A article body is required',
      'publish_at.date_format' => 'The publish at date is not in the correct format.'
    ]);

    // ...
}

ถ้าเป็นกรณี Form Request เราสามารถใช้ method messages() เพื่อ override ข้อความ error ในแต่ละ field และแต่ละ rule ได้เช่นเดียวกัน

public function messages()
{
    return [
        'name.required' => 'A article name is required',
        'body.required'  => 'A article body is required',
        'publish_at.date_format' => 'The publish at date is not in the correct format.'
    ];
}

สรุป

จากบทความนี้เราได้เรียนรู้ถึงวิธีการทำ Validation แบบต่าง ๆ ใน Laravel ตั้งแต่วิธีพื้นฐานสุดคือการ validate ใน Controller เราได้รู้จักการสร้างคลาส Form Request สำหรับ validation ที่ซับซ้อนขึ้น การสร้าง Customer Validation Rule สำหรับ logic การทำ validation ที่เราต้องการกำหนดขึ้นมาเอง รวมไปถึงการแก้ไขข้อความ error ถ้าเราอยากเรียนรู้เรื่องการทำ Validation ใน Laravel ให้มากขึ้น ลองศึกษาเพิ่มเติมได้จากใน Laravel Documentation

Phattarachai Chaimongkol
เกี่ยวกับ phattarachai.dev

สวัสดีครับ เป็น Full Stack Web Developer สามารถดูแลงานทั้งระบบได้ ทำงานสายนี้มากว่า 10 ปี ผ่านงานทางภาครัฐ เป็นที่ปรึกษาบริษัทเอกชน มีงาน Web App ทั้งเล็กและใหญ่ ระบบ Inventory, งาน ERP พร้อมใช้ประสบการณ์ที่มีแก้ไขปัญหาธุรกิจให้ลูกค้าครับ

เรื่องล่าสุด

งานพัฒนา Platform Video E-learning
1 กุมภาพันธ์ 2564
งานพัฒนา Platform Video E-learning
รับงาน Web Scrapping อ่านข้อมูลเว็บไซต์ส่งแจ้งเตือน Line Notification
1 กุมภาพันธ์ 2564
รับงาน Web Scrapping อ่านข้อมูลเว็บไซต์ส่งแจ้งเตือน Line Notification
รับงาน ดึงข้อมูลโพสต์ Facebook Group / รูปภาพ / เนื้อหา ลงไฟล์ ส่งเข้า Google Drive
1 กุมภาพันธ์ 2564
รับงาน ดึงข้อมูลโพสต์ Facebook Group / รูปภาพ / เนื้อหา ลงไฟล์ ส่งเข้า Google Drive