iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Modern Web

Laravel 實務筆記系列 第 12

Eloquent ORM - 讀取資料

讀取表單中的所有資料

接下來的步驟將把 todo 表單中的資料取出展示在 Dashboard 上。

首先看到 TodoController 中的 index 函式

// app\Http\Controllers\TodoController.php

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $todos = Todo::get(); //加入這行
}

get() 方法會將 Model 對應的表單中的所有資料取出。

接著就要將讀取到的 $todos 資料回傳給前端,如果是 API 的話就是將資料回傳

// app\Http\Controllers\TodoController.php

/**
 * Display a listing of the resource.
 *
 * @return \Illuminate\Http\Response
 */
public function index()
{
    $todos = Todo::get();  
    
    return $todos;
}

不過因為這邊想將資料顯示在 Dashboard 上,所以要回傳帶有 $todos 資料的 Dashboard 畫面

// app\Http\Controllers\TodoController.php

public function index()
{

    $todos = Todo::get();

    return inertia('Dashboard', [
        'todos' => $todos,
    ]);
}

這樣 Dashboard 就能將 todos 作為 prop 傳入 Dashboard,再顯示出來

// resources\js\Pages\Dashboard.js

import { List , ListItem , ListItemText } from "@material-ui/core";


export default function Dashboard(props) {
    
    const { todos } = props; // 取出 todos
    
    // ...

    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            header={
                <h2 className="font-semibold text-xl text-gray-800 leading-tight">
                    Dashboard
                </h2>
            }
        >
            //...
            <Container>
                <form onSubmit={submit}>
                   //...
                </form>
                // 顯示 todos 列表
                <List>
                    {todos.map((item) => (
                        <ListItem button>
                            <ListItemText primary={item.name} />
                        </ListItem>
                    ))}
                </List>
            </Container>
        </Authenticated>
    );
}

接著將 /dashboard 路由的 Controller 替換成 TodoController

Route::get('/dashboard', [TodoController::class, 'index'])
->middleware(['auth', 'verified'])->name('dashboard');

這樣當進入 Dashboard 畫面時就能看到簡易的 todo 列表了

inertia.js 局部更新資料

雖然有 todo 清單了不過目前還是靜態的資料,只會顯示呼叫當下取得的 todo 資料,每當新增 todo 後還得重新整理畫面才能看到新增的資料。

這時候就要應用 inertia.js 的局部更新資料功能了,

Inertia.reload({ only: ["todos"] });

Inertia.reload 會重新呼叫目前頁面的 url,而用 only 可以指定這次的讀取只要更新哪部分的資料。

像這裡指定 todos 那就只會更新這個 prop

// app\Http\Controllers\TodoController.php

public function index()
{

    $todos = Todo::get();

    return inertia('Dashboard', [
        'todos' => $todos,  // 對應這裡的鍵值
    ]);
}

所以每當我們新建好 todo 後就呼叫 Inertia.reload

// resources\js\Pages\Dashboard.js

export default function Dashboard(props) {
    // ...
    const submit = (e) => {
        e.preventDefault();
        transform((data) => ({
            name: data.todo,
        }));

        post("/todo", {
            // 新增資料結束後重載 todos
            onFinish: (visit) => {
                Inertia.reload({ only: ["todos"] });
                reset(); //另外順便清空輸入框
            },
        });
    };
    
    //...
}

這樣在新增資料後就能馬上看到新增的 todo 了。

讀取資料應用

前面是利用 get() 方法將所有資料讀出來,不過通常我們可不這麼做,而是有條件的讀取出需要的資料。

Eloquent 讀取資料的函式都是沿用了 Laravel 原生的 Query Builder ,這邊列舉幾個常用的用法

get

沒錯又是 get ,get 的用法是將"目前條件"下的所有資料取出,前面直接在 Model 下使用 get 所以會將該 Model 對應的所有資料讀取出來。

Todo::get() // 讀取模型的所有資料

