Используем Трейты для Laravel Eloquent связей

Допустим, у нас есть Post модель, которая выглядит примерно так:

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
/**
 * Class Post
 *
 * @package App
 */
class Post extends Model
{
    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->getAttribute('title');
    }

    /**
     * @param string $title
     * @return $this
     */
    public function setTitle(string $title)
    {
        $this->setAttribute('title', $title);

        return $this;
    }

    /**
     * @return string
     */
    public function getPost()
    {
        return $this->getAttribute('post');
    }

    /**
     * @param string $post
     * @return $this
     */
    public function setPost(string $post)
    {
        $this->setAttribute('post', $post);

        return $this;
    }

    /**
     * @param Account $account
     * @return $this
     */
    public function setAccount(Account $account)
    {
        $this->account()->associate($account);

        return $this;
    }

    /**
     * @return Account|null;
     */
    public function getAccount()
    {
        return $this->getAttribute('account');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function account()
    {
        return $this->belongsTo(Account::class, 'account_id', 'id');
    }
}

У нас есть некоторые методы, определенные для свойств Post модели, и некоторые для связи с моделью Account.

Теперь, когда мы добавим другую модель, которая имеет отношение к учетной записи, нам придется добавить те же методы. Это может занять много времени, и если вы когда-нибудь хотели изменить методы, вам придется делать это на всех моделях, которые имеют эти отношения.

Traits (Трейты)

Я начну с Php.net документации:

Traits - это механизм повторного использования кода в языках с одним наследованием, таких как PHP. Trait предназначен для уменьшения некоторых ограничений единого наследования, позволяя разработчику повторно использовать наборы методов свободно, в нескольких независимых классах, живущих в разных иерархий классов. Семантика сочетания трейтов и классов определяется таким образом, чтобы уменьшить сложность и избежать типичных проблем, связанных с множественным наследованием и примесями (mixins).

Trait похож на класс, но предназначен только для группирования функциональных возможностей в мелкозернистой и согласованным способом. Невозможно создать экземпляр трейта самостоятельно. Он является дополнением к традиционному наследованию и обеспечивает горизонтальную композицию поведения, то есть применение членов класса без наследования.

Поэтому в нашем случае мы будем использовать трейты. Мы создадим характеристику HasAccountTrait, которая будет содержать все методы для связи, принадлежащей учетной записи:

<?php

namespace App;

/**
 * Class HasAccountTrait
 *
 * @package App
 */
trait HasAccountTrait
{
    /**
     * @param Account $account
     * @return $this
     */
    public function setAccount(Account $account)
    {
        $this->account()->associate($account);

        return $this;
    }

    /**
     * @return Account|null;
     */
    public function getAccount()
    {
        return $this->getAttribute('account');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function account()
    {
        return $this->belongsTo(Account::class, 'account_id', 'id');
    }
}

Затем мы изменим нашу Post модель, чтобы использовать наш трейт, она будет выглядеть таким образом:

<?php

namespace App;
use Illuminate\Database\Eloquent\Model;
/**
 * Class Post
 *
 * @package App
 */
class Post extends Model
{
    use HasAccountTrait;
    
    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->getAttribute('title');
    }

    /**
     * @param string $title
     * @return $this
     */
    public function setTitle(string $title)
    {
        $this->setAttribute('title', $title);

        return $this;
    }

    /**
     * @return string
     */
    public function getPost()
    {
        return $this->getAttribute('post');
    }

    /**
     * @param string $post
     * @return $this
     */
    public function setPost(string $post)
    {
        $this->setAttribute('post', $post);

        return $this;
    }
}

Вывод:

Использование трейтов означает, что мы можем создать чистый код при определении связей с одним и тем же источником. Это также может ускорить разработку в зависимости от количества связей в приложении.