Недавно я проводил рефакторинг одного из своих проектов и обнаружил, что постоянно применяю одни и те же методы в eloquent-моделях для построения их отношений с классом Account
. К сведению, я предпочитаю использовать геттеры и сеттеры, а не магию.
Допустим, у нас есть модель Post
, которая выглядит примерно так:
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
.
Если мы захотим добавить еще одну модель, которая также имеет отношения с Account
, то нам нужно будет добавить те же самые методы. Это займет время, и если вы когда-нибудь захотите изменить эти методы, то вам придется проделать это во всех моделях, имеющих эти отношения.
Использование Traits
Начнём с определения из документации php.net:
Трейт — это механизм обеспечения повторного использования кода в языках с поддержкой только одиночного наследования, таких как PHP. Трейт предназначен для уменьшения некоторых ограничений одиночного наследования, позволяя разработчику повторно использовать наборы методов свободно, в нескольких независимых классах и реализованных с использованием разных архитектур построения классов. Семантика комбинации трейтов и классов определена таким образом, чтобы снизить уровень сложности, а также избежать типичных проблем, связанных с множественным наследованием и смешиванием (mixins).
Трейт очень похож на класс, но предназначен для группирования функционала хорошо структурированым и последовательным образом. Невозможно создать самостоятельный экземпляр трейта. Это дополнение к обычному наследованию и позволяет сделать горизонтальную композицию поведения, то есть применение членов класса без необходимости наследования.
Это идеальная причина для использования трейтов. Мы создадим трейт под названием HasAccountTrait
, который будет содержать все методы для отношения с Account
:
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
и использовать этот трейт. Выглядеть это будет примерно так:
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; } }
Вывод
Использование трейтов подразумевает, что мы создаем DRY код (Don’t repeat yourself — не повторяйся) при создании отношений к одному и тому же источнику. Это может ускорить разработку, в зависимости от того, сколько отношений используется в вашем приложении.
Автор: Tom Ellis
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.