$active_products = $query->clone()->where('status', 1)->get(); // it will not modify the $query
$inactive_products = $query->clone()->where('status', 0)->get(); // so we will get inactive products from $query
public function scopeActive($query) {
return $query->where('active', 1);
}
public function scopeRegisteredWithinDays($query, $days) {
return $query->where('created_at', '>=', now()->subDays($days));
}
// Will return Eloquent Model with first_name and email only
$user = User::find(1, ['first_name', 'email']);
// Will return Eloquent Collection with first_name and email only
$users = User::find([1,2,3], ['first_name', 'email']);
按照键查找
您还可以使用 whereKey() 方法根据您指定的主键查找多条记录。(默认 id 但是你可以在 Eloquent 模型中覆盖掉)
$users = User::whereKey([1,2,3])->get();
使用 UUID 替换 auto-increment
您不想在模型中使用自动递增 ID?
迁移:
Schema::create('users', function (Blueprint $table) {
// $table->increments('id');
$table->uuid('id')->unique();
});
模型:
class User extends Model
{
public $incrementing = false;
protected $keyType = 'string';
protected static function boot()
{
parent::boot();
User::creating(function ($model) {
$model->setId();
});
}
public function setId()
{
$this->attributes['id'] = Str::uuid();
}
}
class Post extends Model
{
// Forget cache key on storing or updating
public static function boot()
{
parent::boot();
static::saved(function () {
Cache::forget('posts');
});
}
}
修改 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。
你也可以用同样的方法更改 updated_at:
public function getUpdatedAtFormattedAttribute()
{
return $this->updated_at->format('H:i d, M Y');
}
在有需要的时候使用 $entry->updated_at_formatted。它会返回 updated_at 的属性如同: 04:19 23, Aug 2020 。
如果 name 不在team模型的 $fillable 中,怎么办?或者如果根本就没有 $fillable/$guarded, 怎么办?
$team->forceFill(['name' => $request->name])
这将忽略该查询的 $fillable 并强制执行。
3 层父子级结构
If you have a 3-level structure of parent-children, like categories in an e-shop, and you want to show the number of products on the third level, you can use with('yyy.yyy') and then add withCount() as a condition
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);
}
}
class Transaction extends Model
{
use MultiTenantModelTrait;
}
class Task extends Model
{
use MultiTenantModelTrait;
}
trait MultiTenantModelTrait
{
// This method's name is boot[TraitName]
// It will be auto-called as boot() of Transaction/Task
public static function bootMultiTenantModelTrait()
{
static::creating(function ($model) {
if (!$isAdmin) {
$isAdmin->created_by_id = auth()->id();
}
})
}
}
Laravel 的 find 方法,比只传一个 ID 更多的选择
// 在 find($id) 方法中第二个参数可以是返回字段
Studdents::find(1, ['name', 'father_name']);
// 这样我们可以查询 ID 为 '1' 并返回 name , father_name 字段
// 我们可以用数组的方式传递更多的 ID
Studdents::find([1,2,3], ['name', 'father_name']);
// 输出: ID 为 1,2,3 并返回他们的 name , father_name 字段
public function index()
{
if (\App\Models\User::exists()) {
// returns boolean true or false if the table has any saved rows
}
if (\App\Models\User::count()) {
// returns the count of rows in the table
}
}
如何避免 property of non-object 错误
// 设定默认模型
// 假设你有一篇 Post (帖子) 属于一个 Author (作者),代码如下:
$post->author->name;
// 当然你可以像这样阻止错误:
$post->author->name ?? ''
// 或者
@$post->author->name
// 但你可以在Eloquent关系层面上做到这一点。
// 如果没有作者关联帖子,这种关系将返回一个空的App/Author模型。
public function author() {
return $this->belongsTo('App\Author')->withDefault();
}
// 或者
public function author() {
return $this->belongsTo('App\Author')->withDefault([
'name' => 'Guest Author'
]);
}
Eloquent 数据改变后获取原始数据
Eloquent 模型数据改变后,你可以使用 getOriginal () 方法来获取原始数据
$user = App\User::first();
$user->name; // John
$user->name = "Peter"; // Peter
$user->getOriginal('name'); // John
$user->getOriginal(); // Original $user record
use Illuminate\Support\Facades\DB;
$totalQuery = DB::table('orders')->selectRaw('SUM(price) as total');
DB::table('orders')
->select('*')
->crossJoinSub($totalQuery, 'overall')
->selectRaw('(price / overall.total) * 100 AS percent_of_total')
->get();
belongsToMany 的中间表命名
为了决定 关系表的中间表, Eloquent 将按字母顺序连接两个相关的型号名称。
这意味着可以这样添加 “Post” 和 “Tag” 之间的连接:
class Post extends Model
{
public $table = 'posts';
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}
但是,您可以自由重写此约定,并且需要在第二个参数中指定联接表。
class Post extends Model
{
public $table = 'posts';
public function tags()
{
return $this->belongsToMany(Tag::class, 'posts_tags');
}
}
如果希望明确说明主键,还可以将其作为第三个和第四个参数提供。
class Post extends Model
{
public $table = 'posts';
public function tags()
{
return $this->belongsToMany(Tag::class, 'post_tag', 'post_id', 'tag_id');
}
}
class Tag extends Model
{
public $table = 'tags';
}
class Post extends Model
{
public $table = 'posts';
public function tags()
{
return $this->belongsToMany(Tag::class, 'posts_tags', 'post_id', 'tag_id')
->using(PostTagPivot::class)
->withTimestamps()
->withPivot('flag');
}
}
class PostTagPivot extends Pivot
{
protected $table = 'posts_tags';
}
// Somewhere in the Controller
public function getPostTags($id)
{
return Post::findOrFail($id)->tags()->orderByPivot('flag', 'desc')->get();
}
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Prunable;
class Flight extends Model
{
use Prunable;
/**
* Get the prunable model query.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function prunable()
{
return static::where('created_at', '<=', now()->subMonth());
}
}
此外,在修剪方法中,可以设置删除模型之前必须执行的操作:
protected function pruning()
{
// Removing additional resources,
// associated with the model. For example, files.
Storage::disk('s3')->delete($this->filename);
}
class User extends Model
{
public $casts = [
'date_field' => 'immutable_date',
'datetime_field' => 'immutable_datetime',
];
}
findorfail方法也接收ids数组
findorfail 方法也接收 ids 数组。若无 ids 被找到 则失败。
若你想拿到一个模型的集合 并不想检测返回数量为你想得到的数量时很好用。
User::create(['id' => 1]);
User::create(['id' => 2);
User::create(['id' => 3]);
// Retrives the user...
$user = User::findOrFail(1);
// Throws a 404 because the user doesn't exist...
User::findOrFail(99);
// Retrives all 3 users...
$users = User::findOrFail([1, 2, 3]);
// Throws because it is unable to find *all* of the users
User::findOrFail([1, 2, 3, 99]);
class File extends Model
{
use SoftDeletes;
// Add Prunable trait
use Prunable;
public function prunable()
{
// Files matching this query will be pruned
return static::query()->where('deleted_at', '<=', now()->subDays(14));
}
protected function pruning()
{
// Remove the file from s3 before deleting the model
Storage::disk('s3')->delete($this->filename);
}
}
// Add PruneCommand to your shedule (app/Console/Kernel.php)
$schedule->command(PruneCommand::class)->daily();
// Migration
Schema::table('products', function (Blueprint $table) {
$table->datetime('live_at')->nullable();
});
// In your model
public function live()
{
return !is_null($this->live_at);
}
// Also in your model
protected $dates = [
'live_at'
];
// Retrieve all logged_in users
$loggedInUsers = User::where('logged_in', true)->get();
// Filter them using a Collection method or php filtering
$nthUsers = $loggedInUsers->nth(3);
// You can't do this on the collection
$nthUsers->update(/* ... */);
// But you can retrieve the Builder using ->toQuery()
if ($nthUsers->isNotEmpty()) {
$nthUsers->toQuery()->update(/* ... */);
}
选择聚合计算相关模型
选择聚合计算相关模型。
需要指出的是在一组相关模型上使用 count 方法要慢一点。
// In your controller
$user = User::withCount('articles');
// Or, to add a constraint to the aggregate
$user = User::withCount([
'articles' => fn ($query) => $query->live();
]);
// In your view
$user->articles_count
// Instead of
$user->articles->count();
自定义强制转换
你可以自定义强制转换来让 Laravel 自动格式化你的模型数据。
下面是一个在检索或更改用户名时将其大写的示例。
class CapitalizeWordsCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
return ucwords($value);
}
public function set($model, string $key, $value, array $attributes)
{
return ucwords($value);
}
}
class User extends Model
{
protected $casts = [
'name' => CapitalizeWordsCast::class,
'email' => 'string',
];
}
保存中不要触发事件
若你不想触发模型事件 使用 saveQuietly() 方法
public function quietly()
{
$user = User::findOrFail(1);
$user->name = 'Martin Joo';
// Will not trigger any model event
$user->saveQuietly();
}
基于相关模型的平均值或总数排序
你是否曾需要基于关系模型的平均值或总数来排序?
这很简单
public function bestBooks()
{
Book::query()
->withAvg('ratings as average_rating', 'rating')
->orderByDesc('average_rating');
}
返回事务结果
若你有一个 DB 事务 并且你想返回它的结果 至少有两种方法:
// 1. You can pass the parameter by reference
$invoice = NULL;
DB::transaction(function () use (&$invoice) {
$invoice = Invoice::create(...);
$invoice->items()->attach(...);
})
// 2. Or shorter: just return trasaction result
$invoice = DB::transaction(function () {
$invoice = Invoice::create(...);
$invoice->items()->attach(...);
return $invoice;
});
从 query 中移除多个公共 scope
当使用 Global Scopes 时 你不仅可以使用多个 scope 而且可以在不需要的时候通过提供的 withoutGlobalScopes 方法移除他们
// Instead of
Integration::where('name', 'foo')->first()->active;
// You can use
Integration::where('name', 'foo')->value('active');
// or this to throw an exception if no records found
Integration::where('name', 'foo')->valueOrFail('active')';
$user = User::first(); // ['name' => "John']
$user->name = 'John';
$user->originalIsEquivalent('name'); // true
$user->name = 'David'; // Set directly
$user->fill(['name' => 'David']); // Or set via fill
$user->originalIsEquivalent('name'); // false
定义访问器与修改器的新方法
Laravel 8.77:定义访问器与修改器的新方法
// Before, two-method approach
public function setTitleAttribute($value)
{
$this->attributes['title'] = strtolower($value);
}
public function getTitleAttribute($value)
{
return strtoupper($value);
}
// New approach
protected function title(): Attribute
{
return new Attribute(
get: fn ($value) => strtoupper($value),
set: fn ($value) => strtolower($value),
}
另外一种定义访问器与修改器的方法
在一些模型中想用同样的修改器 访问器 可以自定义转换。
只需要创建一个类 实现 CastsAttributes 实现两个方法
get 标识模型应当从数据库如何拿到
set 标识数据应当如何存储到数据库
<?php
namespace App\Casts;
use Carbon\Carbon;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
class TimestampsCast implements CastsAttributes
{
public function get($model, string $key, $value, array $attributes)
{
return Carbon::parse($value)->diffForHumans();
}
public function set($model, string $key, $value, array $attributes)
{
return Carbon::parse($value)->format('Y-m-d h:i:s');
}
}
然后你可以在模型中实现这个转换
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Casts\TimestampsCast;
use Carbon\Carbon;
class User extends Authenticatable
{
/**
* The attributes that should be cast.
*
* @var array
*/
protected $casts = [
'updated_at' => TimestampsCast::class,
'created_at' => TimestampsCast::class,
];
}
$book = Book::whereCount('authors')
->orderBy('authors_count', 'DESC')
->having('modules_count', '>', 10)
->firstOr(function() {
// THe Sky is the Limit ...
// You can perform any action here
});
$post = Post::whereId($id)->first();
$result = $post->created_at->diffForHumans();
/* OUTPUT */
// 1 Minutes ago, 2 Week ago etc..as per created time
通过获取器排序
我们不是按数据库级别排序,而是按返回的集合的获取器排序。
class User extends Model
{
// ...
protected $appends = ['full_name'];
public function getFullNameAttribute()
{
return $this->attribute['first_name'] . ' ' . $this->attributes['last_name'];
}
// ..
}
class UserController extends Controller
{
// ..
public function index()
{
$users = User::all();
// order by full_name desc
$users->sortByDesc('full_name');
// or
// order by full_name asc
$users->sortBy('full_name');
// ..
}
// ..
}
sortByDesc 和 sortBy 方法在集合中。
创建或发现特定模型的检查
如果你想检查特定模型是否被创建或找到,使用 wasRecentlyCreated 模型属性。
$user = User::create([
'name' => 'Oussama',
]);
// return boolean
return $user->wasRecentlyCreated;
// true for recently created
// false for found (already on you db)
// Before (fetches all columns on the row)
Statistic::where('user_id', 4)->first()->post_count;
// After (fetches only `post_count`)
Statistic::where('user_id', 4)->value('post_count');
将数组传给 where 方法
你可以传递一个数组给 where 方法。
// Instead of this
JobPost::where('company', 'laravel')
->where('job_type', 'full time')
->get();
// You can pass an array
JobPost::where(['company' => 'laravel',
'job_type' => 'full time'])
->get();
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('table', function (Blueprint $table) {
$table->string('secret')->nullable()->invisible();
});