ฐานข้อมูล

การดำเนินการกับฐานข้อมูลของ ลาราเวล ใช้การต่อเชื่อมและทำงานด้วย PDO ซึ่งเป็นไลบรารีที่ทำงานกับฐานข้อมูลได้หลายชนิด และสนับสนุนการทำงานแบบออบเจ็กต์ที่สมบูรณ์ เมื่อใช้ PDO ก็ทำให้สนับสนุนการใช้งานตามมาตรฐานภาษา SQL นอกจากนี้ ลาราเวลเองยังเพิ่มเติมการทำงานกับฐานมูลในสองลักษณะและสามารถใช้ร่วมกันได้คือ

ทั้งสองชนิดของการดำเนินการข้อมูลช่วยอำนวยความสะด้วยได้มาก แล้วจะได้พบว่าง่ายทั้งคู่ แต่ก่อนที่จะใช้ของง่ายขอยกตัวอย่างของยากกว่าแต่ก็ไม่มาก เพื่อให้เข้าใจว่าก่อนที่จะเป็นของง่ายเขาทำกันอย่างไง โดยใช้รูปแบบ Data Gateway ซึ่งเป็นรูปแบบการดำเนินการกับฐานข้อมูลพื้นฐานที่เข้าใจได้ง่ายและสร้างขึ้นได้เอง

รูปแบบ Data Gateway

จัดโครงสร้างคลาส ให้ง่ายต่อการนำไปใช้งาน ให้มี อินเทอร์เฟส Db มีเมทธอด connect( ) เป็นฟังก์ชันมาตรฐานในติดต่อกับฐานข้อมูลในรูปแบบ PDO มีคลาสอื่น ๆ ที่จะสืบทอดคุณสมบัติ เช่น Mysql ทำหน้าที่เชื่อมกับฐานข้อมูล MySql หรือ Sqlite ทำหน้าที่เชื่อมกับฐานข้อมูล SQLite ดังเขียนได้เป็น รูป 1


รูป 1 แผนภาพคลาส

เมื่อให้เป็นไปตามแผนภาพ เราก็สร้างอินเทอร์เฟส Db ก่อนให้มีเพียงฟังก์ชันเดียวคือ connect( ) ในที่นี้เลือกเป็นค่า static เพื่อให้ง่ายต่อการนำไปใช้ และถือว่ามีค่าที่เดียว


Code 1. database/datagateway/Db.php
<?php
namespace Database\Datagateway;

interface Db{
    public static function connect();
}

ต่อมาสร้างคลาส Mysql เพื่อเป็นตัวแทนการสืบทอด Db และทำงานกับฐานข้อมูล MySql โดยใส่ค่าที่จำเป็นต่อการชื่อต่อกับฐานข้อมูล เช่น ชื่อฐานข้อมูล (laravel) ชื่อผู้ใช้ (root) และไม่มีรหัสผ่าน ภายในฟังก์ชันทำหน้าที่คืนค่า ออบเจ็กต์ PDO


Code 2. database/datagateway/Mysql.php
<?php
namespace Database\Datagateway;

class Mysql implements Db{
    private static $dsn_mysql ="mysql:host=localhost;dbname=laravel;charset=utf8";
    private static $user = "root";
    private static $password = "";
    public static function connect(){
        try{
            return new \PDO(self::$dsn_mysql, self::$user, self::$password);
        } catch(\PDOException $e){
            die('Cound not connection to database because:'. $e->getMessage());
        }
    }
}

และคลาสสุดท้ายในการทำงานกับฐานข้อมูลคือ คลาส CourseTable ซึ่งอยู่ในรูปแบบ Raw Data Gateway ที่คืนค่าข้อมูลดิบ ที่ยังไม่ปรุงแต่งแต่อย่างใด เวลาใช้กับต้องปรับให้เหมาะกับแต่ละงานเอง ในการสร้าง จะยกตัวอย่างเพียงฟังก์ชัน all( ) กับ insert( ) สำหรับฟังก์อื่น ๆ ก็เลียนแบบสองฟังก์นี้ได้เลย เพราะใช้งานคล้าย ๆ กัน


Code 3. database/datagateway/CourseTable.php
<?php
namespace Database\Datagateway;

class CourseTable{
    private $pdo;

    public function __construct($pdo){
        $this->pdo =$pdo;
    }
    public function all(){
        $sql = "select * from courses";
        return $this->pdo->query($sql);
    }
    public function insert($model){
        //id is auto-number
        $name = $model['name'];
        $description = $model['description'];
        $on_off = $model['active'];
        $active = ($on_off==='on')?1:0; //checkbox

        $sql = "insert into courses(name, description, active) values(?,?,?)";
        $stm = $this->pdo->prepare($sql);
        $stm->bindParam(1, $name);
        $stm->bindParam(2, $description);
        $stm->bindParam(3, $active);
        return $stm->execute();
    }
    public function update($model){}
    public function delete($id){}
}

