Объектно-ориентированное программирование (ООП) является одним из столпов любого языка программирования и одним из самых больших его преимуществ является наследование, а мы можем это использовать для реализации кастомного Blueprint.
Для начала давайте разберем, что такое Blueprint?
Класс Blueprint
В реальных задачах мы часто используем миграции. Когда мы создаем какую-либо миграцию, то в папке миграций автоматически создается файл, имеющий два метода: up
и down
. Они содержат логику в соответствии с требованиями конкретной миграции.
Чтобы определить новую таблицу и добавить в неё столбцы, мы можем использовать экземпляр Blueprint
. Вот как он используется в миграции:
public function up() { Schema::create('roles', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('name'); $table->timestamps(); }); }
Проблема
Давайте рассмотрим пример системы управления сотрудниками. У каждого сотрудника (системный администратор, менеджер по персоналу или менеджер проекта) будут разные доступы к разным модулям в системе. Смотрите на рисунки ниже.
Как правило, сотрудник отдела кадров обрабатывает заявления на отпуск, а проект-менеджер отвечает за выставление счетов в рамках проекта. Теперь, чтобы отслеживать изменения, у нас должны быть в каждой модели следующие поля: created_at
, created_by
, updated_at
, updated_by
, deleted_at
и deleted_by
.
Проблема 1. Метод Timestamps()
предоставляет поля created_at
и updated_at
, а метод SoftDeletes()
предоставляет поле deleted_at
. Нам нужно еще в каждую модель вручную добавить поля created_by
, updated_by
и deleted_by
.
Проблема 2. В случае неблагоприятных обстоятельствах, когда нужно изменить название какого-либо поля, то это будет утомительной задачей, ведь придется сделать это в каждой модели.
Решение
Чтобы решить обе проблемы, мы должны переместить все эти поля в одно место. Это делается путем создания нового класса CustomBlueprint
.
namespace App\common; use Illuminate\Database\Schema\Blueprint; class CustomBlueprint extends Blueprint { public function commonFields() { $this->timestamp('created_at')->nullable();; $this->unsignedBigInteger('created_by')->nullable(); $this->timestamp('updated_at')->nullable();; $this->unsignedBigInteger('updated_by')->nullable(); $this->timestamp('deleted_at')->nullable();; $this->unsignedBigInteger('deleted_by')->nullable(); $this->boolean('is_deleted')->default(0); } }
Так как мы расширяем дефолтный класс Blueprint
, то по умолчанию мы можем использовать все его поля и методы, такие как string
, char
, decimal
, timestamps()
и т.д. Теперь, наш первый шаг — создать метод commonFields()
, и объявить все общие поля, необходимые для моделей, в нем. Настало время изменить файл миграции.
public function up() { $schema = DB::connection()->getSchemaBuilder(); }
Нам нужен экземпляр Schema Builder для соединения, и это делается с помощью метода getSchemaBuilder()
в методе up
.
$schema->blueprintResolver(function ($table, $callback) { return new CustomBlueprint($table, $callback); });
BlueprintResolver
используется для установки преобразователя. Возвращая наш новый объект CustomBlueprint
, мы можем изменить дефолтное поведение объекта Blueprint
.
$schema->create('roles', function (CustomBlueprint $table) { $table->bigIncrements('id'); $table->string('name')->unique(); $table->commonFields(); });
Теперь мы можем использовать объект класса CustomBlueprint
для добавления столбцов вместо дефолтного класса Blueprint
. Благодаря методу commonFields()
модель «role
» получит created_at
, updated_by
и все другие поля, определенные в нём. После запуска этой мы сможем увидеть следующую структуру.
Окончательный файл миграции выглядит так:
use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; use App\Common\CustomBlueprint; class CreateRolesTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { $schema = DB::connection()->getSchemaBuilder(); $schema->blueprintResolver(function ($table, $callback) { return new CustomBlueprint($table, $callback); }); $schema->create('roles', function (CustomBlueprint $table) { $table->bigIncrements('id'); $table->string('name')->unique(); $table->commonFields(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('roles'); } }
Если мы будем следовать этой процедуре для каждой модели, то эти поля автоматически добавятся и в них.
Автор: Harsh Shah
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.