$ ls crystal_folder

Laravel Eloquent Model使用小貼士

說一個大結論

我可以直接在MySQL做好資料表,在Laravel手刻Model直接操作,
不用像Django × SQLite跑任何異動

多數後端框架的異動(migration)或許能理解成:
為了從後端服務端發動去創造新或修改資料表等操作

還做了一個實驗 資料庫已經有幾行資料列時新增欄位

  1. 會不會破壞既有Laravel Model?
  2. 能否不需要執行異動也能使用該欄位? 其實根據上方的原理就想當然爾了,但還是可以試一下

具體實驗方法:

  1. 先在該表填入幾筆假資料
  2. 查詢及insert
  3. 然後再開一個新欄位
  4. 重送查詢及insert

20240322另個實驗:不完整更新

也是ok,這樣就不用擔心影響到程式內既有的update語法了

這樣整理起來,新增主鍵以外的欄位真的影響不大

但如果是:

的方面像是用了find()直接用主鍵刪除這種方法.. 的方面,這時以前寫在程式內還沒移除的舊欄位會被提示Unknown column '舊欄位' in 'field list';又或是改變欄位型態導致傳入值變得不匹配

這些都是要去調整的

初次使用

(假設已經是成熟專案有既有Model,新建Model手刻法看下方..)

<?php
DB::connection('設定檔名稱')->beginTransaction();
try {
  $list = [內含要加入的資料,要跟欄位對上];
  Model::insert($list); // 或其他各種操作
  // 註:如果是where然後get(),會回傳一個collection 或以下這樣也是
  // $users = App\User::all();
  // $users[0]->name; // 取用collection的內容

  // 最後才commit 酷!
  DB::connection('設定檔名稱')->commit();
} catch (\Excepttion $e) {
  DB::connection('設定檔名稱')->rollback();
}

上方提到回傳值為collection的議題提到一種取用方式,或用collect($result)->toArray()轉換,那還能怎麼取用呢?

<?php
$userNames = $users->map(function ($user) {
    return $user->name;
});

考慮沒有要打印SQL,也沒有要接續查詢 這時我可能get()後直接->toArray() 其實原本get()方法回傳的型態就是Collection了,多一層collect()有點多餘

那如果只想取特定欄位呢?看這篇[^1]


Function helper詳解

常用的

<?php
// 增
MyModel::insert([
    'name' => 'John',
    'email' => 'john@gmail.com',
    'password' => Hash::make($pwd),
]);
MyModel::create([
    'name' => 'John',
    'email' => 'john@gmail.com',
    'password' => Hash::make($pwd),
]); // 如果有開啟紀錄create_time的設定且時間戳設定為True,create會多帶時間戳,insert則不會,不想要可能不要用create或是修改設定
// 另外就是他可能會出現MassAssignmentException,要你額外做設定才能用create函數幫手

// 查
MyModel::find($pk); // 只能用主鍵,注意!!我在這裡踩了個坑,就是這方法他會直接返回單層的數據結構,要拿東西就接->username像這樣,無須再接續get()..
// 莫像我get()又first()總拿一個0索引號🫠
MyModel::where(阿巴阿巴條件)->get(); // 拿全部結果,回傳型態為Collection
$query = MyModel::where(阿巴阿巴條件)->first(); // 返回Model或NULL
// 這個...水很深 https://stackoverflow.com/questions/24531312/eloquent-first-if-exists

MyModel::where(DB::raw('column1 + column2'), '<', 1000)->get(); // Raw Expressions的使用
MyModel::where('id', '!=' , 2); // 應該是等價於DB支援的運算符 MySQL是<>跟!=都能用
// and not 用whereNot()還原
// 子查詢可以用joinSub()
// 但太複雜乾脆whereRaw算了...?

$users = User::select('欄位A', '欄位B')->get(); // 只拿特定欄位
// 但比較怪異的是Facade DB的select有執行查詢的功能啊..
DB::select('SELECT * FROM users WHERE age > ?', [18]);

$user = User::where('name', 'John')->select('id', 'name')->get(); // 與where的組合技

// 還有一個whereIn()用法大同小異

// 比較怪的是groupBy()除了傳入欄位,也允許你傳raw,像SQL date_format('格式', 欄位)這種的,雖然外框加了`但我在資料庫執行語句發現絲毫不影響查詢🤔🤔🤔(這其實應該是SQL小抄那邊的內容)
// 當然嚴謹點還是要搭配DB::raw()..

// 改
MyModel::where(阿巴阿巴條件)->update(['status' => 0]);

// 刪
MyModel::destroy($id); // 可以批量刪除
MyModel::where('id', $id)->delete();
// 還有軟刪除有興趣可以去查查

如何還原where子句中的各種比較?大概如下

<?php 
MyModel::where('x', '比較運算子', $要比的數)
->where('a', 'a') // and where a = 'a'

如何還原括號

where a = 'a'
and where (b = 'b' and c > 1)

會類似這樣:

<?php
->where('a', 'a')
->where(function ($query) use ($要傳入的傢伙如果有的話) { // 不要的話就把use跟後面那段去掉就好
  $query->where('b', 'b')
  ->where('c', '>', 1);
})

