https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
Eloquent - реализация паттерна active record в Laravel.
Главная идея Eloquent в том, что модели могут вытаскивать из таблицы сразу все поля, если правильно задать аттрибуты-массивы $visible и $hidden.
abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
use Concerns\HasAttributes, # по умолчанию $attributes; добавляемые $appends = []; привести к типу $casts = [] - integer, real, float, double, decimal:<digits>, string, boolean, object, array, collection, date, datetime, and timestamp
Concerns\HasEvents,
Concerns\HasGlobalScopes,
Concerns\HasRelationships, # functions hasOne hasMany... | loaded relationships for the model - $relations = []
Concerns\HasTimestamps,
Concerns\HidesAttributes, # attributes for serialization - $hidden = [] , $visible = []
Concerns\GuardsAttributes, # mass assignable attributes - $fillable , $guarded = ['*'];
ForwardsCalls;
Связи делаются функциями:
# прямые связи у модели App\User
return $this->hasOne('App\Profile', 'foreign_key', 'local_key'); # у пользователя один профиль
return $this->hasMany('App\Phone', 'user_id', 'id'); # у пользователя может быть много телефонов
# обратная у App\Phone
return $this->belongsTo('App\User', 'user_id'); # телефон принадлежит одному пользователю
В отличии от Doctrine и Django, которые по моделям могут создавать файлы миграции, Eloquent заставляет писать их вручную.
# многие ко многим . связующую таблицу (её называют pivot) называют по именам основных в алфавитном порядке
return $this->belongsToMany('App\Address', 'address_user', # у пользователя может быть несколько адресов проживания
'user_id', 'address_id', # по одному адресу могут жить несколько пользователей
'id', 'id')
->withPivot(['rent', 'end_date'])
->withTimestamps(); # в pivot может быть доп информация (стоимость аренды, дата выселения)
Запрос по связи в модели
# если делаем id вместо code то будет ошибка хз почему
$eloquentQueryBuilder->whereHas('details', function ($q1) {
$q1->whereHas('about', function ($q2) {
$q2->where('code', 'active');
});
});
# все дома которые сдаются от 1000 до 9999
$eloquentQueryBuilder->whereHas('adress', function ($query) {
return $query->whereBetween('adress_user.rent', [1000, 9999]);
});
public function cars()
{
return $this->belongsToMany('App\Car','car_customer','car_id','customer_id');
}
#Query to get all customers with N cars:
$userInput = 2;
$data = Customer::with('cars')
->withCount('cars')
->has('cars', '<', $userInput)
->orderBy('cars_count', 'desc')
->get();
# or
$customers = Customer::whereHas("cars", function($query) use ($input) {
$query->where(DB::raw("count(cars.id)"), "<", DB::raw($input))
})->get();
Ограничение количества элементов у связи
->with(['comments'=>function($query) {
return $query->limit(5);
}])
Миграции
$table->...->onDelete('CASCADE');
$table->...->onDelete('SET NULL');
$table->...->onDelete('RESTRICT');
Schema::table('test', function (Blueprint $table) {
$table->dropForeign( ['mytest_id']); // если массив то можно без *_foreign
});
Builder
# pre condition для каждого запроса
public function newQuery()
{
$query = parent::newQuery();
return $query->whereNotNull("avatar");
}
* hasOne / hasMany (1-1, 1-M)
-save(new or existing child)
-saveMany(array of models new or existing)
-create(array of attributes)
-createMany(array of arrays of attributes)
---------------------------------------------------------------------------
* belongsTo (M-1, 1-1)
-associate(existing model)
---------------------------------------------------------------------------
* belongsToMany (M-M)
-save(new or existing model, array of pivot data, touch parent = true)
-saveMany(array of new or existing model, array of arrays with pivot ata)
-create(attributes, array of pivot data, touch parent = true)
-createMany(array of arrays of attributes, array of arrays with pivot data)
-attach(existing model / id, array of pivot data, touch parent = true)
-sync(array of ids OR ids as keys and array of pivot data as values, detach = true)
-updateExistingPivot(relatedId, array of pivot data, touch)
---------------------------------------------------------------------------
* morphTo (polymorphic M-1)
// the same as belongsTo
---------------------------------------------------------------------------
* morphOne / morphMany (polymorphic 1-M)
// the same as hasOne / hasMany
---------------------------------------------------------------------------
* morphedToMany /morphedByMany (polymorphic M-M)
// the same as belongsToMany
Joins
https://laracasts.com/discuss/channels/eloquent/left-outer-join-using-eloquent-with-and-operator
$q = Houses::select("houses.*");
$q->join('favorites', 'houses.id', '=', 'favorites.house_id', 'left outer');
$q->join('users', 'users.id', '=', 'favorites.user_id', 'left outer');
$q->where(function ($q) {
$q->where('users.id', 1);
$q->orWhereNull('users.id');
});
$q->orderBy('status', 'ASC');
$q->orderBy('users.id', 'desc');
https://reinink.ca/articles/ordering-database-queries-by-relationship-columns-in-laravel
https://laraveldaily.com/post/order-by-belongsto-relationship-column-eloquent-vs-query-builder
$product_id = $product->id;
$ratings = Rating::select('ratings.id', 'ratings.score', 'ratings.product_id', 'ratings.user_id')
->join('users', 'users.id', '=', 'ratings.user_id')
->join('products', function($query) use($product_id) {
$query->where('products.id', $product_id)
->where('ratings.product_id', $product_id);
})
->orderBy('users.name', 'asc')
->get();
#
$eloquentQueryBuilder->select(['users.*', 'groups.name as group_name']);
$eloquentQueryBuilder->join('groups', 'users.group_id', '=', 'groups.id');
$eloquentQueryBuilder->orderBy('group_name', $sort_order);
OrderBy random field
->select(["users.*",
DB::raw("(select max(ms.created_at) from messages ms WHERE ms.sender_id = users.id and ms.viewer_id = users.id) as last_message_time")
])
->orderBy('last_message_time', 'desc')
whereRaw
$q->whereRaw("users.id in (select user_id from favorites where house_id = {$house->id})");