สำหรับการนำไปใช้ เช่นใช้ใน CourseControllerก็เรียกออบเจ็กต์ $pdo จาก Mysql::connect( ) แล้วฉีด $pdo ลงในคอนสตรักเตอร์ของ CourseTable($pdo ) หลังจากนั้นก็นำออบเจ็กต์ $courseTb ไปใช้งาน ตามฟังก์ชันที่ต้องการ เช่น ฟังก์ชัน all( ) ที่จะคืนค่าทุกอย่างในตาราง Course แล้วส่งรายการข้อมูลในชื่อตัวแปร couresไปยัง view ที่ชื่อ courses


Code 4. App/Http/Controllers/CourseController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

include("../database/datagateway/Db.php");
include('../database/datagateway/Mysql.php');
include('../database/datagateway/CourseTable.php');
use Database\datagateway\Mysql;
use Database\datagateway\CourseTable;

class CourseController extends Controller
{
    public function __invoke(Request $request)
    {
        $pdo = Mysql::connect();
        $courseTb = new CourseTable($pdo);
        $courses = $courseTb->all();
        $data = array();
        foreach($courses as $c){
          $id = $c['id'];
          $name = $c['name'];
          $description = $c['description'];
          $active = $c['active'];
          $data[] = array('id'=>$id,'name'=>$name,'description'=>$description, 'active'=>$active);
        }
        return view('courses', ['courses'=>json_encode($data)]);
    }
}

จากตัวอย่างนี้จะเป็นพื้นฐานสำหรับงานที่ไม่ได้ใช้ Laravel Framework แต่ถ้าใช้ Laravel Framework ใช้ฐานข้อมูลในรูปแบบของ Laravel จะดีกว่ามาก

สร้างการต่อเชื่อมกับฐานข้อมูลของ Laravel

เปิดไฟล์ .env จะพบชื่อฐานข้อมูลที่ตั้งให้เป็น laravel ซึ่งเป็นค่าปริยายที่มีมาให้ แต่ถ้าต้องการเปลี่ยนแปลงชื่อฐานข้อมูลก็แก้ไข ณ ตอนนี้ได้เลย

Code 5. .env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

Laravel ไม่ได้สร้างฐานข้อมูลให้อัตโนมัติ จะต้องสร้างฐานข้อมูลในชื่อ laravel เองกับฐานข้อมูล MySQL ใน MyPHPadmin ด้วยตนเอง

สร้างตารางตารางได้ด้วย Migrations

การสร้างตารางจะสร้างด้วยตนเองใน MyPHPadmin ก็ได้ หรือจะสร้างจากอัตโนมัติก็ได้ ซึ่งดูเหมือนว่า Laravel จะมีตารางให้มา 4 ตารางเป็นตัวอย่าง ให้เราเลียบแบบการสร้างเพิ่มอีกหนึ่งตาราง โดยสมมุติว่าให้สร้างตาราง course ดังให้สร้างไฟ่ล์ใหม่ จากการเลียนแบบไฟล์ที่ใช้สร้างตาราง users

เปิดไฟล์ database/migrations/2014_10_12_000000_create_users_table.php

สร้างไฟล์ใหม่เลียนแบบ ในไฟล์ชื่อ 2021_06_27_000000_create_course_table.php โดยชื่อไฟล์ต้องอยู่ในรูปแบบนี้ ให้กำหนดคอลัมน์ในตารางโดยกำหนด id(Primary Key), name, description, และ active ดังนี้

Code 6. database/migratins/2021_06_27_000000_create_course_table.php

<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCourseTable extends Migration
{
    public function up()
    {
        Schema::create('courses', function (Blueprint $table) {
            $table->id(); // auto increment and primary key
            $table->string('name');
            $table->string('description');
            $table->boolean('active');
        });
    }
    public function down()
    {
        Schema::dropIfExists('courses');
    }
}

ใช้คำสั่ง migrate ใน CLI ทุกไฟล์ในโฟลเดอร์ migrations มี 5 ไฟล์รวมไฟล์สร้างตาราง course ที่เราเพิ่งสร้าง จะได้ตารางทั้งหมดใน ฐานข้อมูล MySql ในฐานข้อมูลที่ชื่อ laravel

CLI 1.


>php artisan migrate

