有没有办法使用 Laravel 5 Migrations 创建一个 citext 字段?

Posted

技术标签:

【中文标题】有没有办法使用 Laravel 5 Migrations 创建一个 citext 字段?【英文标题】:Is there a way to create a citext field using Laravel 5 Migrations? 【发布时间】:2015-07-27 16:10:45 【问题描述】:

具体来说,由于 mysql 没有该字段类型,因此原始数据库查询似乎是个坏主意。由于 pgsql 默认缺少不区分大小写的文本字段,我们不得不使用这个扩展(当然,它工作得很好),但现在面临迁移的两难境地。

【问题讨论】:

【参考方案1】:

更新

我创建了一个实现此功能的包。它为迁移添加了一个passthru() 方法,以便您可以创建任何您想要的字段类型。在本例中,安装包并添加服务提供者后,您只需在迁移文件中执行$table->passthru('citext', 'name');。这个包叫做“laravel-nomad”,可以在github和packagist找到。


是的,这是可以做到的。它需要扩展一些核心文件,但它是可行的。具体来说,您将需要一个新的连接、架构语法和蓝图。

首先,在您的app 目录下创建一个新目录来保存您的自定义文件。例如,app/Extension。放置在此目录中的文件将扩展核心 Illuminate 文件,因此您将在此新目录下复制 Illuminate 文件夹结构。

蓝图

要添加可用于迁移的新方法,您需要更新蓝图。您将创建一个扩展核心蓝图类的自定义蓝图类。此自定义蓝图类将包含新方法(例如 ciText())。

app/Extension/Database/Schema/PostgresCustomBlueprint.php

<?php namespace App\Extension\Database\Schema;

use Illuminate\Database\Schema\Blueprint;

class PostgresCustomBlueprint extends Blueprint 

    /**
     * Create a new case-insensitive text column on the table.
     *
     * @param  string  $column
     * @return \Illuminate\Support\Fluent
     */
    public function ciText($column)
    
        return $this->addColumn('ciText', $column);
    
    

架构语法

随着蓝图更新以允许ciText() 方法,您需要更新架构语法以能够处理ciText 字段。您将创建一个扩展核心 PostgresGrammar 模式语法类的自定义模式语法类。此自定义模式语法将具有将 Blueprint ciText 列转换为 citext 字段的方法。

app/Extension/Database/Schema/Grammars/PostgresCustomGrammar.php

<?php namespace App\Extension\Database\Schema\Grammars;

use Illuminate\Database\Schema\Grammars\PostgresGrammar;
use Illuminate\Support\Fluent;

class PostgresCustomGrammar extends PostgresGrammar 

    /**
     * Create the column definition for a citext type.
     *
     * @param  \Illuminate\Support\Fluent  $column
     * @return string
     */
    protected function typeCiText(Fluent $column)
    
        return 'citext';
    


连接

既然您有一个自定义蓝图和一个自定义架构语法,将允许使用 citext 字段,您需要创建一个自定义连接来使用这些新的自定义类。此自定义 Connection 类将扩展核心 PostgresConnection 类,以覆盖使用自定义模式语法和自定义蓝图所需的方法。

app/Extension/Database/PostgresCustomConnection.php

<?php namespace App\Extension\Database;

use Illuminate\Database\PostgresConnection;
use App\Extension\Database\Schema\Grammars\PostgresCustomGrammar as SchemaGrammar;
use App\Extension\Database\Schema\PostgresCustomBlueprint;

class PostgresCustomConnection extends PostgresConnection 

    /**
     * Get the default schema grammar instance.
     *
     * @return \App\Extension\Database\Schema\Grammars\PostgresCustomGrammar
     */
    protected function getDefaultSchemaGrammar()
    
        return $this->withTablePrefix(new SchemaGrammar);
    

    /**
     * Get a schema builder instance for the connection.
     *
     * @return \Illuminate\Database\Schema\Builder
     */
    public function getSchemaBuilder()
    
        $parentBuilder = parent::getSchemaBuilder();

        // add a blueprint resolver closure that returns the custom blueprint
        $parentBuilder->blueprintResolver(function($table, $callback) 
            return new PostgresCustomBlueprint($table, $callback);
        );

        return $parentBuilder;
    


服务提供者

现在自定义连接已经设置好了,你需要告诉 Laravel 使用它。您可以覆盖内置的pgsql 驱动程序以使用PostgresCustomConnection 类,也可以为新连接创建一个新的驱动程序名称(例如pgsql-custom)。

如果您只想覆盖内置的pgsql 驱动程序,则需要将以下行添加到您的app/Providers/AppServiceProvider.php 文件中的register() 方法中:

$this->app->bind('db.connection.pgsql', 'App\Extension\Database\PostgresCustomConnection');

如果您想创建一个新的驱动程序名称(例如pgsql-custom),您需要在register() 文件中的register() 方法中添加以下两行:

$this->app->bind('db.connector.pgsql-custom', 'Illuminate\Database\Connectors\PostgresConnector');
$this->app->bind('db.connection.pgsql-custom', 'App\Extension\Database\PostgresCustomConnection');

数据库配置

如果您创建一个新的驱动程序名称,请确保更新您的 config/database.php 文件,以将连接上的 driver 键的值设置为 pgsql-custom(或您为驱动程序命名的任何名称)。

工匠

最后,运行 artisan 命令以确保可以找到所有类并更新 app/Providers/AppServiceProvider 的任何缓存(编译)版本:

composer dump-autoload
php artisan clear-compiled
php artisan optimize

迁移

现在您可以在迁移中使用ciText() 方法,它将创建一个citext 字段。

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration 

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    
        Schema::create('users', function(Blueprint $table)
        
            $table->engine = 'InnoDB';

            $table->increments('id');
            $table->timestamps();
            $table->ciText('name');
            $table->ciText('email')->unique();
            $table->string('password', 60);
            $table->rememberToken();
        );
    

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::drop('users');
    

【讨论】:

嗯,我当然希望它会更容易,但我会接受的。谢谢! @CJThompson 我不知道您的编辑为什么被拒绝,但我修复了 dump-autoload 命令。感谢您了解这一点。 @CJThompson 我创建了一个包来执行此操作,并将信息添加到答案中。我确信您当前的项目正在进行中,但如果需要,我希望这对未来的项目有所帮助。 @EugenDimboiu 很高兴这对您有用。我现在实际上已经创建了一个包来处理这个问题,并将相关信息添加到答案中。我希望它可以帮助。 只是想提一下,一年半之后,我们现在正在使用您的 passthru 包。再次感谢,完美运行

以上是关于有没有办法使用 Laravel 5 Migrations 创建一个 citext 字段?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用 Laravel 5 Migrations 创建一个 citext 字段?

如何正确删除 Laravel 5.3 中用户表列中的“唯一”列属性?

有没有办法在 Laravel 5 验证规则中为输入名称取别名?

有没有办法检查 laravel 5.2 中的几个输入是不是唯一?

有没有办法在 Laravel 5.8 中测试 Eloquent Observers?

[PHP] 再续 Laravel 5.5 接口 跨域问题 终极暴力解决办法