Raw Expressions

中文官方文件跳到Raw Expressions的段落

用處:這樣where中就可以先運算好幾個欄位再做比較

一些疑難雜症


toSql()

在get前改用toSql()可以打印SQL語句

但有的方法會回傳更新筆數不能用toSql()...


beginTransaction()


自動記錄建立與更新時間

看這篇

但即便如此你還是可以在update時傳入自己弄的format日期,這應該只是說沒有的時候他會幫你自己做..

話說insert update日期是可以使用符合格式的String,那比較呢?

insert update時可以插入php內置函數date(格式),這個方法預設給的就是今天日期的格式化字串(可看官方文件

比較應該也是可使用符合格式的字串,這個toSql便能看出來語法是合理的

還有除了format後的str可以直接插入,型態為Carbon實例像Carbon::now()也是可以的


手刻常見的Model眾生相

<?php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class MyModel extends Model
{
    protected $connection = 'DB名稱';
    protected $table = '表名';
    protected $primaryKey = 'PK名';

    public $incrementing = false; // 自增嗎?
    public $timestamps = true; // 要自動時間戳嗎?

    const CREATED_AT = 'create_date'; // 自增建立日期欄位
    const UPDATED_AT = null; // 自增異動日期欄位

}

is/is not null語句的還原

相關討論

whereNotNull() whereNull()


神奇合併查詢代替UNION ALL

stackoverflow的討論


補充


Full Join密技

看這邊討論


沒好好select會爛掉的(不過這邊是Laravel admin的Model)

一SQL語句

     select 
     chiikawa_profile.id,
     chiikawa_profile.created_at,
     chiikawa_profile.name,
     chiikawa_profile.birthday,
     chiikawa_profile.sign,
     sign_lucky_color.lucky_color,
     sign_lucky_jewelry.lucky_jewelry
     from chiikawa_profile 
     left join sign_lucky_color on chiikawa_profile.sign = sign_lucky_color.sign
     left join sign_lucky_jewelry on chiikawa_profile.sign = sign_lucky_jewelry.sign
     order by chiikawa_profile.id asc

要這樣寫$grid才不會爛掉

<?php
    $grid = new Grid(new ChiikawaProfile());
    $grid->model()->selectRaw('
    chiikawa_profile.id,
    chiikawa_profile.created_at,
    chiikawa_profile.name,
    chiikawa_profile.birthday,
    chiikawa_profile.sign,
    sign_lucky_color.lucky_color,
    sign_lucky_jewelry.lucky_jewelry')
      ->leftJoin('sign_lucky_color', 'chiikawa_profile.sign', '=', 'sign_lucky_color.sign')
      ->leftJoin('sign_lucky_jewelry', 'chiikawa_profile.sign', '=', 'sign_lucky_jewelry.sign');

union應該同理

原因出在沒有好好select欄位,selectRaw('*')會爛掉,ORM跟原生SQL還是不太一樣的..可能要看他打印出來的語句...?

問題是我印出來兩種都是可以執行的欸...

[2024-04-26 02:11:30] local.INFO: select 
      chiikawa_profile.id,
      chiikawa_profile.created_at,
      chiikawa_profile.name,
      chiikawa_profile.birthday,
      chiikawa_profile.sign,
      sign_lucky_color.lucky_color,
      sign_lucky_jewelry.lucky_jewelry from "chiikawa_profile" left join "sign_lucky_color" on "chiikawa_profile"."sign" = "sign_lucky_color"."sign" left join "sign_lucky_jewelry" on "chiikawa_profile"."sign" = "sign_lucky_jewelry"."sign"  
[2024-04-26 02:11:30] local.INFO: select * from "chiikawa_profile" left join "sign_lucky_color" on "chiikawa_profile"."sign" = "sign_lucky_color"."sign" left join "sign_lucky_jewelry" on "chiikawa_profile"."sign" = "sign_lucky_jewelry"."sign"  

還是這是grid model的鍋..............


有可能合併兩個Model查詢結果嗎...?待考

網路上常提到關於result的merge似乎是關於collection?


沒查到東西會返回甚麼?

where(條件)->first()沒查到東西會返回NULL

where(條件)->get()呢?

如果在Laravel中使用get方法查詢資料,而該查詢沒有結果,你會得到一個空的集合(EloquentCollection)。這意味著即使沒有匹配的資料,你仍然會收到一個集合物件,但該集合內不包含任何資料。 --By.Copilot

至於where(條件)->get()->first()那個first()便是針對Collection的操作了


其實在Model中關聯挺耗費記憶體的欸


Model中自定義方法的調用方法?


覺得fillable很煩可以試試這個

stackoverflow的討論


想要取值沒煩惱,從看回傳值提示開始

2024五月初在取值上踩了坑,搞得心情很浮躁

反省發生的原因

牽涉到:

  1. 我不是用沒提示的編輯器寫(然後我也不知道那啥型態,var_dump()不會用?)
  2. 就是不看VSCode飄過去會顯示的回傳值

Model關聯查詢取不到值會傳什麼

<?php
$something = $first_result->getXxx->something;

會得到ErrorException: Trying to get property 'order_id' of non-object而非null

#Laravel #php