Custom datatype in Laravel schema builder
Recently I faced some problem with Laravel schema builder: it does not support mysql set
data type, which was necessary for one of my projects. After some searching for any information about it, I have found way to implement custom data types in schema builder. It a little bit ugly, but working well ;)
1. Extend 'Grammar' and 'Blueprint' classes
Put this code to the beginning of your migration file:
use Illuminate\Support\Fluent;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Grammars\MySqlGrammar;
/**
* Extended version of MySqlGrammar with
* support of 'set' data type
*/
class ExtendedMySqlGrammar extends MySqlGrammar {
/**
* Create the column definition for an 'set' type.
*
* @param \Illuminate\Support\Fluent $column
* @return string
*/
protected function typeSet(Fluent $column)
{
return "set('".implode("', '", $column->allowed)."')";
}
}
/**
* Extended version of Blueprint with
* support of 'set' data type
*/
class ExtendedBlueprint extends Blueprint {
/**
* Create a new 'set' column on the table.
*
* @param string $column
* @param array $allowed
* @return \Illuminate\Support\Fluent
*/
public function set($column, array $allowed)
{
return $this->addColumn('set', $column, compact('allowed'));
}
}
2. Replace default grammar and blueprint classes to ours
Insert this code before using Schema::create
:
// register new grammar class
DB::connection()->setSchemaGrammar(new ExtendedMySqlGrammar());
$schema = DB::connection()->getSchemaBuilder();
// replace blueprint
$schema->blueprintResolver(function($table, $callback) {
return new ExtendedBlueprint($table, $callback);
});
then replace Schema::create
to $schema->create
, like this:
$schema->create('example_table', function(ExtendedBlueprint $table)
{
$table->increments('id');
$table->text('sentence');
// text source & author
$table->string('author')->nullable();
$table->string('source')->nullable();
// technical data
$table->set('difficulty', range(1, 10)); // use new datatype
$table->boolean('enabled')->default(true);
});
Thats all, folks ;)
PS. Sorry for my English, I still studying it.
Written by Roman Nazarkin
Related protips
4 Responses
Thanks for the tip, exactly what I needed.
The only issue i have found with this method thus far is that for some reason when creating tables using this method, the created tables do not honor any prefix set (in config) for the database connection, why this is i do not know.
A workaround is to fetch the prefix and then manually prepend it while creating your tables eg:
$prefix = DB::connection()->getTablePrefix();
$schema->create($prefix.'yourtable',function(ExtendedBlueprint $table) {
...
});
Having looked into this a little more i found an enlightening post regarding this subject here: http://forumsarchive.laravel.io/viewtopic.php?pid=34937 if you follow the method outlined in that post then you no longer need to worry about things like database prefix.
As the prefix seems to break in every migration after the custom grammar is set, you can use
class ExtendedMySqlGrammar extends MySqlGrammar
{
public function __construct()
{
$this->tablePrefix = DB::getTablePrefix();
}
...
I used same logic but with postgres.