有没有办法使用 Laravel 5 迁移创建 citext 字段?
Is there a way to create a citext field using Laravel 5 Migrations?
具体来说,由于 MySQL 没有该字段类型,原始数据库查询似乎不是一个好主意。由于 pgsql 默认缺少不区分大小写的文本字段,我们不得不使用此扩展(当然,它工作得很好),但现在面临迁移的困境。
更新
我已经创建了一个实现此功能的包。它向迁移添加了一个 passthru()
方法,以便您可以创建您想要的任何字段类型。在此示例中,安装包并添加服务提供商后,您只需在迁移文件中执行 $table->passthru('citext', 'name');
即可。该包名为“laravel-nomad”,可在 github and packagist.
上找到
是的,这是可以做到的。它需要扩展一些核心文件,但这是可行的。具体来说,您将需要一个新的连接、架构语法和蓝图。
首先,在您的 app
目录下创建一个新目录来保存您的自定义文件。例如,app/Extension
。放置在这个目录中的文件将扩展核心 Illuminate 文件,因此您将在这个新目录下复制 Illuminate 文件夹结构。
蓝图
要添加可用于迁移的新方法,您需要更新蓝图。您将创建一个扩展核心蓝图 class 的自定义蓝图 class。此自定义蓝图 class 将包含新方法(例如 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 模式语法 class 的自定义模式语法 class。此自定义模式语法将具有将蓝图 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
字段的自定义蓝图和自定义模式语法,您需要创建一个自定义连接,以使用这些新的自定义 classes。此自定义连接 class 将扩展核心 PostgresConnection class 以覆盖使用自定义模式语法和自定义蓝图所需的方法。
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
driver 以使用 PostgresCustomConnection
class,或者您可以创建一个新的 driver 名称(例如 pgsql-custom
) 用于新连接。
如果您只想覆盖内置 pgsql
driver,您需要将以下行添加到 app/Providers/AppServiceProvider.php
文件中的 register()
方法:
$this->app->bind('db.connection.pgsql', 'App\Extension\Database\PostgresCustomConnection');
如果您想创建一个新的 driver 名称(例如 pgsql-custom
),您需要在 [=32= 中的 register()
方法中添加以下两行] 文件:
$this->app->bind('db.connector.pgsql-custom', 'Illuminate\Database\Connectors\PostgresConnector');
$this->app->bind('db.connection.pgsql-custom', 'App\Extension\Database\PostgresCustomConnection');
数据库配置
如果您创建一个新的 driver 名称,请确保更新您的 config/database.php
文件以将连接上的 driver
键的值设置为 pgsql-custom
(或者你命名你的 driver).
Artisan
最后,运行 artisan 命令确保可以找到所有 classes 并更新 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');
}
}
具体来说,由于 MySQL 没有该字段类型,原始数据库查询似乎不是一个好主意。由于 pgsql 默认缺少不区分大小写的文本字段,我们不得不使用此扩展(当然,它工作得很好),但现在面临迁移的困境。
更新
我已经创建了一个实现此功能的包。它向迁移添加了一个 passthru()
方法,以便您可以创建您想要的任何字段类型。在此示例中,安装包并添加服务提供商后,您只需在迁移文件中执行 $table->passthru('citext', 'name');
即可。该包名为“laravel-nomad”,可在 github and packagist.
是的,这是可以做到的。它需要扩展一些核心文件,但这是可行的。具体来说,您将需要一个新的连接、架构语法和蓝图。
首先,在您的 app
目录下创建一个新目录来保存您的自定义文件。例如,app/Extension
。放置在这个目录中的文件将扩展核心 Illuminate 文件,因此您将在这个新目录下复制 Illuminate 文件夹结构。
蓝图
要添加可用于迁移的新方法,您需要更新蓝图。您将创建一个扩展核心蓝图 class 的自定义蓝图 class。此自定义蓝图 class 将包含新方法(例如 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 模式语法 class 的自定义模式语法 class。此自定义模式语法将具有将蓝图 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
字段的自定义蓝图和自定义模式语法,您需要创建一个自定义连接,以使用这些新的自定义 classes。此自定义连接 class 将扩展核心 PostgresConnection class 以覆盖使用自定义模式语法和自定义蓝图所需的方法。
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
driver 以使用 PostgresCustomConnection
class,或者您可以创建一个新的 driver 名称(例如 pgsql-custom
) 用于新连接。
如果您只想覆盖内置 pgsql
driver,您需要将以下行添加到 app/Providers/AppServiceProvider.php
文件中的 register()
方法:
$this->app->bind('db.connection.pgsql', 'App\Extension\Database\PostgresCustomConnection');
如果您想创建一个新的 driver 名称(例如 pgsql-custom
),您需要在 [=32= 中的 register()
方法中添加以下两行] 文件:
$this->app->bind('db.connector.pgsql-custom', 'Illuminate\Database\Connectors\PostgresConnector');
$this->app->bind('db.connection.pgsql-custom', 'App\Extension\Database\PostgresCustomConnection');
数据库配置
如果您创建一个新的 driver 名称,请确保更新您的 config/database.php
文件以将连接上的 driver
键的值设置为 pgsql-custom
(或者你命名你的 driver).
Artisan
最后,运行 artisan 命令确保可以找到所有 classes 并更新 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');
}
}