[Open source, PHP, PostgreSQL, GitHub, Laravel] Расширяем возможности миграций Laravel за счет Postgres
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Все, кто однажды начинал вести более-менее нормальный Enterprise проект на Laravel, сталкивался с тем, что стандартных решений, которые предлагает Laravel из коробки, уже недостаточно.А если вы, как и я, используете в своих проектах Postgres, то рано или поздно вам потребуются плюшки этой замечательной СУБД, такие как: различного рода индексы и констрейнты, расширения, новые типы и тд...Сегодня, как вы уже заметили, мы будем говорить про Postgres, про миграции Laravel, как это все вместе подружить, в общем, обо всем том, чего нам не хватает в стандартных миграциях Лары.
Ну а для тех, кто не хочет погружаться в тонкости внутреннего устройства Laravel, может просто скачать пакет, расширяющий возможности миграций Laravel и Postgres по этой ссылке и использовать его в своих проектах. Но я все же рекомендую не пролистывать, а прочитать все до конца.МиграцииВот как выглядит стандартная миграция в Laravel:Пример обычной миграции
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateDocuments extends Migration
{
private const TABLE = 'documents';
public function up()
{
Schema::create(static::TABLE, function (Blueprint $table) {
$table->bigIncrements('id');
$table->timestamps();
$table->softDeletes();
$table->string('number');
$table->date('issued_date')->nullable();
$table->date('expiry_date')->nullable();
$table->string('file');
$table->bigInteger('author_id');
$table->bigInteger('type_id');
$table->foreign('author_id')->references('id')->on('users');
$table->foreign('type_id')->references('id')->on('document_types');
});
}
public function down()
{
Schema::dropIfExists(static::TABLE);
}
}
Но, тут вы прочитали статью на хабре про новые типы в Postgres, например, tsrange и захотели добавить в миграцию что-то вроде этого...
$table->addColumn('tsrange', 'period')->nullable();
Казалось бы, все просто, но ваш перфекционизм наводит вас на мысль, а почему бы не залезть в сорцы и не пропатчить Laravel, ведь я буду часть использовать это, хочется чтобы можно было использовать это примерно так:
$table->tsRange('period')->nullable();
Для тех, кому интересно сколько вендоровских классов нужно пропатчить, чтобы добиться этого, загляните под спойлер:Пример как пропатчить Laravel миграцииПатчим Blueprint
<?php
Blueprint::macro('tsRange', function (string $columnName) {
return $this->addColumn('tsrange', $columnName);
});
Патчим PostgresGrammar
<?php
PostgresGrammar::macro('typeTsrange', function () {
rerurn 'tsrange';
});
Далее создаем какой-нить провайдер, типа ExtendDatabaseProvider:
<?php
use Illuminate\Support\ServiceProvider;
class DatabaseServiceProvider extends ServiceProvider
{
public function register()
{
Blueprint::macro('tsRange', function (string $columnName) {
return $this->addColumn('tsrange', $columnName);
});
PostgresGrammar::macro('typeTsrange', function () {
return 'tsrange';
});
}
}
Вроде бы все, запускаем миграцию, все работает..И не важно, переопределили ли вы половину компонентов Laravel для работы с БД или воспользовались макросами и миксинами из MacroableTrait, круги ада еще не закончились.Круги ада (часть 1)И вот вы локально все это крутите, все работает как часы, написали +100500 строк кода, и решили выкатить готовую таску в гитлаб. Мы же идем в ногу со временем и там у нас Докер, CI, тесты и тд...И вот мы замечаем, что наши миграции в "не локальном" окружении не работают из-за ошибки:
Doctrine\DBAL\Driver\PDOException: SQLSTATE[08006] [7]
FATAL: sorry, too many clients already
И вот ты сидишь и думаешь, что ты не так делаешь, начинаешь подпихивать в локальный .env окружения из CI вашего GitLab, переписывать код, вместо макросов переопределять разные классы, распихивать везде и всюду дебаги, все идеально, локально ошибки нет. А в пайплайнах CI не так-то просто дебажить, начинаешь пихать везде и всюду логирование, и это не помогает, ведь ошибка где-то внутри, в vendor. Но ты об этом еще пока не знаешь. Затем, спустя целый дня гугления ошибки, решения так и нет, куча бессмысленных советов.Начинаешь ощущать по-тихоньку себя идиотом (простите за мой французский), который не способен ни на что, в прямом смысле этого слова, словно ты школьник, который только-только выпустился из школы, день убит, проблема не решена.Важен контекстОшибка sorry, too many clients already может быть совершенно по любой причине.Ты возвращаешься к началу, гуглишь то с чего начинал, с внедрения макросами в PostgresGrammar нового типа и вот чудо, ты натыкаешься на похожую проблему, но с первого взгляда она немного другая.... где кто-то, как и ты добавлял новый тип и у него не заводится БД. Но у него ошибка другая:
Doctrine\DBAL\DBALException: Unknown database type tsrange requested,
Doctrine\DBAL\Platforms\PostgreSQL100Platform may not support it.
Отчаявшись, первая мысль, а чем черт не шутит... ты пробуешь чужие решения, даже самые абсурдные и в один прекрасный день все начинает работать. Вы уже догадались в чем дело?Барабанная дробь
Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType().You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap().If this error occurs during database introspection then you might have forgotten to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.
Иными словами, нужно успеть зарегистрировать тип в Doctrine\Dbal прежде, чем до вашего Database Connection дойдет информация, что вы используете кастомные типы (под кастомными я подразумеваю те, которые есть в Postgres, но отсутствуют в заветном getTypesMap в недрах Doctrine.Круги ада (часть 2)Вы лезете в исходники, куда-то очень глубоко в vendor в недры doctrine\dbal...Спустя некоторое кол-во впустую потраченных часов, понимаете, что чтобы зарегистрировать тип в Doctrine, вам нужно переопределить с десяток классов и, помимо прочего, еще и с десяток методов.О боже, часть из них приватные!Все больше не могу, это единственные мысли и слова, которые выходят из ваших уст..Руки опускаются окончательно..Спасительный кругНе буду ходить вокруг, да около. Это, как вы уже поняли, был мой личный опыт, мои руки не опустились, все-таки я победил этот великий и ужасный Doctrine.Подумаем о будущемА что, если я не первый, что если не мне одному надо это, что если сделать публичный пакет, который бы позволял расширять возможности наших миграций любому, добавлять новые типы, чтобы это было просто, прозрачно, и чтобы не приходилось лезть в исходники Laravel и Doctrine, и чтобы он работал по принципу автоботов. Помните, как Оптимус Прайм при помощи трейлера приобретал способности летать, а другие автоботы, были для него своего рода доп. орудиями.Представим себе такой DatabaseProvider, который мы внедряем в свой проект вместо стандартного от Laravel, опишем структуру будущих Extension-ов в виде маленьких библиотек с похожей структурой, чтобы они легко коннектились к нашему провайдеру, и забыть, как страшный сон исходники Doctrine.Основные компонентыЭти объекты нам надо модифицировать, но сделать это в стиле ООП, сбоку, по типу как трейты иньектятся в классы:
- Blueprint - объект, использующийся в миграциях, по сути билдер
- Builder - он же фасад Schema
- PostgresGrammar - объект для компиляции Blueprint-а в SQL-выражения
- Types - наши типы
Давайте, придумаем объект, который будет подмешивать объекты расширений во внутренние объекты Laravel таким образом, чтобы и овцы были целы и волки сыты, имею ввиду, чтобы IDE был счастлив, все работало, а наш код был понятным.Пример класса, описывающего такое расширение
<?php
namespace Umbrellio\Postgres\Extensions;
use Illuminate\Support\Traits\Macroable;
use Umbrellio\Postgres\Extensions\Exceptions\MacroableMissedException;
use Umbrellio\Postgres\Extensions\Exceptions\MixinInvalidException;
abstract class AbstractExtension extends AbstractComponent
{
abstract public static function getMixins(): array;
abstract public static function getName(): string;
public static function getTypes(): array
{
return [];
}
final public static function register(): void
{
collect(static::getMixins())->each(static function ($extension, $mixin) {
if (!is_subclass_of($mixin, AbstractComponent::class)) {
throw new MixinInvalidException(sprintf(
'Mixed class %s is not descendant of %s.',
$mixin,
AbstractComponent::class
));
}
if (!method_exists($extension, 'mixin')) {
throw new MacroableMissedException(sprintf('Class %s doesn’t use Macroable Trait.', $extension));
}
/** @var Macroable $extension */
$extension::mixin(new $mixin());
});
}
}
Теперь, пропатчим соединение базы данных, чтобы оно умело работать с этим объектом и решало все наши проблемы, регистрировало в нужные внутренние компоненты Laravel наши дополнения, в том числе и решало проблему с регистрацией типов в Doctrine.Патчим PostgresConnection
<?php
namespace Umbrellio\Postgres;
use DateTimeInterface;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Events;
use Illuminate\Database\PostgresConnection as BasePostgresConnection;
use Illuminate\Support\Traits\Macroable;
use PDO;
use Umbrellio\Postgres\Extensions\AbstractExtension;
use Umbrellio\Postgres\Extensions\Exceptions\ExtensionInvalidException;
use Umbrellio\Postgres\Schema\Builder;
use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;
use Umbrellio\Postgres\Schema\Subscribers\SchemaAlterTableChangeColumnSubscriber;
class PostgresConnection extends BasePostgresConnection
{
use Macroable;
private static $extensions = [];
final public static function registerExtension(string $extension): void
{
if (!is_subclass_of($extension, AbstractExtension::class)) {
throw new ExtensionInvalidException(sprintf(
'Class %s must be implemented from %s',
$extension,
AbstractExtension::class
));
}
self::$extensions[$extension::getName()] = $extension;
}
public function getSchemaBuilder()
{
if ($this->schemaGrammar === null) {
$this->useDefaultSchemaGrammar();
}
return new Builder($this);
}
public function useDefaultPostProcessor(): void
{
parent::useDefaultPostProcessor();
$this->registerExtensions();
}
protected function getDefaultSchemaGrammar()
{
return $this->withTablePrefix(new PostgresGrammar());
}
private function registerExtensions(): void
{
collect(self::$extensions)->each(function ($extension) {
/** @var AbstractExtension $extension */
$extension::register();
foreach ($extension::getTypes() as $type => $typeClass) {
$this
->getSchemaBuilder()
->registerCustomDoctrineType($typeClass, $type, $type);
}
});
}
}
А также необходимо переопределить провайдер и фабрику для работы с БД:Патчим DatabaseProvider
<?php
namespace Umbrellio\Postgres;
use Illuminate\Database\DatabaseManager;
use Illuminate\Database\DatabaseServiceProvider;
use Umbrellio\Postgres\Connectors\ConnectionFactory;
class UmbrellioPostgresProvider extends DatabaseServiceProvider
{
protected function registerConnectionServices(): void
{
$this->app->singleton('db.factory', function ($app) {
return new ConnectionFactory($app);
});
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
$this->app->bind('db.connection', function ($app) {
return $app['db']->connection();
});
}
}
Патчим ConnectionFactory
<?php
namespace Umbrellio\Postgres\Connectors;
use Illuminate\Database\Connection;
use Illuminate\Database\Connectors\ConnectionFactory as ConnectionFactoryBase;
use Umbrellio\Postgres\PostgresConnection;
class ConnectionFactory extends ConnectionFactoryBase
{
protected function createConnection($driver, $connection, $database, $prefix = '', array $config = [])
{
if ($resolver = Connection::getResolver($driver)) {
return $resolver($connection, $database, $prefix, $config);
}
if ($driver === 'pgsql') {
return new PostgresConnection($connection, $database, $prefix, $config);
}
return parent::createConnection($driver, $connection, $database, $prefix, $config);
}
}
Начало работыПредставим что нам надо добавить поддержку нового типа tsrange в наши миграции. Как будет выглядеть наше расширение в нашем проекте теперь.TsRangeExtension.php
<?php
namespace App\Extensions\TsRange;
use App\Extensions\TsRange\Schema\Grammars\TsRangeSchemaGrammar;
use App\Extensions\TsRange\Schema\TsRangeBlueprint;
use App\Extensions\TsRange\Types\TsRangeType;
use Umbrellio\Postgres\Extensions\AbstractExtension;
use Umbrellio\Postgres\Schema\Blueprint;
use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar;
class TsRangeExtension extends AbstractExtension
{
public const NAME = TsRangeType::TYPE_NAME;
public static function getMixins(): array
{
return [
TsRangeBlueprint::class => Blueprint::class,
TsRangeSchemaGrammar::class => PostgresGrammar::class,
// ... список миксинов может включать в себя почти любой внутренний компонент Laravel
];
}
public static function getName(): string
{
return static::NAME;
}
public static function getTypes(): array
{
return [
static::NAME => TsRangeType::class,
];
}
}
TsRangeBlueprint.php
<?php
namespace App\Extensions\TsRange\Schema;
use Illuminate\Support\Fluent;
use App\Extensions\TsRange\Types\TsRangeType;
use Umbrellio\Postgres\Extensions\Schema\AbstractBlueprint;
class TsRangeBlueprint extends AbstractBlueprint
{
public function tsrange()
{
return function (string $column): Fluent {
return $this->addColumn(TsRangeType::TYPE_NAME, $column);
};
}
}
TsRangeSchemaGrammar.php
<?php
namespace App\Extensions\TsRange\Schema\Grammars;
use App\Extensions\TsRange\Types\TsRangeType;
use Umbrellio\Postgres\Extensions\Schema\Grammar\AbstractGrammar;
class TsRangeSchemaGrammar extends AbstractGrammar
{
protected function typeTsrange()
{
return function (): string {
return TsRangeType::TYPE_NAME;
};
}
}
TsRangeType.php
<?php
namespace App\Extensions\TsRange\Types;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;
class TsRangeType extends Type
{
public const TYPE_NAME = 'tsrange';
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string
{
return static::TYPE_NAME;
}
public function convertToPHPValue($value, AbstractPlatform $platform): ?array
{
//...
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
//...
return $value;
}
public function getName(): string
{
return self::TYPE_NAME;
}
}
Теперь необходимо зарегистрировать наше расширение TsRangeExtension в нашем провайдере для работы с БД:
<?php
namespace App\TsRange\Providers;
use Illuminate\Support\ServiceProvider;
use App\Extensions\TsRange\TsRangeExtension;
use Umbrellio\Postgres\PostgresConnection;
class TsRangeExtensionProvider extends ServiceProvider
{
public function register(): void
{
PostgresConnection::registerExtension(TsRangeExtension::class);
}
}
ИтогВы можете писать свои расширения для Postgres имплементируя AbstractExtension, на мой взгляд, очень быстро и просто, не вникая в тонкости работы Laravel и Doctrine.Это мой первый опыт, сделать что-то полезное для PHP сообщества, для тех кто использует в своих проектах Laravel / Postgres, не судите строго, пожалуйста.Но я буду рад обратной связи, в любом ее проявлении, в Issues / Pull-реквестах, или в комментах относительно не только моей публикации, но и пакета в целом приму любую критику.Пощупать данный пакет можно на GitHub: laravel-pg-extensions.Спасибо за внимание.
===========
Источник:
habr.com
===========
Похожие новости:
- [Open source, Виртуализация, Облачные вычисления, Администрирование баз данных] Изучаем Bash путем написания интерактивой игры, создаем культуру DevOps, а также шпаргалка по MariaDB и MySQL
- [Open source, Машинное обучение, Звук] Modern Portable Voice Activity Detector Released
- [Информационная безопасность, Open source, JavaScript, Node.JS] CRUD для NMAP’а: решение для мониторинга открытых портов на хостах
- [Open source, Python, Data Mining, Машинное обучение, Звук] Мы опубликовали современный Voice Activity Detector и не только
- [Настройка Linux, Информационная безопасность, Open source] Linux exploits
- [PHP, JavaScript, Программирование] OpenCart popup, модальные окна
- [Разработка веб-сайтов, PHP, Программирование] Это не легаси-код, это PHP (перевод)
- [Настройка Linux, Open source, Разработка под Linux] Разработчики Linux рассматривают отказ от поддержки старых процессоров
- [Open source, PHP, PostgreSQL, Совершенный код, GitHub] Интеграция PHP проекта на GitHub и Scrutinizer
- [Open source, PHP, GitHub] Автоматизация ручных действий с GitHub Actions
Теги для поиска: #_open_source, #_php, #_postgresql, #_github, #_laravel, #_php, #_postgres, #_postgresql, #_laravel, #_github, #_open_source, #_open_source, #_php, #_postgresql, #_github, #_laravel
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:28
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Все, кто однажды начинал вести более-менее нормальный Enterprise проект на Laravel, сталкивался с тем, что стандартных решений, которые предлагает Laravel из коробки, уже недостаточно.А если вы, как и я, используете в своих проектах Postgres, то рано или поздно вам потребуются плюшки этой замечательной СУБД, такие как: различного рода индексы и констрейнты, расширения, новые типы и тд...Сегодня, как вы уже заметили, мы будем говорить про Postgres, про миграции Laravel, как это все вместе подружить, в общем, обо всем том, чего нам не хватает в стандартных миграциях Лары. Ну а для тех, кто не хочет погружаться в тонкости внутреннего устройства Laravel, может просто скачать пакет, расширяющий возможности миграций Laravel и Postgres по этой ссылке и использовать его в своих проектах. Но я все же рекомендую не пролистывать, а прочитать все до конца.МиграцииВот как выглядит стандартная миграция в Laravel:Пример обычной миграции <?php
declare(strict_types=1); use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateDocuments extends Migration { private const TABLE = 'documents'; public function up() { Schema::create(static::TABLE, function (Blueprint $table) { $table->bigIncrements('id'); $table->timestamps(); $table->softDeletes(); $table->string('number'); $table->date('issued_date')->nullable(); $table->date('expiry_date')->nullable(); $table->string('file'); $table->bigInteger('author_id'); $table->bigInteger('type_id'); $table->foreign('author_id')->references('id')->on('users'); $table->foreign('type_id')->references('id')->on('document_types'); }); } public function down() { Schema::dropIfExists(static::TABLE); } } $table->addColumn('tsrange', 'period')->nullable();
$table->tsRange('period')->nullable();
<?php
Blueprint::macro('tsRange', function (string $columnName) { return $this->addColumn('tsrange', $columnName); }); <?php
PostgresGrammar::macro('typeTsrange', function () { rerurn 'tsrange'; }); <?php
use Illuminate\Support\ServiceProvider; class DatabaseServiceProvider extends ServiceProvider { public function register() { Blueprint::macro('tsRange', function (string $columnName) { return $this->addColumn('tsrange', $columnName); }); PostgresGrammar::macro('typeTsrange', function () { return 'tsrange'; }); } } Doctrine\DBAL\Driver\PDOException: SQLSTATE[08006] [7]
FATAL: sorry, too many clients already Doctrine\DBAL\DBALException: Unknown database type tsrange requested,
Doctrine\DBAL\Platforms\PostgreSQL100Platform may not support it. Any Doctrine type that you use has to be registered with \Doctrine\DBAL\Types\Type::addType().You can get a list of all the known types with \Doctrine\DBAL\Types\Type::getTypesMap().If this error occurs during database introspection then you might have forgotten to register all database types for a Doctrine Type. Use AbstractPlatform#registerDoctrineTypeMapping() or have your custom types implement Type#getMappedDatabaseTypes(). If the type name is empty you might have a problem with the cache or forgot some mapping information.
<?php
namespace Umbrellio\Postgres\Extensions; use Illuminate\Support\Traits\Macroable; use Umbrellio\Postgres\Extensions\Exceptions\MacroableMissedException; use Umbrellio\Postgres\Extensions\Exceptions\MixinInvalidException; abstract class AbstractExtension extends AbstractComponent { abstract public static function getMixins(): array; abstract public static function getName(): string; public static function getTypes(): array { return []; } final public static function register(): void { collect(static::getMixins())->each(static function ($extension, $mixin) { if (!is_subclass_of($mixin, AbstractComponent::class)) { throw new MixinInvalidException(sprintf( 'Mixed class %s is not descendant of %s.', $mixin, AbstractComponent::class )); } if (!method_exists($extension, 'mixin')) { throw new MacroableMissedException(sprintf('Class %s doesn’t use Macroable Trait.', $extension)); } /** @var Macroable $extension */ $extension::mixin(new $mixin()); }); } } <?php
namespace Umbrellio\Postgres; use DateTimeInterface; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Events; use Illuminate\Database\PostgresConnection as BasePostgresConnection; use Illuminate\Support\Traits\Macroable; use PDO; use Umbrellio\Postgres\Extensions\AbstractExtension; use Umbrellio\Postgres\Extensions\Exceptions\ExtensionInvalidException; use Umbrellio\Postgres\Schema\Builder; use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar; use Umbrellio\Postgres\Schema\Subscribers\SchemaAlterTableChangeColumnSubscriber; class PostgresConnection extends BasePostgresConnection { use Macroable; private static $extensions = []; final public static function registerExtension(string $extension): void { if (!is_subclass_of($extension, AbstractExtension::class)) { throw new ExtensionInvalidException(sprintf( 'Class %s must be implemented from %s', $extension, AbstractExtension::class )); } self::$extensions[$extension::getName()] = $extension; } public function getSchemaBuilder() { if ($this->schemaGrammar === null) { $this->useDefaultSchemaGrammar(); } return new Builder($this); } public function useDefaultPostProcessor(): void { parent::useDefaultPostProcessor(); $this->registerExtensions(); } protected function getDefaultSchemaGrammar() { return $this->withTablePrefix(new PostgresGrammar()); } private function registerExtensions(): void { collect(self::$extensions)->each(function ($extension) { /** @var AbstractExtension $extension */ $extension::register(); foreach ($extension::getTypes() as $type => $typeClass) { $this ->getSchemaBuilder() ->registerCustomDoctrineType($typeClass, $type, $type); } }); } } <?php
namespace Umbrellio\Postgres; use Illuminate\Database\DatabaseManager; use Illuminate\Database\DatabaseServiceProvider; use Umbrellio\Postgres\Connectors\ConnectionFactory; class UmbrellioPostgresProvider extends DatabaseServiceProvider { protected function registerConnectionServices(): void { $this->app->singleton('db.factory', function ($app) { return new ConnectionFactory($app); }); $this->app->singleton('db', function ($app) { return new DatabaseManager($app, $app['db.factory']); }); $this->app->bind('db.connection', function ($app) { return $app['db']->connection(); }); } } <?php
namespace Umbrellio\Postgres\Connectors; use Illuminate\Database\Connection; use Illuminate\Database\Connectors\ConnectionFactory as ConnectionFactoryBase; use Umbrellio\Postgres\PostgresConnection; class ConnectionFactory extends ConnectionFactoryBase { protected function createConnection($driver, $connection, $database, $prefix = '', array $config = []) { if ($resolver = Connection::getResolver($driver)) { return $resolver($connection, $database, $prefix, $config); } if ($driver === 'pgsql') { return new PostgresConnection($connection, $database, $prefix, $config); } return parent::createConnection($driver, $connection, $database, $prefix, $config); } } <?php
namespace App\Extensions\TsRange; use App\Extensions\TsRange\Schema\Grammars\TsRangeSchemaGrammar; use App\Extensions\TsRange\Schema\TsRangeBlueprint; use App\Extensions\TsRange\Types\TsRangeType; use Umbrellio\Postgres\Extensions\AbstractExtension; use Umbrellio\Postgres\Schema\Blueprint; use Umbrellio\Postgres\Schema\Grammars\PostgresGrammar; class TsRangeExtension extends AbstractExtension { public const NAME = TsRangeType::TYPE_NAME; public static function getMixins(): array { return [ TsRangeBlueprint::class => Blueprint::class, TsRangeSchemaGrammar::class => PostgresGrammar::class, // ... список миксинов может включать в себя почти любой внутренний компонент Laravel ]; } public static function getName(): string { return static::NAME; } public static function getTypes(): array { return [ static::NAME => TsRangeType::class, ]; } } <?php
namespace App\Extensions\TsRange\Schema; use Illuminate\Support\Fluent; use App\Extensions\TsRange\Types\TsRangeType; use Umbrellio\Postgres\Extensions\Schema\AbstractBlueprint; class TsRangeBlueprint extends AbstractBlueprint { public function tsrange() { return function (string $column): Fluent { return $this->addColumn(TsRangeType::TYPE_NAME, $column); }; } } <?php
namespace App\Extensions\TsRange\Schema\Grammars; use App\Extensions\TsRange\Types\TsRangeType; use Umbrellio\Postgres\Extensions\Schema\Grammar\AbstractGrammar; class TsRangeSchemaGrammar extends AbstractGrammar { protected function typeTsrange() { return function (): string { return TsRangeType::TYPE_NAME; }; } } <?php
namespace App\Extensions\TsRange\Types; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\Type; class TsRangeType extends Type { public const TYPE_NAME = 'tsrange'; public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform): string { return static::TYPE_NAME; } public function convertToPHPValue($value, AbstractPlatform $platform): ?array { //... return $value; } public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { //... return $value; } public function getName(): string { return self::TYPE_NAME; } } <?php
namespace App\TsRange\Providers; use Illuminate\Support\ServiceProvider; use App\Extensions\TsRange\TsRangeExtension; use Umbrellio\Postgres\PostgresConnection; class TsRangeExtensionProvider extends ServiceProvider { public function register(): void { PostgresConnection::registerExtension(TsRangeExtension::class); } } =========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:28
Часовой пояс: UTC + 5