如果有加上其他的篩選條件,就會將符合該條件的所有資料取出

Todo::where('created_at', "<=", now()->subMonth())->get(); // 讀取早於一個月前建立的資料

where

基本的搜尋條件函式,是最常用也最多變的一環

基礎用法 where( 欄位 , 比較條件 , 目標值 ) ,比較欄位的值與目標值,符合條件的資料用 get 取出

Todo::where('created_at', "<=", now()->subMonth())->get();

通常都用用來比大小或相不相等

where('votes', '>', 100) //大於
where('votes', '>=', 100) //大於等於
where('votes', '<>', 100) //不等於
where('votes', '=', 100)  //等於
where('votes', 100) // 等於的簡略寫法

也可以用資料庫支援的表達式

where('name', 'like', 'T%')

可以串接多個 where ,取交集

// 取年齡小於 60 且大於 35 的使用者
$users = User::where('age', '<', 60)
               ->where('age', '>', 35)
               ->get();

取聯集則是使用 orWhere

// 取年齡大於 35 或者名子為 John 的使用者
$users = User::where('age', '>', 35)
               ->orWhere('name', 'John')
               ->get();

可以一次篩選多個條件,取交集

$users = User::where([
    ['status', '=', '1'],
    ['subscribed', '<>', '1'],
])->get();

除了基本 where 還有其他衍伸的 where 函式

// 取介於範圍內/外的值
whereBetween('votes', [1, 100])
orWhereBetween('votes', [1, 100])
whereNotBetween('votes', [1, 100])
orWhereNotBetween('votes', [1, 100])

// 取包含 / 不包含在陣列中的值
whereIn('id', [1, 2, 3])
orWhereIn('id', [1, 2, 3])
whereNotIn('id', [1, 2, 3])
orWhereNotIn('id', [1, 2, 3])

// 取欄位是 / 不是 null 的資料
whereNull('deleted_at')
orWhereNull('deleted_at')
whereNotNull('deleted_at')
orWhereNotNull('deleted_at')

// 比較時間
whereDate('created_at', '2016-12-31')
whereDate('created_at', '<' , '2016-12-31')
whereMonth('created_at', '12')
whereDay('created_at', '31')
whereYear('created_at', '2016')
whereTime('created_at', '11:20:45')

//比較兩個欄位之間的值
whereColumn('first_name', 'last_name')
whereColumn('updated_at', '>', 'created_at')

where 邏輯組合

可以將條件作為子集合組合出想要的搜尋條件

//名子為 John 且 votes 大於 100 或者 title 為 Admin  

$users = User::where('name', '=', 'John')
               ->where(function ($query) {
                   $query->where('votes', '>', 100)
                         ->orWhere('title', '=', 'Admin');
               })
               ->get();

order

可以用 order 在讀取資料的同時將資料排序

$users = User::orderBy('name', 'desc')
               ->get();
asc = 升序
desc = 降序

可以串接多個 order ,會依序用條件排列

$users = User::orderBy('name', 'desc')
               ->orderBy('email', 'asc')
               ->get();

first

first 會取得當下條件排序第一位的資料

$flight = Flight::where('active', 1)->first();

如果沒有符合條件的資料,first 只會回傳 null,不會報錯。

如果想要在沒找到對應的資料時報錯的話,可以用 firstOrFail()

$flight = Flight::where('active', 1)->firstOrFail();

當拋出的 ModelNotFoundException 未被攔截的話, Laravel 會回傳 404 回應,包含對應的錯誤訊息。

find

find 會搜尋主鍵值找出一筆資料,通常都是用 id 當主鍵值來搜尋

$flight = Flight::find(1); // 尋找 id 為 1 的資料

References

Eloquent: Getting Started
Database: Query Builder

上一篇
補充: 建立 Todo list 畫面
下一篇
Eloquent ORM - 編輯資料
系列文
Laravel 實務筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言