เมื่อใช้คำสั่งนี้ให้ตรวจสอบว่ามีตารางเกิดขึ้นมาจริงไหม (เปิด MyPHPadmin) ดังเมื่อเปิดดูแล้ว ให้ทดลองแทรก(insert)ข้อมูลในตาราง course ลงไปประมาณ 3 แถว เพื่อให้ในการทดสอบการสืบค้นต่อไป

สร้างแบบจำลอง

ใช้คำสั่งใน CLI สร้างแบบจำลองในชื่อ CourseModel

CLI 2.


>php artisan make:model  CourseModel

ต่อมาปรับแต่งคลาสนี้ ในทำงานกับฐานข้อมูลให้สืบทอดจากคลาส Model สร้างชื่อตารางให้ตรงกับฐานข้อมูลรวมทั้งข้อมูลที่จำเป็นอื่น ๆ

Code 7. app/Models/CourseModel.php

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class CourseModel extends Model
{
    protected $table = 'courses';
    protected $primaryKey = 'id';
    public $incrementing = true;
    protected $connection = 'mysql';
}

สืบค้นข้อมูลจากฐานข้อมูล

เมื่อสร้างแบบจำลองพร้อมแล้ว ต่อไปจะเป็นการทดสอบสืบค้นข้อมูล ในการสืบค้นใช้คำสั่งแทรกลงไปในไฟล์หน้าแรกกัน โดยใช้การสืบค้นผ่าน คลาส CourseModel และเรียกคำสั่ง all( ) ซึ่งหมายถึงอ่านข้อมูลทั้งหมดจากตาราง course เมื่อสืบค้นได้แล้ว นำไปแสดงผล ในรูปแบบตาราง

Code 8. resources/views/welcome.blade.php

<div class="content">
    <h2>Courses</h2>
        <table class="table">
        <thead>
    <tr>
        <th scope="col">#</th>
        <th scope="col">Name</th>
        <th scope="col">Active</th>
    </tr>
    </thead>
    <tbody>
    @php
    use App\Models\CourseModel;
    use Illuminate\Support\Facades\DB;
    $courses = DB::select('select * from courses')
    //or
    //$courses = CourseModel::all();
    @endphp
    @foreach($courses as $course)
    <tr>
            <th scope="row">{{$course->id}}</th>
            <td>{{$course->name}}</td>
            <td>{{$course->active}}</td>
    </tr>
    @endforeach
        </tbody>
        </table>
    </div>
</div>  

จากตัวอย่างมีการใช้งานเพื่ออ่านตาราง course ทำได้สองลักษณะคือ

  1. แบบ Fluent query builder ด้วยคำสั่ง DB::select('select * from course')
  2. แบบEloquent ORM ด้วยคำสั่ง CourseModel::all()

แบบแรกใช้เป็นภาษา SQL ซึ่งเราต้องรู้จักการแบบภาษา SQLส่วนแบบที่สองใช้เป็นแบบฟังก์ชัน เราต้องรู้จักฟังก์ชันที่มีให้ใช้ ซึ่งแน่นอนมีในแบบที่คาดเดาได้ง่าย และทั้งสองแบบให้ผลการสืบค้นออกมาในรูปแบบ JSON อย่างกรณีตัวอย่างนี้ได้ผลออกมาในรูปแบบ อาร์เรย์ของ JSON แต่ถ้าใช้การสืบค้นที่ได้ค่ามาค่าเดียวก็จะได้ผลออกมาในรูปหนึ่งออบเจ็กต์ JSON

การใช้งาน Fluent Query Builder (FQD)

จะเห็นแล้วว่า การใช้ FQD เน้นการเขียน ภาษา SQL และใช้งานคู่กับฟังก์ชัน ดังนั้นแล้วเราต้องรู้ว่ามีฟังก์ชันอะไรบ้าง ซึ่งชื่อฟังก์ชันก็สื่อความหมายในตัวอยู่แล้ว

  1. select( )
  2. insert( )
  3. update( )
  4. delete( )
  5. unprepared( )
  6. connection( )
  7. table()

ในลำดับ 1-4 เราคาดเดาได้และต้องศึกษาอีกนิด เพื่อการใส่ตัวแปรทำอย่างไง ส่วนในลำดับ 5-6 ก็ทำความเข้าใจเพิ่มเติมอีกนิดเป็นตัวเสริมของ PDO โดย unprepared( ) ใช้แบบรูปแบบเต็ม SQL และ connection( ) เพื่ออ่านคุณสมบัติของ PDO

การใช้งานเริ่มจากการนำเข้า(use) DB แล้วเปิดฟังก์ชันแบบใส่ตัวแปรเป็นฟังก์ชัน หรือที่เรียกว่า Closure

