# laravel model 8.61 可以用 --all 建立 model factory seeder policy controller migrate ## cast (larvel 8^) https://www.youtube.com/watch?v=i4RGuYj7zi0&ab_channel=Laracasts ## touch ![](https://i.imgur.com/I7siAio.png) ![](https://i.imgur.com/EEvSzov.png) ## 不可變的carbon 在casts 8.5以後 https://www.youtube.com/watch?v=UekvqwHvWp4&ab_channel=Laratips ## 自訂relation https://stitcher.io/blog/laravel-custom-relation-classes ## view https://stitcher.io/blog/eloquent-mysql-views ## morphMap 比morphMap 好 會檢查 也不用重新build ![](https://i.imgur.com/RZW1qFR.png) ## 自定relation through可能不好用 可以自訂 https://stitcher.io/blog/laravel-custom-relation-classes ## update_at關掉 https://learnku.com/laravel/t/5199/the-laravel-lumen-eloquent-model-removes-one-of-the-created-at-and-updated-at ## creating saveing差異 https://medium.com/@lynnlin827/laravel-eloquent-%E4%BA%8B%E4%BB%B6%E4%B8%AD%E7%9A%84-updated-%E5%92%8C-saved-%E5%8E%9F%E4%BE%86%E4%B8%8D%E4%B8%80%E6%A8%A3-caa8ef0ddbc ## Default Attribute Values ![](https://i.imgur.com/FiXpT8C.png) ![](https://i.imgur.com/O8PU9hA.png) ![](https://i.imgur.com/jYHoBTL.png) ![](https://i.imgur.com/UbS16xA.png) ## upsert ![](https://i.imgur.com/o9a5BiT.png) ## 訪問器 https://chebincarl.github.io/2020/06/11/Laravel-Database-Eloquent-Model%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%8A%EF%BC%89/ ## 數組對象和集合轉換 儘管標準array鑄件足以滿足許多應用,但它確實有一些缺點。由於array強制轉換返回原始類型,因此無法直接改變數組的偏移量。例如,以下代碼將觸發 PHP 錯誤: ``` $user = User::find(1); $user->options['key'] = $value; ``` 為了解決這個問題,Laravel 提供了一個AsArrayObject將 JSON 屬性轉換為ArrayObject類的轉換。這個特性是使用 Laravel 的自定義轉換實現來實現的,它允許 Laravel 智能地緩存和轉換變異對象,以便可以修改單個偏移量而不會觸發 PHP 錯誤。要使用AsArrayObject演員表,只需將其分配給一個屬性: ``` use Illuminate\Database\Eloquent\Casts\AsArrayObject; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'options' => AsArrayObject::class, ]; ``` 同樣,Laravel 提供了一個AsCollection轉換,將你的 JSON 屬性轉換為 Laravel Collection實例: ## casts 抓取自己的屬性 ``` <?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * Set the user's first name. * * @param string $value * @return void */ public function setFirstNameAttribute($value) { $this->attributes['first_name'] = strtolower($value); } } ``` mutator 將接收在屬性上設置的值,允許您操縱該值並在 Eloquent 模型的內部$attributes屬性上設置操縱值。要使用我們的 mutator,我們只需要first_name在 Eloquent 模型上設置屬性: ``` use App\Models\User; $user = User::find(1); $user->first_name = 'Sally'; ``` 在此示例中,setFirstNameAttribute將使用 value 調用該函數Sally。然後,mutator 將該strtolower函數應用於名稱並將其結果值設置在內部$attributes數組中。 ## 關聯必看 https://learnku.com/articles/65733 ## 外键的默认名称 另一个不同是外键的默认名称,不再是类名 + 主键名,而是关联名 + 主键名: ``` if (is_null($foreignKey)) { $foreignKey = Str::snake($relation).'_'.$instance->getKeyName(); } ``` ## 获取中间表中的关联关系数据 在多对多关系中,您定义的中间表里面可能会包含扩展字段,甚至可能包含其它的关联关系。 下面生成一个中间表模型: php artisan make:model RoleUser --pivot 然后,给 belongsToMany() 指定 ->using() 方法。下面就是见证奇迹的时刻: ``` // in app/Models/User.php public function roles() { return $this->belongsToMany(Role::class) ->using(RoleUser::class) ->withPivot(['team_id']); } // app/Models/RoleUser.php: 注意继承的是 Pivot, 不是 Model use Illuminate\Database\Eloquent\Relations\Pivot; class RoleUser extends Pivot { public function team() { return $this->belongsTo(Team::class); } } // 在控制器里面就可以直接使用如下方式获取中间表 RoleUser 的 Team 信息: $firstTeam = auth()->user()->roles()->first()->pivot->team->name; ``` ## 多個資料庫獲取資料(會用到在看) https://www.youtube.com/watch?v=KJAXLf78QPs ## 自帶get魔術方法 解釋為什麼能抓到他屬性 https://www.youtube.com/watch?v=zbA-zchIZbI ## 一張表兩個model用 https://www.youtube.com/watch?v=R5fMcpDGuGg ![](https://i.imgur.com/uNUsyBD.jpg) 上面的好像會有問題 反正下面比較好 這種跟用repository 覆蓋newQuery 跟 create ## ORM 透過ORM操作 是一個active的設計模式 Laravel 的 Eloquent 会维护实例的两个数组,分别是 original 和 attributes。 https://learnku.com/articles/6657/model-events-and-observer-in-laravel ## 強制使用eager loading ![](https://i.imgur.com/ou79k3j.png) 這時候用到延遲加載 Illuminate\Database\LazyLoadingViolationException 會丟出這個例外 ## 使用trait model只要用 trait就會跑 boot + trait名稱的function 原因在這 https://github.com/tkeer/how-laravel-soft-deletes 記得在這bootfunction內 就是全域了 所以不用再覆寫boot方法 然後paren::boot()了 ## mutator and Casting(轉換跟顯示)() ![](https://i.imgur.com/9qepCyK.png) getAttribute 這個相對來說比較靈活一點 可以理解為他就是你這張表的一個欄位 所以像是repository get出來的時候是collection 然後你collection的pluck也可以抓得到這個model的欄位 增加欄位的用getAttribute 因為 getAttribute如果用自己本身欄位的會全域影響 所以要對自己欄位轉換用present present 是资料显示不同资料 因為present每個new的都不一樣 ### mutator https://www.youtube.com/watch?v=rie3Ot7C1Ek 都是get or set開頭 attribute都是結尾 #### get ![](https://i.imgur.com/m5M0HLU.png) 必定要get開頭 雖然casts也會有 但不會用到的感覺 你可以追看看他會顯示 他是負責轉換大小寫那樣 #### set 改便他的值 例如都 * 100這樣 ### 資料型態轉換用 casts https://laracasts.com/series/whats-new-in-laravel-7/episodes/3 ex boolean 在資料庫應該要true false ### 自定義casts 可以直接建立一個 extent的就照官網的範例 你可你點進來看 裡面有set 跟 get 用來表示存進去 跟取出來 然後再casts註冊 當然你也可以不寫在casts專門class裡面 一開始先經過model _get方法 在網內你看到你有->casts或->attributs ![](https://i.imgur.com/2rBwAo8.jpg) 在網內 ![](https://i.imgur.com/n7MvZso.png) 前面的transform是排序 ![](https://i.imgur.com/MPvdfGQ.jpg) 先訪問器 getAttribute那種 ![](https://i.imgur.com/1NpCABT.png) 再來casts 再來屬性 **用處** 很多model用到相同casts就可以寫這樣 **注意** 就算你有關連 你可能會被這個搶掉 因為他是先轉換器先的 小心用 ## get set 8.77進階版本 ![](https://i.imgur.com/0pWzxJl.png) ## api Appends 添加字段 https://www.youtube.com/watch?v=FNU3gYgiEgQ 如果你今天create時間想要顯示不一樣 但create還要留著 但又不必要開欄位 因為只是多一個欄位 是轉換的 可以用get轉換器 加上 append $proteced $append = []; ![](https://i.imgur.com/p1AJW0S.jpg) 但這樣不太好 全域的 所以最好是get轉換 加上你要顯示的那個collection最後加上append ![](https://i.imgur.com/arJre75.png) ## 必看 has whereHas https://www.youtube.com/watch?v=sqQE4TgitSU 關聯多的 不要加s {{ $poll->votes()->count() }} 要這樣 {{ $poll->votes->count() }} 抓那個屬性 不是查詢的 基本觀念 https://blog.quickadminpanel.com/eloquent-relationships-the-ultimate-guide/ 一對多還是... 只要對上的是多的 https://laraveldaily.com/did-you-know-five-additional-filters-in-belongsto-or-hasmany/ https://github.com/LaravelDaily/laravel-tips 基本多對多到高級 https://www.youtube.com/watch?v=V5xINbA-z9o 分層 repository裡面的用fiter設計,但不一定要 可以直接this->model->create之類的 去看model文黨 this->model 最好用繼承不會麻煩 然後 再把 hasOne 關係 filtter 變數宣告之類的分開 hasOne之類的用trait引入 這想法來自 Laravel jet stream(laravel 8 的auth) (trait原因 有很多funtion 但 helper只能一個一個註冊 不如用class全包起來 屬於誰這樣) https://www.youtube.com/watch?v=q6u_4-q0ArI ## 強制改變屬性 不經過fillable 實際應用在uuid配合觀察者 可以看最下面uuid的介紹 ``` // 修改後的密碼、重新生成 remember_token $user->forceFill([ 'password' => bcrypt($password), 'remember_token' => Str::random(60), ])->save(); ``` ## morphMap ## 外key的名稱 規定依照駝峰 但可在第二參數自訂義 所以a hasMany b (如果再belonTo的外key叫a_id 那這邊第二參數要叫a_id) b belongTO ### 預設 會以外function 的小駝峰變成 snake命名方式 _去分割 預設是id ex blogPost 變成 blog_post_id 這樣 ex ``` public function blogPost() { return $this->belongto('App\blogPost','blog_post_id') } ``` ### 自定義多態類型 默認情況下,Laravel將使用完全限定的類名稱來存儲相關模型的類型。例如,給出上面的一對多示例,其中Comment可能屬於Post或Video,則默認commentable_type分別為App\Models\Post或App\Models\Video。但是,您可能希望將資料庫與應用程式的內部結構脫鉤。在這種情況下,您可以定義"morph map"來指示Eloquent為每個模型使用自定義名稱而不是類名稱: ``` use Illuminate\Database\Eloquent\Relations\Relation; Relation::morphMap([ 'posts' => 'App\Models\Post', 'videos' => 'App\Models\Video', ]); ``` ## relation 計算數量 member->good->count() vs member->good()->count() 用第二種 第一種是會抓去所有關聯 調用的是collecion的count 但第二種 是利用關係的 調用裡面的count()涵式 ## bolonTo 的 withDefault https://learnku.com/articles/5148/withdefault-method-of-belongsto-association 兩個可以共用一個主題 belongTo主題 ``` /** * 主題.. */ public function category(): BelongsTo { return $this->belongsTo(config('morph-map.customer_service_category')) ->withDefault([ 'type' => self::TYPE_MEMBER, 'name' => '未分類', ]); } ``` ## model collection https://laravel.com/docs/8.x/eloquent-collections ## with load loadMissing 急切加載 通過使用with()您可以在**查詢父模型**時“急切加載”關係: `$book = Book::with('author')->find($id);` 延遲加載 要在檢索到父模型後預先加載關係: `$book->load('author');` 這也可以用於僅急切加載丟失的內容 `$book->loadMissing('author');` 與load()方法相反,loadMissing()方法過濾給定的關係,並且只有在尚未加載時才懶惰地“急切”加載它們 load會加載,但loadMissing會看他有沒有加載過,結論loadMissing>load 技術長也這樣用 ## 查詢大量資料 lazy Collection https://iter01.com/574559.html https://www.oulub.com/zh-TW/Laravel/collections-lazy-collections 但好像要千萬級別,當做增加知識就好 ## 原生文黨中間的save 可以看到update是 fill 在save 所以save裡面的option要搞清楚 可以看這篇 https://stackoverflow.com/questions/32891883/what-are-the-available-options-for-eloquents-modelsave-method update比save好 https://medium.com/@lynnlin827/laravel-eloquent-%E4%BA%8B%E4%BB%B6%E4%B8%AD%E7%9A%84-updated-%E5%92%8C-saved-%E5%8E%9F%E4%BE%86%E4%B8%8D%E4%B8%80%E6%A8%A3-caa8ef0ddbc ## Eloquent where 日期方法 雄辯,請與功能的日期whereDay(),whereMonth(), whereYear(),whereDate()和whereTime() ``` $products = Product::whereDate('created_at', '2018-01-31')->get(); $products = Product::whereMonth('created_at', '12')->get(); $products = Product::whereDay('created_at', '31')->get(); $products = Product::whereYear('created_at', date('Y'))->get(); $products = Product::whereTime('created_at', '=', '14:13:58')->get(); ``` ## All() find 在調用 Eloquent 的 時Model::all(),您可以指定要返回的列。 find也可以 `$ users = User :: all ([ 'id' , 'name' , 'email' ]); $ users = User :: find ([ 1 , 2 , 3 ]); ` ## 更改 Created_at 和 Updated_at 的格式 要更改格式,created_at您可以在模型中添加一個方法,如下所示: ``` public function getCreatedAtFormattedAttribute() { return $this->created_at->format('H:i d, M Y'); } ``` 所以你可以$entry->created_at_formatted在需要的時候使用它。它將返回這樣的created_at屬性:04:19 23, Aug 2020 ## 將數組類型存儲到 JSON 中 如果您有接受數組的輸入字段,並且必須將其存儲為 JSON,則可以$casts在模型中使用屬性。這images是一個 JSON 屬性。 ``` protected $casts = [ 'images' => 'array', ]; ``` 因此,您可以將其存儲為 JSON,但是當從數據庫中檢索時,它可以用作數組。 ## 減少內存 https://www.infyom.com/blog/tobase-function-in-laravel-eloquent 有時我們需要將大量數據加載到內存中。例如: `$orders = Order::all();` 但是如果我們有非常大的數據,這可能會很慢,因為 Laravel 準備了 Model 類的對象。在這種情況下,Laravel 有一個方便的功能toBase() ## 親子的3層結構計算數量 你有一個 3 層的親子結構,比如一個電子商店的分類,並且你想在第三級顯示產品的數量,你可以使用with('yyy.yyy')然後添加withCount()作為條件 ``` class HomeController extend Controller { public function index() { $categories = Category::query() ->whereNull('category_id') ->with(['subcategories.subcategories' => function($query) { $query->withCount('products'); }])->get(); } } ``` ``` class Category extends Model { public function subcategories() { return $this->hasMany(Category::class); } public function products() { return $this->hasMany(Product::class); } } ``` ``` <ul> @foreach($categories as $category) <li> {{ $category->name }} @if ($category->subcategories) <ul> @foreach($category->subcategories as $subcategory) <li> {{ $subcategory->name }} @if ($subcategory->subcategories) <ul> @foreach ($subcategory->subcategories as $subcategory) <li>{{ $subcategory->name }} ({{ $subcategory->product_count }})</li> @endforeach </ul> @endif </li> @endforeach </ul> @endif </li> @endforeach </ul> ``` ## whereIn取代方法 但個人覺得 多重Where的話還是用whereIn find最好當結尾 之前踩過雷 `return Product::whereIn('id', $this->productIDs)->get();` `return Product::find($this->productIDs)` whereIn 是吃 array ## 查詢丟出404 ``` $model = Flight::where('legs', '>', 3)->firstOr(function () { // ... }) ``` ## findOrFail 跟 optional() ``` $product = Product::findOrFail($id); // shows 404 if not found $product->update($productDataArray); ``` 可簡化成 `optional(Product::find($id))->update($productDataArray);` ## belongTo 默認 belongsTo關係中分配一個默認模型,以避免在調用它時出現致命錯誤,就像{{ $post->user->name }}$post->user 不存在一樣 ``` public function user() { return $this->belongsTo('App\User')->withDefault(); } ``` ## with用法 初級 `$users = App\Book::with('author:id,name')->get();` 進階 `$users = App\Book::with('author:id,name')->get();` ## 不要使用belongsTo,使用hasMany 可參考 盡量從父層開始 belongsTo關係,在創建子記錄時不要傳遞父母的ID,而是使用hasMany關係來製作更短的句子 ``` // if Post -> belongsTo(User), and User -> hasMany(Post)... // Then instead of passing user_id... Post::create([ 'user_id' => auth()->id(), 'title' => request()->input('title'), 'post_text' => request()->input('post_text'), ]); // Do this auth()->user()->posts()->create([ 'title' => request()->input('title'), 'post_text' => request()->input('post_text'), ]); ``` ## 檢查關係方法是否存在 可以用php用法 `method_exists($object, $methodName)` ``` $user = User::first(); if (method_exists($user, 'roles')) { // Do something with $user->roles()->... } ``` ## 關聯表 多對多的 **前提是你的關聯表有要做別的事情,不然多此一舉** 跑這個 php artisan make:model RoleUser --pivot 在belongsToMany()with->using()方法中指定它。然後你就可以施展魔法了,就像例子中那樣 ``` // in app/Models/User.php public function roles() { return $this->belongsToMany(Role::class) ->using(RoleUser::class) ->withPivot(['team_id']); } // app/Models/RoleUser.php: notice extends Pivot, not Model use Illuminate\Database\Eloquent\Relations\Pivot; class RoleUser extends Pivot { public function team() { return $this->belongsTo(Team::class); } } // Then, in Controller, you can do: $firstTeam = auth()->user()->roles()->first()->pivot->team->name; ``` ## 按首字母分組 ``` $ users = User :: all ()-> groupBy ( function ( $ item ) { return $ item -> name [ 0 ]; }); ``` ## 驗證 Model 是否被儲存 isDirty、isClean ``` $user = User::create([ 'first_name' => 'Taylor', 'last_name' => 'Otwell', 'title' => 'Developer', ]); $user->title = 'Painter'; $user->isDirty(); // true $user->isDirty('title'); // true $user->isDirty('first_name'); // false $user->isClean(); // false $user->isClean('title'); // false $user->isClean('first_name'); // true $user->save(); $user->isDirty(); // false $user->isClean(); // true ``` ## 一對一 一對多 多對多 ## attach可接受集合 所以應該是看model是一對多等型態 ![](https://i.imgur.com/YGWQ7a9.png) ## 注意事項 第一 laravel 6 . 7的id默認都是biginterger 在原本表單改成increments或連接的外key用big連接 第二 刪除外key 刪除一個外鍵,可以使用dropForeign方法 第三 重點非常重要 onUpdate 則是主鍵表中被參考字段的值更新 onDelete 是指在主鍵表中刪除一條記錄 on update 和 on delete 后面可以跟的詞語有四個 no action , set null , set default ,cascade no action 表示 不做任何操作, set null 表示在外鍵表中將相應字段設置為null set default 表示設置為默認值 cascade 表示級聯操作(一般都用這個) 就是說,如果主鍵表中被參考字段更新,外鍵表中也更新,主鍵表中的記錄被刪除,外鍵表中改行也相應刪除 多數人都只寫delete 這必加 不然你主表crud的地方會掛掉 update沒加我沒掛掉 *** 一些基本要注意的 $blog->comments 會跑出all 跟has不一樣 BlogPost::has 是找全部關聯 這是被聯的 $blog->comments() 看他是甚麼關聯 return ## 一對一 https://www.latech.tw/2017/02/laravel-migrationmodeldb.html 基本互存 hasOne $author->profile()->save($profile); belognto $profile->author()->associate($author)->save(); ## 一對多 ``` class Post extends Model { /** * Get the comments for the blog post. */ public function comments() { return $this->hasMany('App\Comment'); } } ``` - 原廠設定 記住,Eloquent將自動確定Comment模型上正確的外鍵列。按照慣例,Eloquent將採用擁有模型的“蛇皮套”名稱,並在其後綴_id。因此,對於此示例,Eloquent將假定Comment模型上的外鍵為post_id。 ## 一對多(逆向) - 原廠設定 post_id將Comment模型中的匹配到模型id上的Post。Eloquent通過檢查關係方法的名稱並在方法名稱後加上_主鍵列的名稱作為後綴,從而確定默認的外鍵名稱。但是 ## 多對多 注意 關聯表 -- 兩個表相加 重點重點****兩個表相加不用s ex BlogPost tag 關聯表名字 Blog_post_tag `大地雷小心` 這邊的where('id',$id); 不能用find(); 因為要對上query builder 我猜是要看find的那個句子 ![](https://i.imgur.com/RIhvHah.png) ## 多對多 新增移除 新增 attach `$user->roles()->attach($roleId);` ``` $user->roles()->attach($roleId1->id,$roleId2->id); 這句記得它們user id一樣 只存的那邊 role的id不一樣 ``` 移除 detach ``` // 從使用者上移除單一身份... $user->roles()->detach($roleId); // 從使用者上移除所有身份... $user->roles()->detach(); ``` sync雖然是只增加要得 其他的移除 但他有第二個參數 **可以只加不移除** `sync($a,false)` ## 多對多 參數 除了自定義聯接表的名稱之外,還可以通過將其他參數傳遞給belongsToMany方法來自定義表上鍵的列名。第三個參數是您要在其上定義關係的模型的外鍵名稱,而第四個參數是您要加入的模型的外鍵名稱: ``` return $this- >belongsToMany('App\Role', 'role_user', 'user_id', 'role_id'); ``` 第一個關聯的 第二表名 第三自己名字 第四 外key ### 關聯 - withPivot 默認情況下,只有模型關鍵點會出現在對pivot像上。如果數據透視表包含額外的屬性,則在定義關係時必須指定它們: `return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');` - wherePivot,wherePivotIn,wherePivotNotIn 通過中間表列過濾關係 ``` return $this->belongsToMany('App\Role')->wherePivot('approved', 1); return $this->belongsToMany('App\Role')->wherePivotIn('priority', [1, 2]); return $this->belongsToMany('App\Role')->wherePivotNotIn('priority', [1, 2]); ``` ## 自定義中間表模型 ``` class Role extends Model { /** * The users that belong to the role. */ public function users() { return $this->belongsToMany('App\User')->using('App\RoleUser'); } } ``` 如果您定義了使用自定義樞紐模型的多對多關係,並且該樞紐模型具有自動遞增的主鍵,則應確保自定義樞紐模型類定義了一個incrementing設置為的屬性true。 `public $incrementing = true;` ## a->b->c 直接a->c 命名 中間先在連過去的 ex useCar ``` class Mechanic extends Model { /** * Get the car's owner. */ public function carOwner() { return $this->hasOneThrough('App\Owner', 'App\Car'); } } ``` 傳遞給該hasOneThrough方法的第一個參數是我們希望訪問的最終模型的名稱,而第二個參數是中間模型的名稱。 自訂的話 如果您想自定義關係的鍵,則可以將它們作為方法的第三個和第四個參數傳遞hasOneThrough。第三個參數是中間模型上外鍵的名稱。第四個參數是最終模型上外鍵的名稱。第五個參數是本地鍵,而第六個參數是中間模型的本地鍵: ``` return $this->hasOneThrough( 'App\Owner', 'App\Car', 'mechanic_id', // Foreign key on cars table... 'car_id', // Foreign key on owners table... 'id', // Local key on mechanics table... 'id' // Local key on cars table... ); ``` ## 多态关联 https://www.kancloud.cn/curder/laravel/408493 多态关联允许一个模型在单个关联下属于多个不同父模型。常见的多态关联就是评论,评论内容可能是属于文章或视频。 ## 檢查是否有任何字段被更改 可以搭配觀察者 https://www.youtube.com/watch?v=_xluet13xxE ![](https://i.imgur.com/Akev7PC.png) ## model 查詢方法 ### 關於Query builder ORM 在Laravel中有兩種操作DB的方法, DB Query builder Eloquent ORM 先來淺談一下兩者 | |DB Query builder | Eloquent ORM | | -------- | -------- | -------- | | 使用方式 | DB::table()…語法 | 需建立與維護Model | | 回傳型態 | array | Collection | | 方便程度 | 普通 | 很方便 | | 彈性 | 很彈性 | 普通 | | 維護 | 若沒有寫class,就需要到處維護 | 只需維護Model | | 易用程度 | 普通 | 較易用 | 以上是我兩者使用過後的小心得,不一定是都是對的, 因為遇到的情況有些差異,所以有一些不一樣的感受, 但兩者都會自己轉為sql語法進行操作, 看完這個簡單的差異之後,讓我們來看看各自的用法吧! ### 建立關聯 User::find(1)->roles()->save($role); 上面的例子裡,新的 Role 模型物件被儲存, 同時附加關聯到 user 模型。也可以傳入屬性陣列, 把資料加到關聯資料表: ``` hasOne $profile->author()->associate($author)->save(); belognto 原本是 $author->profile()->save($profile); ``` 當然你可以直接賦值去 ### 查詢關聯 不用with的方法 可以直接調用 ex $profile->author 另外沒有關聯前 不會顯示出來 ex ``` $profile = Profile::find(1); 不會跑出來關聯 $profile->author(); $profile; ``` 這時才回跑出來 因為有呼叫了 ### with用法 ``` $author = Author::with('Profile')->whereKey(1)->first(); 一次with多個 $author = Author::with(['Profile','comment'])->whereKey(1)->first(); ``` `::find() === whereKey(1)->first();` 原本寫法 ### 查詢有沒有關聯 關聯用has where查自己屬性 ### where 特別用法 Book::where("title",'like','%xxxx%')->get() <!-- 查詢自己的屬性 --> ### 查詢關聯的有沒有這個屬性的 裡面有沒有符合 這是查詢沒有的 ``` BlogPost::doesntHave('comments')->get(); BlogPost::has('comments')->get(); ``` ### 關聯的有沒有這個屬性的 裡面有沒有符合 這是查尋有的 `BlogPost::whereDoesntHave('comments',function($query){$query->where('content','like','%a%');})->get();` ### Book::sum('price') 計算總價 ### Book::avg('price') 平均 https://www.youtube.com/watch?v=oQHEddn6ItI ### 關聯要注意的事情 Eager Loading lazy loaded 所謂的n+1問題 官網 https://laravel.com/docs/7.x/eloquent-relationships#constraining-eager-loads #### 如果要查詢裡面的裡面 ex 本書的所有作者和所有作者的個人聯繫人 用.去連接 ex `$books = App\Book::with('author.contacts')->get();` ![](https://i.imgur.com/RqyyhUA.png) 預設是lazy loaded 所以盡量用 With去關聯 ### 關於updateOrCreate firstOrCreate 差別 firstOrCreate第一個參數是判斷 第二是要加入的 ![](https://i.imgur.com/AeKQpTd.png) updateOrCreate第一個參數是判斷 第二是加入的 但是但是create是兩個參數合併 像這張圖是加username eamil password ![](https://i.imgur.com/JweT2My.png) ## softDelete 軟刪除 **表有更動都要composer dump-autoload** ### 基本寫法子從關係刪除 外key請加上 `onDelete('cascade')` 然後`另外建立`migrate ``` 記住有() 跟 timestamps一樣 up寫 $table->softDeletes(); down寫 $table->dropSoftDeletes() ``` 最基礎寫法 ### even寫法 施工 #### 復原連同子關係都復原 ![](https://i.imgur.com/PV6MdQV.png) ## model查詢的複製 https://www.youtube.com/watch?v=nM5SRNAd78Y ## 日期轉換器 預設情況下,Eloquent 將會把 created_at 和 updated_at 欄位轉換成 Carbon 的實例,它提供了各式各樣有用的方法,並繼承了 PHP 原生的 DateTime 類別。 你可以在你的模型中自訂哪些欄位要自動地被修改,或甚至完全禁止修改,只要藉由覆寫模型的 $dates 屬性: `protected $dates = ['created_at', 'updated_at', 'deleted_at'];` 但最好寫在Casting會比較好 ## uuid https://stackoverflow.com/questions/37948764/laravel-uuid-generation/54301345 之後可以先嘗試 stackoverflow的 第一個解答 不行再用公司的解答 ``` <?php namespace Dolfan\Traits; use Illuminate\Support\Str; trait Uuidable { /** * Indicates if the UUIDs are auto-generating. * * @var bool */ public $generating = true; /** * The uuid key for the model. * * @var string */ protected $uuidKey = 'uuid'; /** * Get the value indicating whether the UUIDs are generating. * * @return bool */ public function getGenerating() { return $this->generating; } /** * Get the uuid key for the model. * * @return string */ public function getUuidKeyName() { return $this->uuidKey; } public function firstOrFailByUUID(string $uuid) { return $this->where($this->getUuidKeyName(), $uuid)->firstOrFail(); } public function findByUUID(string $uuid) { return $this->where($this->getUuidKeyName(), $uuid)->first(); } /** * Boot function from Laravel. */ protected static function boot() { parent::boot(); static::creating(function ($model) { if ($model->getGenerating()) { if (empty($model->{$model->getUuidKeyName()})) { $model->{$model->getUuidKeyName()} = Str::uuid()->toString(); } } }); } } ``` 另外一種寫法 用觀察者 ``` <?php namespace App\Observers; use Illuminate\Support\Str; use TWJOIN\AdminPanel\Models\AdminUser; class AdminUserObserver { /** * Listen to the Media creating event. */ public function creating(AdminUser $user): void { $user->forceFill(['uuid' => Str::uuid()]); } } ``` ## triat 初始化 跟 自動run https://medium.com/swlh/laravel-booting-and-initializing-models-with-traits-2f77059b1915 ###### tags: `Laravel`