Кодогенерация моделей и миграций в Laravel

от автора

Введение

Да, вместо того, чтобы ручками писать все эти скрипты миграций и в особенности классы моделей их лучше просто генерить в одно мгновение, а ни сидеть, копипастить туда-сюда названия полей и т.п. Называется всё это термином database reverse engineering, который, как и технология судя по всему не очень то прижился, а совершенно напрасно. Под reverse engineering’ом обычно понимается генерация моделей/сущностей на основе таблиц БД. Но для Laravel есть ещё и кодогенераторы миграций.

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

Инструменты

Для своих проектов на Laravel я использую следующие инструменты:

  1. kitloong/laravel-migrations-generator для генерации миграций

  2. reliese/laravel для генерации моделей

Не потому что они лучшие или худшие, просто они делают то, что мне нужно, но возможно есть и другие. Рассмотрим оба подробнее.

kitloong/laravel-migrations-generator

Основное назначение инструмента — это нагенерить миграций по уже существующей БД. Если у вас нет таблиц в БД, по которым нет миграций, то соответственно инструмент вам и не нужен. А нужен он может быть, например, когда:

  1. Вы разрабатываете новый проект и создаёте таблицы непосредственно в БД при помощи DDL-запросов а-ля CREATE TABLE… И в какой-то момент обнаруживаете, что у вас уже там N таблиц и писать под них миграции как-то уже совсем не хочется.

  2. Вы опять разрабатываете новый проект, почти такой, как тот. Вот действительно на днях была задача просто скопипастить часть микросервиса в другой микросервис. Т.к. таблицы эволюционируют то получается, что в коде копируемого проекта просто нет миграции, описывающей какую-либо таблицу в её нынешнем состоянии, а есть миграция с CREATE TABLE… и куча миграций с ALTER’ами. В таком случае проще перетащить таблицы в виде DDL-запросов в новую БД и опять же нагенерить по ним миграций.

  3. Ваш вариант…

Инструмент работает прямо из коробки, никакой дополнительной конфигурации не требуется.

Устанавливаете:

composer require --dev kitloong/laravel-migrations-generator

Запускаете согласно документации:

php artisan migrate:generate

И обнаруживаете в папке database/migrations маленький презент. Всё.

reliese/laravel

Этот инструмент про классический database reverse engineering — генерацию сущностей БД, которыми в Laravel являются классы-модели. И в Laravel есть инструмент, который генерит модели, но он генерит пустышки, которые вам предстоит заполнить вручную. Это не по-пацански, нужно генерить готовый код, пачками.

Устновка:

composer require --dev reliese/laravel

После установки пакета нужно затащить в проект его конфиг:

php artisan vendor:publish --tag=reliese-models

После этого в папке config обнаружится файл models.php. Это конфиг пакета. Далее рекомендуется почистить кэш:

php artisan config:clear

И если я не ошибаюсь, после этого можно запускать генератор так:

php artisan code:models

После этого он перезатрёт вам все ваши уже имеющиеся на данный момент модели. Ха-ха-ха. Конечно, если таковые были. И это будет происходить каждый раз, когда вы будете запускать кодогенерацию. Выглядит как несусветная тупость. И эту проблему можно легко обойти, если в конфиге указать true для опции base_files. Тогда на каждую таблицу будет генериться по два файла:

  1. Обычный класс модели в app/Models. Например для таблицы users БД будет создан класс app/Models/User.php. Если такой файл уже есть, то кодогенератор его не перезатрёт. Таким образом решается проблема описанная выше.

  2. Родительский класс app/Models/Base/User.php класса app/Models/User.php. Вы будете писать свой код в app/Models/User.php, а кодогенератор будет писать в app/Models/Base/User.php. Таким образом вы никогда не перетрёте изменения друг друга.

Можно фильтровать таблицы т.е. генерировать модели не для всех. Можно даже указать другую папку, куда будут писаться новые классы. Т. о. инструмент можно внедрить в уже существующий проект и забыть про ручное написание моделей. Поменялось что-то в БД — перегенерили модели за 0.5 секунды и едем дальше.

Ещё одна интересная опция — with_property_constants. Если указано true, то в классы будут добавлены одноимённые колонкам таблицы константы, вот пример:

<?php  /**  * Created by Reliese Model.  */  namespace App\Models\Base;  use Carbon\Carbon; use Illuminate\Database\Eloquent\Model;  /**  * Class ContactMessage  *  * @property int $id  * @property string|null $name  * @property string $email  * @property string $message  * @property int|null $ip_address  * @property Carbon|null $created_at  *  * @package App\Models\Base  */ class ContactMessage extends Model {     const ID = 'id';     const NAME = 'name';     const EMAIL = 'email';     const MESSAGE = 'message';     const IP_ADDRESS = 'ip_address';     const CREATED_AT = 'created_at';     protected $table = 'contact_messages';     public $timestamps = false;     public static $snakeAttributes = false;      protected $columns = [         'id',         'name',         'email',         'message',         'ip_address',         'created_at'     ];      protected $casts = [         self::ID => 'int',         self::IP_ADDRESS => 'int',         self::CREATED_AT => 'datetime'     ];      protected $fillable = [         self::NAME,         self::EMAIL,         self::MESSAGE,         self::IP_ADDRESS     ]; }

Вот с 26 по 31 строки они. А вот так, к слову, выглядит «ваш» свежеиспечённый класс, куда вы будете писать свой код:

<?php  namespace App\Models;  use App\Models\Base\ContactMessage as BaseContactMessage;  class ContactMessage extends BaseContactMessage { }

Вы можете спросить, зачем нужны эти константы? Для чистоты кода, чтобы ссылаться на константы классов, не плодить магические числа, типа:

$array['name'] = $data['name'];

С константами будет ясен контекст, про какой/чей name идёт речь. И здесь следует упомянуть ещё такой PHP’ый инструмент как PHP Magic Number Detector (PHPMND) — это собственно детектор магических чисел. По дефолту он ищет только именно числа, вот пример работы:

Но если запустить его с опцией --strings, то детектор будет искать не только свободно плавающие по коду числа, но и строки (узнаёте код своего проекта?):

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

P.S. Тут мне вспомнилось, что есть ещё другая фича c кодогенерацией в ORM — это генерация таблиц по уже существующим классам моделей. Не помню где видел такое, но кажется и никогда не пользовался. Знаете ли вы что-нибудь об этом? Напишите в комментариях, если вдруг.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Пользуетесь ли вы генераторами кода для ORM?

0% Первый раз слышу0
28.57% Слышал, но не пробовал2
14.29% Пробовал, но не пользуюсь1
57.14% Пользуюсь при возможности4
0% Это всё от лукавого, предпочитаю писать руками на бересте0

Проголосовали 7 пользователей. Воздержавшихся нет.

ссылка на оригинал статьи https://habr.com/ru/articles/861584/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *