Oct 16, 2024
0
Level 1
Extend Grammars and add new function
in laravel i need to extend the postgresql grammar to add a functionality, to create a conditional unique index
in debugging I was only able to reach the uniqueSoftDelete milestone, it does not enter the extended function compileUniqueSoftDelete
PostgresGrammar extended
<?php
namespace App\Database\Schema\Grammars;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\Grammars\PostgresGrammar as BasePostgresGrammar;
use Illuminate\Support\Fluent;
class PostgresGrammar extends BasePostgresGrammar
{
/**
* Compile a unique key command.
*
* @param Blueprint $blueprint
* @param Fluent $command
* @return string
*/
public function compileUniqueSoftDelete(Blueprint $blueprint, Fluent $command): string
{
// Extrai as colunas e o nome do índice
$columns = $this->columnize($command->columns);
$indexName = $this->wrap($command->indexName);
// Retorna o SQL que cria o índice único condicional
return "CREATE UNIQUE INDEX {$indexName} ON {$this->wrapTable($blueprint)} ({$columns}) WHERE deleted_at IS NULL";
}
}
Provider
<?php
namespace App\Providers;
use App\Database\Schema\Grammars\PostgresGrammar;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Schema\PostgresBuilder;
use Illuminate\Support\ServiceProvider;
class PostgresSchemaGrammarServiceProvider extends ServiceProvider
{
public function register(): void
{
// Define a macro uniqueSoftDelete no Blueprint
Blueprint::macro('uniqueSoftDelete', function ($columns, $name = null) {
// Garante que as colunas sejam um array
if (is_string($columns)) {
$columns = [$columns];
}
// Cria o nome do índice se não foi passado
$indexName = empty($name) ? $this->createIndexName('unique_soft_delete', $columns) : $name;
// Adiciona o comando ao fluxo de migration
return $this->addCommand('uniqueSoftDelete', compact('indexName', 'columns'));
});
}
public function boot(): void
{
// Substitui o Grammar padrão pelo customizado
// Use a resolução do schema para substituir o grammar da conexão com PostgreSQL
$this->app->resolving('db.schema', function ($connection) {
if ($connection instanceof PostgresBuilder) {
// Substitua o grammar da conexão por nosso customizado
$connection->getConnection()->setSchemaGrammar(new PostgresGrammar());
}
});
}
}
Migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('folha.testes', function (Blueprint $table) {
$table->id();
$table->foreignId('tenant_id')->unsigned()->nullable(false)->comment('Empresa')->constrained('geral.tenants')->onUpdate('cascade')->onDelete('restrict');
$table->string('cpf')->nullable(false)->comment('CPF');
//$table->unique(['cpf']);
$table->uniqueSoftDelete(['cpf'])->comment('CPF Único');
$table->softDeletes()->comment('Excluído Logicamente');
$table->timestamp('created_at')->useCurrent()->comment('Criado');
$table->timestamp('updated_at')->useCurrent()->comment('Alterado');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('geral.testes');
}
};
Please or to participate in this conversation.