Cómo agregar nuevos tipos de datos a las migraciones de Laravel
Contenido
¿Alguna vez has intentado agregar un tipo longBinary en las migraciones de Laravel?
Hace unos días lo intente, así que agregue esto a una migración:
return new class extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('print_labels', function (Blueprint $table) { //... 👇🏼 $table->longBinary('label_pdf')->nullable(); }); } //... };
Sobra decir que me lleve una sorpresa cuando ejecute el comando php artisan migrate.
Ya que la migración exploto con un error:
BadMethodCallException
Method Illuminate\Database\Schema\Blueprint::longBinary does not exist.
El error es una excepción que nos avisa que el método longBinary no existe en la clase Blueprint de Laravel,
Así que ahora la pregunta es…
¿Cómo hacemos para agregar este método y que todo funcione?
Resulta que hacerlo es muy sencillo, pero antes vamos a analizar un poco que sucede en la clase Blueprint.
Clase Blueprint
La clase Illuminate\Database\Schema\Blueprint tiene un método binary:
/** * Create a new binary column on the table. * * @param string $column * @return \Illuminate\Database\Schema\ColumnDefinition */ public function binary($column) { return $this->addColumn('binary', $column); }
Si observas este método llama a otro que se llama al método addColumn que recibe dos parámetros; el primero es el tipo de dato que vamos a querer usar, en este caso binary(BLOB en MySQL) y el segundo parámetro es el nombre que va a tener la columna en la tabla de la base de datos.
Posiblemente, te preguntes como hacer para agregar nuestro método longBinary
Afortunadamente, Laravel cuenta con un mecanismo llamado Macros que nos permite extender las clases de Laravel sin tener que usar herencia. De esta forma podemos agregar nuestro método sin meternos en problemas.
Las macros se pueden agregar en la clase AppServiceProvider de Laravel, en el método boot como sigue.
class AppServiceProvider extends ServiceProvider { //... /** * Bootstrap any application services. * * @return void */ public function boot() { Blueprint::macro('longBinary', function($column){ return $this->addColumn('longBinary', $column); }); } }
El método macro recibe dos parámetros, el primero es el nombre del método que vamos a crear en la clase y el segundo es una función anónima que recibe el nombre que queremos que tenga la columna en la base de datos, dentro de la función retornamos la llamada al método addColumn, pero ahora con el tipo longBInary(LONGBLOB en Mysql), que es el tipo de dato que quiero usar.
Con todo esto listo, ejecute las migraciones de nuevo y…
¿Qué crees?
Todo exploto nuevamente, ahora con un nuevo error:
BadMethodCallException
Method Illuminate\Database\Schema\Grammars\MySqlGrammar::typeLongBinary does not exist.
Resulta que Laravel se queja, diciendo que no existe el método typeLongBinary en la clase MySqlGrammar. Esta clase se encarga entre otras cosas de “mapear” los tipos de datos que se usan en la clase Blueprint con uno equivalente en Mysql, por ejemplo el tipo binary es el tipo BLOB.
Clase MySqlGrammar
Si revisamos la clase, podemos encontrar que existe un método typeBinary.
/** * Create the column definition for a binary type. * * @param \Illuminate\Support\Fluent $column * @return string */ protected function typeBinary(Fluent $column) { return 'blob'; }
Este método dice que para crear un tipo de dato, tienes que crear un método cuyo nombre comienza con la palabra type seguido del nombre que queremos darle a nuestro tipo de dato (longBinary), además el método recibe un objeto Fluent que representa a la columna que se creó en la clase Blueprint.
Con esto en mente vamos a cambiar la clase AppServiceProvider para extender la clase MySqlGrammar con un macro.
class AppServiceProvider extends ServiceProvider { //... /** * Bootstrap any application services. * * @return void */ public function boot() { Blueprint::macro('longBinary', function($column){ return $this->addColumn('longBinary', $column); }); // 👇🏼 MySqlGrammar::macro('typeLongBinary',function(Fluent $column){ return 'longblob'; //👈🏼 tipo equivalente en Mysql }); } }
Con esto listo, ahora es posible ejecutar las migraciones sin ningún problema:

Conclusión
Extender el Schema de Laravel para que soporte “columnas” personalizadas es muy sencillo, gracias al uso de Macros. Pero un punto importante a revisar y que no incluí aquí, es el caso donde tienes que cambiar el tipo de dato a una columna existente.
¡Espero que te sea útil ese post y si tienes alguna sugerencia déjame tu comentario! 👇🏼👇🏼