Как стать автором
Обновить

Комментарии 19

Библиотека миграций в зависимостях у которой twig?) спасибо, но лучше уж doctrine-migrations или eloquent прости хоспади

но как пет-проект и для резюме вполне пойдет, если причесать) плюсанул пост

На самом деле twig (да и вообще все зависимости кроме shasoft/pdo) там только чтобы генерировать справку по сущностям в таком виде и справку по миграциям. Это я использовал для отладки. Скорее всего я это в дальнейшем в отдельный пакет выделю или в require-dev перенесу. Но для первой версии оставил "как есть".

Кстати о shasoft/pdo. Я бы обратил внимание на классическую инъекцию через имена полей в методе insert. Плюс - если уж мы делаем поддержку множественной вставки - не стоило ли бы сделать ее одним запросом? И еще небольшое замечание: зачем-то используются именованные плейсхолдеры из имен полей. Сами имена полей мы отформатировали, но при этом это же самое имя в плейсхолдер попадает как есть. И как поведет себя этот метод, если имя поля будет такое же расфуфыренное, как имя таблицы из readme, test~table?

Ну и саму структуру класса Connection стоило бы причесать, а то сейчас в нем и соединение, и (не очень понятная) работа с таблицами, и этот примкнувший к ним insert. Я бы вынес квери билдер и работу с таблицами в отдельные классы.

Красивый HTML - это конечно хорошо, но основной функционал класса для выполнения SQL запросов тоже не стоит забывать.

Идея следующая: написать библиотеку SqlQueryBuilder которая использую мета-информацию о состоянии БД генерирует запрос, выполняет его, получается результаты и конвертирует их в значения в представлении PHP.

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

Метод insert + работа с таблицами в реальности нужен в пакете PDO только для тестирования функционала. Точно также наличие в миграциях метода insert тоже нужно только для тестов. Поэтому в итоге все эти функции уйдут в раздел классов "для тестирования".
А все высокоуровневые функции будут находится в SqlQueryBuilder. Инъекции не проверяются на уровне PDO, так как они будут проверяться на уровне Builder-а. Для этой проверки как раз и будет служить мета-информация о состоянии БД. В ней находится список всех таблиц, полей таблиц и индексов. Т.е. просто не будет возможности вставить в запрос поле, которого нет в текущем активном состоянии БД. Уровень PDO будет просто выполнять сырой запрос и всё. На этом его функция и заканчивается. При этом так как значения можно вставлять любые, то вот их то для защиты от инъекций оборачиваю в параметры.

В результате рефакторинга пакет shasoft/pdo вообще был удален. Теперь пакет версионирования в продуктивном варианте вообще без зависимостей и работает на "голом" PDO драйвере.

#[Drop]
protected ColumnString $name;

Кажется немного странным оставлять дропнутое поле в определении таблицы

Это миграции. А значит нельзя удалять то что было определено ранее. Иначе нарушится последовательность шагов.

Но это также является и моделькой на сколько я понял с поста. И мне кажется что модель не должна содержать такие данные. Но это просто мое мнение )

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

Если у вас отдельная модель для описания таблицы, то чем это проще обычных миграций?

Вы же сами пишете: раздражало что при написании миграций в Laravel сначала необходимо прописывать поля в классе модели, а затем эти же поля в миграциях.

А тут разве не то же самое получилось? Сначала правим бизнес-модель, потом модель для таблицы.

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

Мы берем вот такой класс
#[Comment('Таблица с изменениями')]
#[Migration('2011-11-11T12:00:00+03:00')]
#[Comment('Таблица для тестов изменений')]
class AllMigrations
{
    // Колонка
    #[Comment('Идентификатор')]
    protected ColumnId $id;
    // Колонка
    #[Migration('2012-12-12T12:00:00+03:00')]
    #[DefaultValue('Имя')]
    #[Migration('2013-12-14T12:00:00+03:00')]
    #[DefaultValue]
    #[Comment('Колонка с именем')]
    #[Migration('2017-12-12T12:00:00+03:00')]
    #[Name('Imj')]
    #[Migration('2018-12-12T12:00:00+03:00')]
    #[Type(ColumnBoolean::class)]
    #[Name('NAME')]
    #[Migration('2019-12-12T12:00:00+03:00')]
    #[MaxLength(2 ** 16)]
    protected ColumnString $name;
    // Колонка
    #[Migration('2015-12-12T12:00:00+03:00')]
    protected ColumnReal $rost;
    //
    #[Columns('id')]
    protected IndexPrimary $pkKey;
    // Индекс
    #[Columns('id')]
    #[Migration('2011-11-11T12:00:00+03:00')]
    #[Drop]
    #[Migration('2015-12-12T12:00:00+03:00')]
    #[Create]
    #[Columns('id', 'name')]
    #[Migration('2016-12-12T12:00:00+03:00')]
    #[Columns('id', 'rost')]
    protected IndexKey $testIdx;
}

и получаем такую картинку

и генерируем из него вот такую справочную информацию по которой всё достаточно понятно. Какая миграций за какой выполнялась и какой SQL код выполнялся.

А не проще ли в таком случае использовать доктрину? Потому что пока что выглядит как изобретение велосипеда, но только переусложнённого.

В моём случае - нет, не проще. Мне помимо миграций нужно иметь состояние БД чтобы на её основе потом свой sql-builder сделать.

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

В моём случае - нет, не проще. Мне помимо миграций нужно иметь состояние БД чтобы на её основе потом свой sql-builder сделать.

Так доктрина как раз и берёт текущие сущности/модели, делает дифф с состоянием базы и на выходе выдаёт миграцию со всеми отличиями.

Очевидно вы либо не читали пост, либо не дочитали.

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

// Получить максимальное значение колонки id
$migrations
    ->database()
    ->table(TabExample::class)
    ->column('id')
    ->value(MaxValue::class);

Или получить команду конвертации данных из БД в PHP

// Получить фукнцию конвертации значение колонки id БД=>PHP
$migrations
    ->database()
    ->table(TabExample::class)
    ->column('id')
    ->value(ConversionOutpute::class);

Т.е. это состояние содержит всю мета-информацию о БД. И эту информацию из структуры не получить. Также на основе этой мета-информации могут генерироваться рандомные данные для теста

// Сгенерировать 10 строк случайных значений
$rows = $migrations
    ->database()
    ->table(TabExample::class)
    ->seeder(10,30);

В общем много чего можно придумать. Достаточно просто ввести новую команду и обрабатывать её. На основании этой мета-информации я планирую делать свой пакет работы с БД с блэкджеком и шлюхами, само собой. :)

Интроспекция есть в любом зрелом dbal.

Не понятно зачем это всё в laravel. Там как раз используется паттерн active record, в котором не нужно описывать поля таблицы, в отличии от той же Doctrine

Это не для Laravel, это для своего проекта.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории