Laravel Migration、Model、DB物件 相關操作 (濃縮)

官方文件非常詳細,而這篇主要將用法濃縮來「速查」,且由另外一個角度來了解 DB 相關操作。
  1. 指令相關
  2. DB 相關物件
  3. Relationships
  4. Model 屬性
  5. Queries 操作

指令相關

建立/更新 tables
$ php artisan migrate
清空
$ php artisan migrate:reset
刪除最後一個 migration
$ php artisan migrate:rollback --step=1
自動化(首次安裝,下 composer install 會連帶執行)
{
    ...
    
    "scripts": {
        "init" : [
            "mysql -P 3306 -h 127.0.0.1 --user=root --password=1234 --execute=\"CREATE DATABASE IF NOT EXISTS mydb\"",
            "php artisan migrate",
            "php artisan db:seed"
        ],
    }
}

DB 相關物件

//原始 SQL
$users = DB::select('select * from users where id = :id', ['id' => 1]);
//使用 Queries(ActiveRecord) 簡易 CURD 等..
DB::table('users')->select('name')->get();
//使用 ORM,需先建立 Model
User::where('name', 'wild')->get();
//將 Model 彼此建立關聯後,可操作 A Model 去撈取關聯的 B Model 資料
User::find(1)->posts()->where('title','test')->get();
//在 migrate file 使用,主要在操作資料庫架構
Schema::create('users', function (Blueprint $table) {
    $table->string('name', 20)->comment('註解');
});
命名規則
"Snake-case" 蛇底式,ex. user_detail
"Camel-Case" 駝峰式,ex. UserDetail
DB相關命名都使用 snake-case
table name 命名,通常 +'s' 複數
table index 命名,通常為 id,關聯的 table index,本地欄位名稱通常為 table_name(單數) + '_id'
FK 名稱通常為 table_name + '_' + local欄位名稱 + '_foreign'
多對多樞紐表,名稱為 A表_B表,依字母排序
Model 檔案名稱用 camel-case,單數
Model 中的 method 名稱,依照 relation 做單數 or 複數命名
Model 在自動帶入 FK 時,預設 classname + '_id'
Migration 檔名通常為 時間戳記_create_xxxx_table
Migration 一個 Class 也可操作多張 table

Relationships

Laravel沒有規定一定要建 Model,可以直接用 DB::來操作。若想用ORM操作,才需建立 Model,Model 內的 relation "有用到才建立"

One To One 一對一

  • 範例:users vs details
//User model
public function detail(){
    return $this->hasOne('App\Detail', 'foreign_key', 'local_key');
}
//Detail model
public function user(){
    return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}

One To Many 一對多

  • 範例:users vs comments
//User model
public function comments(){
    return $this->hasMany('App\Comment', 'FK', 'local_key');
}
//Comment Model
public function user(){
    return $this->belongsTo('App\User', 'FK', 'other_key');
}

Many To Many 多對多

  • 範例:users vs user_app vs app
  • 判別:A表 - 樞紐表 - B表,樞紐表欄位一定有 A_id, B_id
//User model
public function apps(){
    return $this->belongsToMany('App\App', 'user_app', 'user_id', 'app_id');
}
//app Model
public function users(){
    return $this->belongsToMany('App\User', 'user_app', 'app_id', 'user_id');
}

Has Many Through 遠層一對多

  • 範例:countries vs users vs comments,要取得某個 country 的 Comment,須先查該國哪些 User,在查這些 User 有哪些 Comment
  • 判別:A表(1) - B表(n) - C表(n),需查B才能查C
//Country model
public function comments(){
    return $this->hasManyThrough('App\Comment', 'App\User', 'country_id', 'user_id');
}

Polymorphic Relations 多型關聯

  • 範例:users vs products vs photos,Photos 存放 User & Product 的圖片,用 type 分開,User 與 Photo 是 1對1關係
  • 判別:A表 - B表 - 多型表,多型表含有 id + type 欄位
//User Model
public function photos(){
    return $this->morphMany('App\Photo', 'imageable');
}
//Product Model
public function photos(){
    return $this->morphMany('App\Photo', 'imageable');
}
//Photo Model
public function imageable(){
    return $this->morphTo(); //取得所有所屬的可擁有圖片的Model
}
//photos Migration
//up function
Schema::create('photos', function (Blueprint $table) {
    $table->increments('id');
    $table->string('path'); 
    $table->morphs('imageable'); //會建立2欄位,imageable_id 和 imageable_type
});

Many To Many Polymorphic Relations 多型多對多

  • 範例:posts vs videos vs taggables vs tags,Post 有 N 個 Tag、Video 也有 N 個 Tag
  • 判別:A表 - B表 - C多型表 - C表,多型表欄位為 Target_id, Target_type, C_id ,Target_type 為 A or B
//Post Model
public function tags(){
    return $this->morphToMany('App\Tag', 'taggable');
}
//Video Model
public function tags(){
    return $this->morphToMany('App\Tag', 'taggable');
}
//Tag Model
public function posts(){ //type1
    return $this->morphedByMany('App\Post', 'taggable');
}
public function videos(){ //type2
    return $this->morphedByMany('App\Video', 'taggable');
}
//taggables Migration
//up function
Schema::create('taggables', function (Blueprint $table) {
    $table->integer('tag_id'); //C表的索引
    $table->morphs('taggable'); //會建立2欄位,taggable_id 和 taggable_type

    $table->foreign('tag_id')->references('id')->on('tags'); //如有需要可加
});

預載 N+1

  • with

延遲預載 load

Pivot 樞紐表操作(多對多)

  • Model取值 - 在樞紐表中,除了 A_id, B_id 欄位之外,也可能有其他資訊欄位
  • //user Model
    public function apps(){
        return $this->belongsToMany('App\App')->withPivot(col1, col2,..);
        return $this->belongsToMany('App\App')->withTimstamps();
    }
  • 新增 - 增加一個關聯
  • //Controller
    $user = App\User::find(1);
    $user->apps()->attach($appId, ['col1' => false,...]); //參數2可略
    
  • 刪除 - 刪除一個關聯
  • $user->apps()->detach($appId); //刪除單一個關係
    $user->roles()->detach(); //刪除全部關係
    
  • 更新 - 更新關係欄位以外的資訊欄位
  • $user->apps()->updateExistingPivot($appId, [col1 => false, col2 => 100, ..]);
  • 同步 - 傳入關聯清單,自動比對,並新增刪除
  • $user->apps()->sync([1 => ['col1' => false], 2, 3]);
  • 同步(無刪除) - 同步功能,只會新增、但不刪除
  • $user->apps()->syncWithoutDetaching([1, 2, 3]);

Model 屬性

class Xxxx extends Model
{
    //使用軟刪除(註記刪除),需指定 deleted_at,Migration 需加上 $table->softDeletes();
    use SoftDeletes;

    //指定與該 Model 關聯的資料表
    protected $table = 'my_table';

    //告知該 table 的 PK 欄位(預設為 id 欄位)
    protected $primaryKey = 'SongID';

    //讓 Model 連接指定的 connection
    protected $connection = 'connection-name';

    //是否讓 Eloquent 來自動維護 created_at 和 updated_at 欄位
    public $timestamps = false;

    //日期欄位的儲存格式。'Y-m-d' or 'U' or ...
    protected $dateFormat = 'U';

    //需要被轉換成日期的屬性。(通常輔助 softdeletes 使用)
    protected $dates = ['deleted_at'];

    //「連動」,資料更新時,可連帶更新上層 updated_at 欄位
    //此 Model 為 belongsTo 或 belongsToMany 
    protected $touches = ['post', 'model2', ...];

    //可以被大量賦值的屬性。
    protected $fillable = ['name'];

    //不可以被大量賦值的屬性。
    protected $guarded = ['price'];

    //被大量撈出時,不會顯示在物件中,要暫時可見需使用 makeVisible()
    protected $hidden = ['password'];
    
    //應該在陣列中可見的屬性。(白名單)
    protected $visible = ['first_name', 'last_name'];

    //把指定值附加到 Model 資料陣列中。需實作 get{fieldname}Attribute()
    //可參考 eloquent-serialization 官方文件
    protected $appends = ['is_admin'];

    //輸出時,轉化格式
    //可參考 Eloquent: Mutators 官方文件
    protected $casts = ['is_admin' => 'boolean','raw_json' => 'array',];
}

Queries 操作

預載入

最重要的部份,沒處理好會造成效能低落
//撈取
$user->books()->get(); //預載入,在呼叫 get() 當下,就將資料取回轉成物件
$user->books; //延遲載入 (動態屬性用法),在使用到該 table、欄位 才會去 Query
//以上兩種結果相同
N + 1 問題,
範例為 1對1 的 Book、Author Model,已經做好關聯
$books = App\Book::all(); //select * from books

//撈取每一本書的個別作者
foreach ($books as $book) {
    echo $book->author->name;
    //select * from authors where id = n
}
//依「延遲載入」的特性,使用前才 Query,所以上面 Query 了「N次」
//簡單說,就是沒在迴圈外先撈完資料,才在裡面,每缺一次資料就抓一次
簡易判別:當看到 all(),foreach 裡面有用到關聯的 table,就會有 N + 1 問題發生
解決方式:
//預載關聯 table
$books = App\Book::with('author')->get();
//預載 多個 關聯 table,A->B()、A->C()
$books = App\Book::with('author', '發行商',...)->get();
//巢狀預載入,A->B()->C()
$books = App\Book::with('author.多個聯繫方式')->get();
//預載入條件限制
//範例:多對多,N個user->N個post
$users = App\User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%first%');
}])->get();
//延遲預載入
$books = App\Book::all();
if ($someCondition) { //判斷後,再決定是否預載入關聯 table
    $books->load('author', 'publisher');
}
//延遲預載入的額外條件
$books->load(['author' => function ($query) {
    $query->orderBy('published_date', 'asc');
}]);

其他操作

//至少有一篇"評論"的"文章"
$posts = Post::has('comments')->get();
$posts = Post::has('comments', '>=', 3)->get(); //大於3篇
$posts = Post::has('comments.votes')->get(); //是少有一篇評論 + 被評分。(巢狀關係,votes 是 table)
//has進階用法,裡面設定 where 條件,用 whereHas、orWhereHas
$posts = Post::whereHas('comments', function ($query) { // 取得所有至少有一篇評論
    $query->where('content', 'like', 'foo%'); //內容包含 foo 的文章
})->get();

DB:: 物件操作

transactions 交易模式

#方法一
DB::transaction(function () use($nickname) {
    DB::table('users')->update(['nickname' => $nickname]);
    DB::table('posts')->delete();
}, 重試次數);
#方法二
DB::beginTransaction();
try {
    DB::...
    DB::commit();
} catch (\Exception $e) {
    DB::rollback();
}

問題


  • 因 Migrate class name 相同,導致 rollback 出錯
     Cannot declare class UpdateUsersTable, because the name is already in use 

Laravel Migration、Model、DB物件 相關操作 (濃縮) Laravel Migration、Model、DB物件 相關操作 (濃縮) Reviewed by Wild on 2/09/2017 03:17:00 上午 Rating: 5

沒有留言:

沒有Google帳號也可發表意見唷!

技術提供:Blogger.