...

20 трика за Laravel Eloquent (част 1)

под повърхноста на Eloquent ORM
преди 7 месеца

Eloquent ORM изглежда порост механизъм, но под повърхноста има доста полу-скрити и не-толкова познати фунцкии. Тук ще разгледаме някои от тях.

1. Инкрементиране и декреминиране

вместо традиционният метод:

$post = Post::find($post_id);
$post->read_count++;
$post->save();

Може да използвате:

$post = Post::find($post_id);
$post->increment('read_count');

// или още по-съкратено

Post::find($post_id)->increment('read_count');

// увеличаване с повече от 1

Post::find($post_id)->increment('read_count', 10); // +10

// намаляваване

Post::find($post_id)->decrement('read_count'); // -1

2. XorY методи

Eloquent има няколко бързи функции за комбиниране на два метдоа от типа “please do X, otherwise do Y”.

findOrFail():

вместо

$user = User::find($id);
if (!$user) { abort (404); }

може да ползвате

$user = User::findOrFail($id);
firstOrCreate():

вместо

$user = User::where('email', $email)->first();
if (!$user) {
  User::create([
    'email' => $email
  ]);
}

може да ползвате

$user = User::firstOrCreate(['email' => $email]);

3. Model boot() method

Има вълшебно място, където може да извикате boot() метод в Eloquent модел, където да презапишете действието по подразбиране

class User extends Model
{
    public static function boot()
    {
        parent::boot();
        static::updating(function($model)
        {
            // do some logging            // override some property like $model->something = transform($something);
        });
    }
}

Един от най-популярните примери в случая е генерирането на UUID поле при създаване на модел


public static function boot()
{
  parent::boot();
  self::creating(function ($model) {
    $model->uuid = (string)Uuid::generate();
  });
}

4 Връзки с условия и подреждане

Обикновенно създаваме връзки към модели така

public function users() {
    return $this->hasMany('App\User');    
}

но спокойно може да добавим и условия и подреждане още при дефинирането на връзките:

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']; // which fields can be filled with User::create()
    protected $dates = ['created_at', 'deleted_at']; // which fields will be Carbon-ized
    protected $appends = ['field1', 'field2']; // additional values returned in JSON
    protected $primaryKey = 'uuid'; // it doesn't have to be "id"
    public $incrementing = false; // and it doesn't even have to be auto-incrementing!
    protected $perPage = 25; // Yes, you can override pagination count PER MODEL (default 15)
    const CREATED_AT = 'created_at';
    const UPDATED_AT = 'updated_at'; // Yes, even those names can be overridden
    public $timestamps = false; // or even not used at all

за пълен списък може да проверите в самият код на Ларавел : https://github.com/laravel/framework/blob/7.x/src/Illuminate/Database/Eloquent/Model.php

6 Метода find

Метода find може да си езползва и за намиране на повече от един запис:

$users = User::find([1,2,3]);

7 WhereX

Елегантен начин да превърнем тази заявка:

$users = User::where('approved', 1)->get();

в:

$users = User::whereApproved(1)->get(); 

Може да добавите името на всяко поле към where и така да съкратите кода си. Има и някой предефинирани метода в 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 Подреждане при relations

Има възможност за подреждане при дефиниране или използване на връзки. Примерно ако искате да покажете последните постове на потребител - връзката в модела би била:

public function latestPost()
{
    return $this->hasOne(\App\Post::class)->latest();
}

и после в контролера може да използвате така:

$users = Topic::with('latestPost')->get()->sortByDesc('latestPost.created_at');

9. Eloquent::when() – без повече if-else’s

Често при писане на заявки ползваме нещо подобно:

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 Default Models

Да кажем, че имаме връзка от сорта на post->author, в blade го показваме така

{ { $post->author->name } }

за да се предпазим в случай, че автор липсва в blade ползваме

{ { $post->author->name ?? ' ' } }

Но проблема може да се реши още на ниво дефиниране на връзка, задавайки стойности по подразбиране:

public function author()
{
    return $this->belongsTo('App\Author')->withDefault([
        'name' => 'Guest Author'
    ]);
}