use Illuminate\Support\Facades\DB;

การใส่ตัวแปร ทำได้ด้วยการเพิ่มตัวแปรลงในฟังก์ชันในรูปอาร์เรย์ ดังตัวอย่างในลักษณะต่าง ๆ คือ:


$users = DB::select('select * from users where active = ?', [1]);
DB::insert('insert into users (id, name) values (?, ?)', [1, 'Marc']);
$affected=DB::update('update users set votes = 100 where name = ?',['Anita']);

การใช้ unprepared( ) เป็นการใส่ SQL เต็มรูปแบบ ทำงานตามภาษา SQL ที่ใส่


DB::unprepared('update users set votes = 100 where name = "Dries"');
DB::unprepared('create table a (col varchar(1) null)');

การใช้งาน connectio( ) เป็นการอ่านคุณบัติใน PDO


$users = DB::connection('sqlite')->select(...);
$pdo = DB::connection()->getPdo();

ทรานเซกชันของ FQD และ Eloquent

การควบคุมชุดดำเนินการกับฐานข้อมูลที่ทำงานหลายคำสั่งดำเนินการจนกว่าทุกผลการดำเนินการจะเสร็จสิ้น จึงเรียกว่าหนึ่งทรานเซกชัน (Transaction) แต่ในบางครั้งการทำงานยังไม่จบในลำดับใดลำดับหนึ่งด้วยเหตุผลใดก็ตาม เช่น ในลำดับแรกมีการแทรกข้อมูลใหม่ แล้วต่อด้วยการลบข้อมูล แต่เกิดความผิดพลาดในลำดับนี้ การย้อนกลับในลำดับก่อนหน้านี้จึงต้องทำให้ข้อมูลเหมือนเดิม

ลาราเวล ใช้ DB facade (รูปแบบทางเข้าอย่างหนึ่ง) เป็นตัวเริ่มต้นในการเรียกฟังก์ชัน transaction( ) ซึ่งใช้งานได้กับ FQD และ Eloquent

การใช้งานเริ่มจากการนำเข้า(use) DB วิธีการนี้ไม่จำเป็นต้องมีการบังคับให้ย้อนกลับได้ เพราะจะถือว่ามีการบังคับให้ย้อนกลับแล้ว โดยไม่ต้องใส่คำสั่งย้อนกลับ (DB::rollBack()) และไม่ต้องใช้คำสั่งยืนยันการดำเนินการของทรานเซกชัน (DB::commit())


DB::transaction(function () {
    DB::update('update users set votes = 1');
    DB::delete('delete from posts');
});

ซึ่งหากว่าต้องการใช้แบบไม่อัตโนมัติตามตัวอย่างก่อนหน้านี้ก็ดำเนินแยกแต่ละขึ้นตอนได้ตามฟังก์ชันต่อไปนี้


DB::beginTransaction();
DB::rollBack();
DB::commit();

ทดสอบการใช้งาน FQD

ตอนนี้ถึงเวลาทดสอบการใช้งาน FQD จากที่เห็นแนวทางการใช้งาน เราจะเริ่มจากการสร้าง เส้นทาง แล้วต่อด้วยสร้างคอนโทรลเลอร์ และหน้าเว็บ

Code 9. routes/web.php

    Route::get('/courses', [CourseController::class, 'index']);
    Route::get('/courses/{id}', [CourseController::class, 'show']);

ต่อด้วยการสร้างหน้า View รองรับการอ่านข้อมูลในรูปแบบอาร์เรย์ของตาราง Course

Code 10. resources/views/course.blade.php

<div class="content">
    <h2>Courses</h2>
      <table class="table">
        <thead>
        <tr>
            <th scope="col">#</th>  	<th scope="col">Name</th>
            <th scope="col">Description</th><th scope="col">Active</th>    
        </tr>
        </thead>
        <tbody>    
        @foreach($courses as $course)
        <tr>
            <th scope="row">
        <a href="/courses/{{$course->id}}">{{$course->id}}</a></th>
            <td>{{$course->name}}</td>
            <td>{{$course->description}}</td>
            <td>{{$course->active}}</td>
        </tr>
        @endforeach
        </tbody>
     </table>
  </div>
</div>

และสร้างคอนโทรลเลอร์แบบเต็มรูปแบบ ด้วยทางเลือก --resoruce

CLI 3.


php artisan make:controller CourseController --resource

Code 11. Http/Controllers/CourseController.php

use App\Models\CourseModel;
use Illuminate\Support\Facades\DB;

