Specifically, since MySQL doesn't have that field type, raw DB queries seem like a bad idea. Since pgsql lacks a case insensitive text field by default, we had to use this extension (which works perfectly, of course), but now are faced with a dilemma wrt the migration.
1 Answers
Update
I have created a package that implements this functionality. It adds a passthru()
method to the migrations, so that you can create any field type you'd like. In this example, after installing the package and adding the service provider, you'd just do $table->passthru('citext', 'name');
in the migration file. The package is called "laravel-nomad", and can be found on github and packagist.
Yes, this can be done. It requires extending a few of the core files, but it is doable. Specifically, you will need a new connection, schema grammar, and blueprint.
First, create a new directory under your app
directory to hold your custom files. For example, app/Extension
. The files placed in this directory will be extending the core Illuminate files, so you will be replicating the Illuminate folder structure under this new directory.
Blueprint
To add a new method available to the migration, you need to update the Blueprint. You will create a custom Blueprint class that extends the core Blueprint class. This custom Blueprint class will have the new method in it (e.g. 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);
}
}
Schema Grammar
With the Blueprint updated to allow the ciText()
method, you need to update the schema grammar to be able to handle the ciText
field. You will create a custom schema grammar class that extends the core PostgresGrammar schema grammar class. This custom schema grammar will have the method that converts the Blueprint ciText
column into the citext
field.
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';
}
}
Connection
Now that you have a custom Blueprint and a custom schema grammar that will allow use of the citext
field, you need to create a custom Connection that will use these new custom classes. This custom Connection class will extend the core PostgresConnection class in order to override the methods needed to use the custom schema grammar and the custom Blueprint.
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;
}
}
Service Provider
Now that the custom Connection is setup, you need to tell Laravel to use it. You can either override the built in pgsql
driver to use the PostgresCustomConnection
class, or you can create a new driver name (e.g. pgsql-custom
) for the new connection.
If you just want to override the built in pgsql
driver, you need to add the following line to the register()
method in your app/Providers/AppServiceProvider.php
file:
$this->app->bind('db.connection.pgsql', 'App\Extension\Database\PostgresCustomConnection');
If you would like to create a new driver name (e.g. pgsql-custom
), you need to add the following two lines to the register()
method in your app/Providers/AppServiceProvider.php
file:
$this->app->bind('db.connector.pgsql-custom', 'Illuminate\Database\Connectors\PostgresConnector');
$this->app->bind('db.connection.pgsql-custom', 'App\Extension\Database\PostgresCustomConnection');
Database Config
If you create a new driver name, make sure to update your config/database.php
file to set the value for the driver
key on your connection to pgsql-custom
(or whatever you named your driver).
Artisan
Finally, run the artisan commands to make sure all your classes can be found and to update any cached (compiled) version of app/Providers/AppServiceProvider
:
composer dump-autoload
php artisan clear-compiled
php artisan optimize
Migration
Now you are able to use the ciText()
method inside your migrations and it will create a citext
field.
<?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');
}
}
-
Well, I was certainly hoping it'd be easier, but I'll take it. Thanks! – CJ Thompson May 27 '15 at 02:41
-
@CJThompson I don't know why your edit was rejected, but I fixed the dump-autoload command. Thanks for catching that. – patricus May 27 '15 at 06:09
-
@CJThompson I have created a package to do this, and added the information to the answer. I'm sure your current project is well underway, but I hope this helps with future projects if needed. – patricus Jan 15 '16 at 09:44
-
@EugenDimboiu I'm glad this was useful to you. I have actually created a package to take care of this now, and have added the relevant information to the answer. I hope it can help. – patricus Jan 15 '16 at 09:45
-
Just wanted to mention that, a year and a half later, we're now using your `passthru` package. Thanks again, works perfectly – CJ Thompson Sep 27 '16 at 02:47