- Оригинальный адрес:20 советов и хитростей Laravel Eloquent
- постоянный адрес:blog.Schedule.What/2019/01/03/…
- Переводчик:KBiao
За его поверхностью просто и легко использовать, есть много скрытых функций или малоизвестных методов для достижения некоторых полезных нужд. В этой статье я покажу вам некоторые приемы.
1. Увеличение и уменьшение
Если вы обычно делаете это:
$article = Article::find($article_id);
$article->read_count++;
$article->save();
Тогда вы можете попробовать это:
$article = Article::find($article_id);
$article->increment('read_count');
Или это тоже возможно:
Article::find($article_id)->increment('read_count');
Article::find($article_id)->increment('read_count', 10); // +10
Product::find($produce_id)->decrement('stock'); // -1
2. XorY-метод
У Eloquent есть много методов, которые представляют собой комбинацию двух методов для достижения таких требований «пожалуйста, сделайте X, иначе сделайте Y».
пример 1 findOrFail():
Вы можете поставить такой код:
$user = User::find($id);
if (!$user) { abort (404); }
Замените его на это:
$user = User::findOrFail($id);
Пример 2 firstOrCreate():
Не надо так долго писать:
$user = User::where('email', $email)->first();
if (!$user) {
User::create([
'email' => $email
]);
}
Достаточно:
$user = User::firstOrCreate(['email' => $email]);
3. Метод boot() модели
В моделях Eloquent есть волшебное место под названием boot(), где вы можете переопределить поведение по умолчанию:
class User extends Model
{
public static function boot()
{
parent::boot();
static::updating(function($model)
{
// 记录一些日志
// 覆盖或者重写一些属性 比如$model->something = transform($something);
});
}
}
Наверное, один из самых распространенных примеров — установка значений некоторых полей при создании объекта модели. Допустим, вам нужно сгенерировать поле UUID при создании объекта.
4. Ассоциативная модель с условиями и сортировкой
Обычно способ определения реляционной модели таков:
public function users() {
return $this->hasMany('App\User');
}
Но знаете ли вы, что вы можете добавить условия where или orderBy при определении реляционной модели? Например, вам нужно определить определенный тип отношений с пользователем и заказать информацию по электронной почте, тогда вы можете сделать это:
public function approvedUsers() {
return $this->hasMany('App\User')->where('approved', 1)->orderBy('email');
}
5. Свойства модели: метка времени, добавление и т. д.
Модели Eloquent имеют некоторые «параметры», которые будут отображаться как свойства класса. Наиболее часто используемые, вероятно, следующие:
class User extends Model {
protected $table = 'users';
protected $fillable = ['email', 'password']; // 这些字段可以在模型的 create 方法中直接创建
protected $dates = ['created_at', 'deleted_at']; // 这些字段将会转换成 Carbon类型的,可以方便的使用 Carbon 提供的时间方法
protected $appends = ['field1', 'field2']; // 序列化时候附加的额外属性,通过模型中定义 getXXXAttribute 的方式来定义
}
Не только эти, но и:
protected $primaryKey = 'uuid'; // 模型的主键名称可以不是默认的 id
public $incrementing = false; // 甚至可以不必是自增的类型!
protected $perPage = 25; // 是的,你还定义模型集合分页参数(默认是 15)
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at'; // 默认的时间戳字段也是可以改变的
public $timestamps = false; // 或者完全不用他
Их даже больше, я перечислил только самые интересные, больше смотрите по умолчаниюКласс абстрактной моделикод и увидеть все используемые методы трейтов.
6. Запросить несколько объектов сущностей
Метод find() должен быть известен всем, верно?
$user = User::find(1);
Я удивлен, как мало людей знают, что он может принимать несколько идентификаторов в виде массива:
$users = User::find([1,2,3]);
7. WhereX
Существует элегантный способ поместить следующий код:
$users = User::where('approved', 1)->get();
Измените его на это:
$users = User::whereApproved(1)->get();
Да, вы также можете изменить имя любого поля и добавить его в качестве суффикса к «где», и это волшебным образом произведет желаемый эффект (черезмагический методВызов реализации).
Кроме того, в Eloquent есть несколько предопределенных методов, связанных с датой/временем:
User::whereDate('created_at', date('Y-m-d'));
User::whereDay('created_at', date('d'));
User::whereMonth('created_at', date('m'));
User::whereYear('created_at', date('Y'));
8. Сортировка с использованием полей реляционной модели
Более сложный «трюк». Что делать, если у вас есть сообщения, но вы хотите отсортировать их по самым новым сообщениям? Очень распространенный запрос на форумах с последней обновленной темой вверху, верно?
Во-первых, определите отношение последних сообщений по теме:
public function latestPost()
{
return $this->hasOne(\App\Post::class)->latest();
}
Затем мы можем сделать это с помощью этого волшебного метода в нашем контроллере:
$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');
9. Eloquent::when() — больше нет if -else
Большую часть времени мы используем if-else для реализации условного запроса, похожего на этот код:
if (request('filter_by') == 'likes') {
$query->where('likes', '>', request('likes_amount', 0));
}
if (request('filter_by') == 'date') {
$query->orderBy('created_at', request('ordering_rule', 'desc'));
}
Но лучший способ - использовать метод when()
$query = Author::query();
$query->when(request('filter_by') == 'likes', function ($q) {
return $q->where('likes', '>', request('likes_amount', 0));
});
$query->when(request('filter_by') == 'date', function ($q) {
return $q->orderBy('created_at', request('ordering_rule', 'desc'));
});
Возможно, это не выглядит короче или элегантнее, но самое мощное — это возможность передавать параметры:
$query = User::query();
$query->when(request('role', false), function ($q, $role) {
return $q->where('role_id', $role);
});
$authors = $query->get();
10. Объект модели по умолчанию, связанный с BelongsTo
Предположим, что есть почтовый объект, который принадлежит объекту автора, а в шаблоне лезвия есть следующий код
{{ $post->author->name }}
Но что делать, если автор удален, или не установлен по каким-либо причинам? Тогда это вызовет ошибку, которая может быть "свойством не-объекта".
Конечно, вы можете исправить эту ошибку с помощью следующего кода:
{{ $post->author->name ?? '' }}
Но вы можете решить эту проблему во время определения модели:
public function author()
{
return $this->belongsTo('App\Author')->withDefault();
}
В этом примере ассоциация author() вернет пустую модель App\Author, когда для этого сообщения нет связанного автора.
Сделав еще один шаг, мы можем установить некоторые свойства по умолчанию для этой модели.
public function author()
{
return $this->belongsTo('App\Author')->withDefault([
'name' => 'Guest Author'
]);
}
11. Пользовательская сортировка свойств
Предположим, у вас есть код ниже:
(устанавливает дополнительный атрибут «full_name» при возврате объекта. См. Атрибуты модели подсказки5: метка времени, добавление и т. д.)
function getFullNameAttribute()
{
return $this->attributes['first_name'] . ' ' . $this->attributes['last_name'];
}
Если вы хотите следоватьfull_name
Сортировать? Следующий код не будет работать:
$clients = Client::orderBy('full_name')->get(); //不行滴
Конечно, решение тоже очень простое. Нам нужно отсортировать их после того, как мы получим результаты.
$clients = Client::get()->sortBy('full_name'); //稳了
Обратите внимание, что имена двух методов не совпадают — нет.orderBy
ноsortBy
.
(Одним из них является оператор SQL. Пользовательский атрибут — это поле, которого нет в базе данных. Конечно, его нельзя использовать напрямую. Однако возврат запроса — это объект Collection. Laravel предоставляет множество удобных методов работы с коллекцией. .sortBy является одним из них.Конечно, вы также можете использовать фильтр.и другие операции над множествами)
12. Порядок по умолчанию в глобальной области
Что, если вы хотите, чтобы User::all() всегда сортировал по полю имени? Вы можете назначить глобальную область запроса. Вернемся к уже упомянутому выше методу boot().
protected static function boot()
{
parent::boot();
// 默认按照name 字段升序
static::addGlobalScope('order', function (Builder $builder) {
$builder->orderBy('name', 'asc');
});
}
здесьИ еще о области действия запроса.
13. Методы нативных запросов
Иногда нам нужно добавить собственные операторы запросов к операторам Eloquent. К счастью, он предоставляет такой функционал.
// 原生 where 语句
$orders = DB::table('orders')
->whereRaw('price > IF(state = "TX", ?, 100)', [200])
->get();
// 原生 having 语句
Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();
// 原生 orderBy 语句
User::where('created_at', '>', '2016-01-01')
->orderByRaw('(updated_at - created_at) desc')
->get();
(По сути, Eloquent — это инкапсуляция объектов запросов к БД, поэтому исходные методы запросов, которые можно использовать в БД, можно использовать для объектов модели, унаследованных от Eloquent.)
14. Копировать: получить копию строки данных
Очень простой, не требующий особых пояснений. Это лучший способ создать копии записей базы данных.
$task = Tasks::find(1);
$newTask = $task->replicate();
$newTask->save();
15. Метод Chunk() для больших таблиц и больших коллекций
Не совсем связанный с Eloquent, это скорее метод, предоставляемый классом Collection, но все же очень мощный — для работы с большими наборами данных вы можете разбить их на части.
Не делайте этого:
$users = User::all();
foreach ($users as $user) {
// ...
Вместо этого:
User::chunk(100, function ($users) {
foreach ($users as $user) {
// ...
}
});
Подобно разделению данных, уменьшите занятость и улучшите производительность
16. Создайте несколько дополнительных шаблонов при создании модели
Мы все знаем эту ремесленную команду:
php artisan make:model Company
Но знаете ли вы, что у него также есть три полезных флага параметров для создания других файлов, связанных с этой моделью?
php artisan make:model Company -mcr
- -m создаст файл миграции для модели
- -c создаст контроллер
- -r будет использовать этот контроллер, он должен быть контроллером ресурсов (находчивый)
17. Переопределите поле update_at при сохранении
Знаете ли вы, что метод -> save() может принимать параметры? Таким образом, мы можем сказать ему «игнорировать» функцию updated_at, которая по умолчанию заполняет текущую метку времени. См. этот пример:
$product = Product::find($id);
$product->updated_at = '2019-01-01 10:00:00';
$product->save(['timestamps' => false]);
Здесь мы динамически переписалиupdate_at
полей, а не предопределенных в модели.
Laravel по умолчанию настроит временные метки для всех классов сущностей.Если они вам не нужны, вы обычно указываете их в модели.
$timestamps = false
18. Какое значение возвращает метод update()?
Вы когда-нибудь задумывались, какой результат возвращает приведенный ниже код?
$result = $products->whereNull('category_id')->update(['category_id' => 2]);
Я имею в виду, что оператор обновления выполняется правильно в базе данных, но что будет содержать переменная $result?
Ответ — затронутая строка. Поэтому, если вам нужно проверить количество затронутых строк, вам не нужно вызывать какой-либо другой метод — метод update() вернет вам это число.
19. Правильно переводите круглые скобки в операторах SQL в запросы Eloquent.
Предположим, вы включаете такие ключевые слова, как и/или, в свой SQL-запрос следующим образом:
... WHERE (gender = 'Male' and age >= 18) or (gender = 'Female' and age >= 65)
Как перевести в Eloquent запрос? Это неправильный путь:
$q->where('gender', 'Male');
$q->orWhere('age', '>=', 18);
$q->where('gender', 'Female');
$q->orWhere('age', '>=', 65);
Этот порядок проблематичен. Правильный способ немного сложнее и требует использования замыкающей функции в качестве подзапроса:
$q->where(function ($query) {
$query->where('gender', 'Male')
->where('age', '>=', 18);
})->orWhere(function($query) {
$query->where('gender', 'Female')
->where('age', '>=', 65);
})
Метод 20 в возрасте, используя больше параметров
Наконец, вы можете передать массив методу orWhere.
Обычное использование:
$q->where('a', 1);
$q->orWhere('b', 2);
$q->orWhere('c', 3);
Вы также можете выполнить ту же функцию с помощью следующего оператора:
$q->where('a', 1);
$q->orWhere(['b' => 2, 'c' => 3]);