public function index()
{
    return view('course', [
        'courses' => DB::select('select * from courses')
   ]);
}
public function show($id)
{
    //return single json
    //return CourseModel::find($id); 

    //return array of json
    //return array(CourseModel::find($id)); 
    //return DB::select('select * from courses where id=?',[$id]); 

    return view('course', [
        'courses' => DB::select('select * from courses where id=?',[$id])
    ]);
}

จากตัวอย่างการสืบค้นทั้งสองของ index( ) และ show( ) ให้ผลการสืบค้นเป็นอาร์เรย์ของ JSON ทั้งคู่ ซึ่งทำให้ไม่ต้องเปลี่ยนแปลงอะไรในหน้า course.blade.php แต่ถ้าการสืบค้นออกมาไม่เป็นอาร์เรย์ เช่นการสืบค้นการเลือกของการเลือกเพียง id ตัวใดตัวหนึ่ง ก็ต้องแปลงให้ผลเป็นอาร์เรย์ เช่น

'courses' => array(CourseModel::find($id));

ให้ทดลองดูผลว่าข้อมูลที่ได้เป็น JSON หรือไม่ โดยการเปิดการทำงานของบรรทัดที่เปิดการทำงานไว้ (//)

ทดสอบอีกครั้ง ด้วยการแทรกข้อมูล โดยเลือกใช้ฟังก์ชัน store( ) ในคอนโทรลเลอร์นี้ ฟังก์ชันนี้รองรับการทำงานแบบ POST (เราอาจไม่ต้องทำตามรูปแบบนี้ก็ได้) โดยเมื่อแทรกข้อมูลเสร็จก็ให้กลับไปหน้าเดิม เพื่อแสดงผลการแทรก

Code 12. Http/Controllers/CourseController.php

public function store(Request $request)//POST accept
{
    $id = $request->input('id');
    $name = $request->input('name');
    $description = $request->input('description');
    $active = $request->input('active');
    DB::insert(
       "insert into courses(id, name, description, active) values(?,?,?,?)",
       [$id, $name, $description, $active]
    );
    return view('course', [           
       'courses' => DB::select('select * from courses')
    ]);
}

ต่อมาต้องสร้างฟอร์มให้กรอกข้อมูล ก่อนจะส่งไปในรูปแบบ POST โดยวางฟอร์มไว้ในหน้าเดียวกับที่อ่านตาราง

Code 13. resources/views/course.blade.php

<div style="border:solid 1px gray;border-radius:10px;">
    <form method='POST' action="/courses" class="row g-3">
        @csrf
        <div class='row' style='padding:30px 10px 0 30px'>
            <div class="col" >
                <input type='number' name='id' placeholder='id' 
                class="form-control-plaintext">
            </div>
            <div class="col">
                <input type='text' name='name'class="form-control-plaintext"
                placeholder='Name'>
            </div>
            <div class="col">
                <input type='text' name='description' class="form-control-plaintext"
                placeholder='Description'>
            </div>
            <div class="col">
                <input type='text' name='active'class="form-control-plaintext"
                placeholder='Active'>
            </div>
            <div class="col">
                <button type='submit' class="btn btn-primary mb-3">
                Insert
                </button>
            </div>
        </div>
    </form>
</div>

และไม่ลืมสร้างเส้นทางสำหรับการ POST นี้ด้วย


Route::post('/courses', [CourseController::class, 'store']);

ได้เห็นตัวอย่างไปหลายตัวอย่างแล้ว สำหรับการ ลบ การปรับปรุงข้อมูลก็ทำในทำนองเดียวกัน

DB::table()

นอกจากใช้โมเดลค่าเริ่มต้นในการสืบค้นแล้วยังสามารถใช้ คลาส DB เป็นจุดเริ่มต้นได้ด้วย และตามด้วยฟังก์ชัน table() ในการสืบค้นต่อไป การใช้ DB จะต้องนำเข้า (use) ด้วย

Code 14. ค่าได้ผลเป็นอาร์เรย์

use Illuminate\Support\Facades\DB;
$courses = DB::table('courses')->get();
$course_java = DB::table('courses')->where('name', 'Java')->get();

ในบางกรณีผลการสืบค้นต้องการเพียงค่าเดียว เพียงออบเจ็กต์เดียว ผลการสืบค้นนี้จึงไม่ได้อยู่ในรูปอาร์เรย์ การอ่านค่าจึงใช้การอ่านค่าจากออบเจ็กต์โดยตรง ไม่ใช่การวนซ้ำตามที่เคยทำมา

การสืบค้นที่ได้ค่าเดียวมีอยู่ด้วยกันหลายฟังก์ชัน ยกตัวอย่างการใช้ first() จะเป็นการหาค่าแรกที่ค้นพบ การใช้ฟังก์ชัน find($id) เป็นการหาค่าตาม คีย์หลัก ซึ่งจะต้องมีค่าตัวเลข

Code 15. ค่าได้ผลเป็นแถวเดียว

$course_java_first = DB::table('courses')->where('name','Java')->first();
$course_id_1 = DB::table('courses')->find(1);
    

และกรณีที่หาค่าเป็นเดี่ยว คือไม่เป็นอาร์เรย์ และไม่เป็นแถว พบในคำสั่ง SQL เช่น การนับ Count, Min, Max ค่าประเภทนี้เป็นค่าตัวเลข หรือเรียกใช้ชื่อ Aggregate

ตาราง 1. Aggregate
ฟังก์ชันความหมายตัวอย่าง
count นับจำนวนแถว DB::table(‘book’)->count();
max ค่าสูงสุด DB::table(‘book’)->max(‘price’);
min ค่าต่ำสุด DB::table(‘book’)->max(‘min’);
avg ค่าเฉลี่ย DB::table(‘book’)->avg(‘price’);
sum ค่าผลรวม DB::table(‘book’)->where(‘category’,’computer’)->avg(‘price’);

การใช้งาน Eloquent

จากตัวอย่างทั้งหมดถือเป็นจุดเริ่มต้นที่ใช้งานฐานข้อมูลในแบบของ Eloquent ซึ่งเป็นรูปแบบ Object-relational mapper (ORM) โดยการสืบทอดจาก Model ที่เพิ่มเติมข้อมูลให้ตรงกับตารางฐานข้อมูล ซึ่งต่อไปทำให้ สืบค้น แทรก ปรับปรุง และลบ จากฐานข้อมูลได้

ในการใช้งาน Eloquent จะต้องสร้างคลาสที่สืบทอดจาก Model และกำหนดค่าดังนี้

ตาราง 2. การกำหนดคุณสมบัติใน Model
คุณสมบัติใน Modelตัวอย่าง
ชื่อฐานข้อมูลจะใช้ชื่อตามค่ากำหนดไว้ใน .env แต่ถ้าต้องการใช้ชื่อฐานข้อมูลที่ต่าง ออกไป protected $connection = 'sqlite';
ชื่อตาราง ต้องกำหนดว่าชื่ออะไร protected $table = 'table_name';
ตามปกติคีย์ของตารางจะเป็น id แต่ถ้าไม่ใช้ต้องกำหนดใหม่ protected $primaryKey = 'myId';
ตามปกติคีย์ของตาราง จะเป็นค่าเพิ่มขึ้นอัตโนมัติ แต่ถ้าไม่เป็นเช่นนั้นให้เขียน public $incrementing = false;
แต่ถ้าคีย์ของตารางไม่ได้เป็นตัวเลขเช่น เป็นอักษร ก็ต้องกำหนด: protected $keyType = 'string';
ตารางอาจมีคีย์หลายตัว ก็กำหนดแต่ละตัวเป็น primary key ได้ protected $primaryKey = 'primary key 1';
protected $primaryKey = 'primary key 2';
คอลัมน์ที่มีข้อมูลให้อัตโนมัติ แต่ต้องสร้างในฐานข้อมูลด้วย มีไทป์ เป็น TimeStamp แต่ถ้าต้องการให้มีชื่อคอลัมน์เป็นอย่างอื่น ก็กำหนดใหม่ created_at
updated_at
const CREATED_AT = 'create_date';
const UPDATED_AT = 'update_date';

สร้างการสืบค้นของ Eloquent

การสืบค้นแรกที่เราได้เคยทำไว้แล้วคือ all( ) ยังมีวิธีอื่นสร้างคำสั่งสืบค้นได้

find($id)

การสืบค้นที่คืนด้วยการหาจาก id ซึ่งเป็นคีย์หลักของตาราง เราสามารถใช้คำสั่ง find($id) ได้ จากตัวอย่าง Code 11 ในฟังก์ชัน show($id) เราสามารถเปลี่ยนมาใช้ การคืนค่าเป็นอาร์เรย์ได้


'courses'=> array(CourseModel::find($id)) 

//or

//'courses' => [CourseModel::find($id))]

แต่ถ้าต้องการให้คืนค่าเป็นค่าออบเจ็กต์ JSON ค่าเดียวใช้


//return single json
return CourseModel::find($id);

ผลการคืนค่าจะเป็น


{
    "id": 2,
    "name": "C++",
    "description": "Programming",
    "active": 0
}

where()

การสืบค้นด้วย where( ) ใช้กับ โมเดลซึ่งทำได้หลากลายมาก คล้ายคำสั่งของ SQL ผลการสืบค้นอยู่ในรูปอาร์เรย์ของออบเจ็กต์ ดังนั้นจึงต้องใช้การวนซ้ำในการอ่านค่า

ตัวอย่างต่อไปนี่้ ใช้การสืบค้นของโมเดล CourseModel ที่เคยได้ทดลองทำก่อนหน้านี้ การสืบค้นใช้เงื่อนไขต่าง ๆ อย่างแรกใช้ where โดยกำหนดชื่อฟิลด์ active ให้มีค่าเท่ากับ 1 ต่อมาจัดเรียงตาม ด้วย orderBy ให้ผลการเรียงตาม name และเงื่อนไขสุดท้ายใช้ take โดยให้นำเพียงแถวแรกที่เลือกได้เท่านั้น สุดท้ายผลการสืบค้นใช้ฟังก์ชัน get( )


$courses = CourseModel::where('active',1)
    ->orderBy('name')
    ->take(2)
    ->get();

refresh( )

จากกรณีที่อ่านข้อมูล ดังตัวอย่างที่ผ่านมาของ $courses แล้ว ถ้าต้องการทำงานซ้ำอีกครั้ง เราใช้เพียง refresh( ) จะทำให้สืบค้นข้อมูลจาก Model อีกครั้ง


$courses->refresh();

แต่จะไม่มีผลกับการแก้ไขข้อมูลของออบเจ็กต์ เช่น กำหนดค่าข้อมูลใหม่ของ $courses เช่น


$courses[0].active = 0;
$courses->refresh();

ผลการ refresh() จะทำให้ไปสืบค้นค่าเดิม ที่มี active=1 อีกครั้ง ซึ่งมาจากฐานข้อมูล

การแก้ไขตารางข้อมูล

การแทรกข้อมูลใหม่ ไม่จำเป็นต้องย้อนไปอ่านแบบจำลองใหม่ เราสามารถที่จะสร้าง Model เป็นออบเจ็กต์ตัวใหม่แล้วใช้เพียงฟังก์ชัน save()


$course = new CourseModel();
$course->name = 'ABC';
$course->save();

//หรือใช้ผ่านฟังก์ชัน create
$course = Flight::create([
   'id'=>4, 'name'=>'ABC',
]);

การลบข้อมูล สามารถใช้ผ่านการค้นก่อนแล้วต่อด้วยฟังก์ชัน delete() หรือใช้ร่วมกับฟังก์ชัน where


$course =  CourseModel::find(1);
$course->delete();

$delete = CourseModel::where('active', 0)->delete();

การปรับปรุงข้อมูล ใช้การค้นข้อมูลก่อนแล้วตามด้วยฟังก์ชัน save()


$course =  CourseModel::find(1);
$course->name = 'CBA';
$course->save();

หรือใช้ผ่านฟังก์ชัน update( ) ก็ได้ แต่วิธีการนี้ใช้ได้กับการปรับปรุงข้อมูลหลาย ๆ แถวได้ ตามผลการสืบค้น


CourseModel::where('active', 1) ->update(['active'=> 0]);

Soft Delete

ในการทดสอบการใช้งานฐานข้อมูล ไม่ได้ต้องการลบฐานข้อมูลจริง เราสามารถทำได้ด้วยการใช้ Soft Delete วิธีการคือต้องเพิ่มคอลัมน์ deleted_at และ updated_at ในตารางฐานข้อมูลและมีไทป์เป็น DateTime (default=Null) โดยไม่จำเป็นต้องระบุสองฟิลด์นี้ใน Model และเพิ่มเติมคีย์เวิร์ด SoftDelete

Code 16. app/Models/CourseModel.php

use Illuminate\Database\Eloquent\SoftDeletes;
class CourseModel extends Model
{ 
   use SoftDeletes; //ข้อมูลที่เพิ่มเข้าไป
   //และข้อมูลก่อนหน้านี้
}

เมื่อเราใช้คำสั่งลบ จะไม่เป็นการลบไปจากฐานข้อมูลจริง แต่ถ้าเราสืบค้นก็จะไม่พบ ข้อมูลที่ใช้ Soft Delete ไปแล้ว แต่ต้องการสืบค้นให้พบค่าที่ใช้ Soft Delete ลบไปแล้วก็ต้องใช้คำสั่ง:

$course = CourseModel::withTrashed()->where('active', 0)->get();
    

ถ้าต้องการอ่านข้อมูลกลับมา ก็ใช้คำสั่ง restore() ซึ่งมีผลให้ตารางข้อมูล ฟิลด์ delete_at มีค่าเป็น Nullเช่น

CourseModel::where('active',0)->restore();

หรือจะต้องการลบไปจริง ๆ จากฐานข้อมูล ก็ใช้ forceDelete( ):


CourseModel::where('active',0)->forceDelete();

การปรับปรุงข้อมูล ใช้การค้นข้อมูลก่อนแล้วตามด้วยฟังก์ชัน save()

$course =  CourseModel::find(1);
$course->name = 'CBA';
$course->save();

หรือใช้ผ่านฟังก์ชัน update( ) ก็ได้ แต่วิธีการนี้ใช้ได้กับการปรับปรุงข้อมูลหลาย ๆ แถวได้ ตามผลการสืบค้น

CourseModel::where('active', 1) ->update(['active'=> 0]);

Factory

เมื่อต้องการทดสอบ หรือใช้งานอย่างรวดเร็ว เราไม่จำเป็นต้องระบุข้อมูลอย่างครบด้านเหมือนที่ทำก่อนหน้านี้ก็ได้ รวมทั้งยังไม่มีฐานข้อมูลจริงมาก่อนก็ได้ ด้วยการใช้งานแบบ Factory จะเป็นการระบุข้อมูลตัวอย่างอย่างง่าย ๆ ก่อนอื่นต้องสร้างไฟล์ สมมุติให้ชื่อ Book เป็น Model และ BookFactory เป็นตัวแบบ Factory สร้างสองอย่างด้วยคำสั่ง

CLI 4.


php artisan make:model Book --factory

หรือต้องการให้มีคำว่า Model ต่อท้าย


php artisan make:model ฺBookModel --factory

แต่ถ้าต้องการสร้างเฉพาะ Factory


php artisan make:factory BookModelFactory

ภายใน BookFactory สร้างหนังสือหลอก ๆ มาก่อน ตามรายการเพิ่มเติม ให้มีข้อมูล id, title, price, และ year

Code 17. app/database/factories/BookFactory.php

private static $nextId = 0;
public function definition(): array
{ 
    self::$nextId++;
    return [
        'id'=>self::$nextId,
        'title'=>substr(fake()->text(),0, 6),
        'price'=>rand(80, 400),
        'year'=>rand(2018, 2023),
    ];
}

สำหรับไฟล์ Book.php เป็นคลาสที่ต้องการใช้ BookFactory ให้ใส่การใช้ HasFactory แค่นี้ถือเป็นใช้ได้ โดยไม่ต้องนิยามอะไรเพิ่มเติมอีก เพราะจะใช้งานให้มีฟิลด์ตาม BookFactory

Code 18. app/Models/Book.php

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
     use HasFactory;
}

เราจะทดสอบการสร้างออบเจ็กต์ $books สัก 4ตัวผ่าน BookController ในฟังก์ชัน __invoke( ) แต่มีการสร้างค่าเริ่มต้นที่ __construct( ) มาก่อน

Code 19. app/Http/Controllers/BookController.php

use Illuminate\Http\Request;
use App\Models\Book;

class BookController extends Controller
{
    private $book;
    public function __construct(){
        $this->book = Book::factory()->count(4)->make();
    }
    public function __invoke(){
        return $this->book;
    }
}

ฟังก์ชัน __invoke( ) เป็นฟังก์ชันปริยายที่ใช้งานผ่าน Route โดยไม่จำเป็นต้องระบุชื่อฟังก์ชัน ดังเขียนเส้นทางการอ่านค่า book คือ

Code 20. routes/web.php

use App\Http\Controllers\BookController;

Route::get('/books', BookController::class);

สร้างข้อมูล factories ลงฐานข้อมูล

ในกรณีที่ใช้ factories สร้างลงฐานข้อมูลจริง เราจะใช้ข้อมูลหลอก ๆ หรือข้อมูลจริงก็ได้ เพียง เปลี่ยนฟังก์ชันจาก make( ) ไปเป็น create( ) แต่ในฐานข้อมูลจริงจะต้องมีฟิลด์ created_at และ updated_at ที่มีไทป์ เป็น date หรือ datetime

สมมุติว่าจะใช้ factories สร้างลงฐานข้อมูลแต่ไม่ใช้ข้อมูลหลอก เราเพียงเพิ่มรายการแต่ละฟิลด์ใหม่ เช่น


Book::factory()->create([
    'id'=>8, 'title'=>'C++', 'price'=>200, 'year'=>2023
]);

ยังมีฟังก์ชันการทำงานอีกมากมาย อ่านเพิ่มเติมได้ที่