Is there any method to adding column in existing table without using migration. I mean executing php artisan migrate and creating migration file through program/code in Laravel rather than CLI. Thank you.
Migration files are only an easy way to create tables and other db actions, you still can use raw queries on Laravel anywhere by using DB::raw(...); check its documentation (https://laravel.com/docs/5.8/queries) to proper use it.
You may also be able to write a Schema::table(,,,) anywhere on your code, it will return some a Schema object which you can execute some method to run the code on your apo runtime, if you are using some IDE just try to explore and see what will you have by typing Schema::table(...)->
TRy this add just coloumn in your migration table
public function up()
{
Schema::table('users', function($table) {
$table->string('name');// only add this line
});
}
php artisan migrate:refresh
Related
I am using Laravel 4.2. I have the following library loaded in my composer.json
"doctrine/dbal": "2.4.*",
I created the following migration:
class RenameDeliveryNotesColumnOnOrderHeaderTable extends Migration {
public function up()
{
Schema::table('order_header', function(Blueprint $table)
{
$table->renameColumn('delivery_notes', 'packing_notes');
});
}
}
Where delivery_notes column type is text.
When I run the migration, I get the following error:
[Doctrine\DBAL\DBALException] Unknown database type enum requested,
Doctrine\DBAL\Platforms\MySqlPlatform may not support it.
Any idea why I am getting this error? How should I go about fixing this? I need to rename a column in my table. Are there any alternative way to rename the column?
DB::getDoctrineSchemaManager()
->getDatabasePlatform()
->registerDoctrineTypeMapping('enum', 'string');
This works for me on Laravel 5.1
Laravel's documentation says that:
Note: Renaming enum column types is not supported.
Here: https://github.com/laravel/framework/issues/1186
You can find some workarounds about this issue. And since you said that this column is not enum, take a look at #upngo's comment:
"...The issue is renaming ANY column on a table that has an enum."
Also I found this article that focuses on this issue and suggest an option that might help you.
http://www.paulbill.com/110/laravel-unknown-database-type-enum-requested-doctrinedbalplatformsmysqlplatform-may-not-support-it
I met this problem in Laravel version 5.1.19 (LTS). This is actual for earlier versions too.
I wanted to inform you as I resolved the issue base on previous comments.
First of all, I tried next code in my migration file:
$table->renameColumn('column_name');
But after command php artisan migrate, I got next error:
[Symfony\Component\Debug\Exception\FatalErrorException] Class
'Doctrine\DBAL\Driver\PDOMySql\Driver' not found
As you know DBAL was removed from the laravel core and we need add it to the composer.json.(For example:"require": {"doctrine/dbal": "2.5.1"}).
I set DBAL as required and tried again to do migrate command but got next error:
[Doctrine\DBAL\DBALException]
Unknown database type enum requested,
Doctrine\DBAL\Platforms\MySqlPlatform may not support it.
Then I tried next raw sql in my migration file:
For up():
DB::statement("ALTER TABLE `table_name` CHANGE `old_column_name` `new_column_name` ENUM('first value', 'second_value', ...) DEFAULT 'first_value' AFTER `some_field`");
For down():
DB::statement("ALTER TABLE `table_name` CHANGE `new_column_name` `old_column_name` ENUM('first value', 'second_value', ...) DEFAULT 'first_value' AFTER `some_field`");
and it works.
P.S. For renaming other fields in the table which contains an enum field we should
use same schema with raw sql as was written in previous comments.
You can add custom constructor to migration and explain to Doctrine that enum should be treated like string.
public function __construct(\Doctrine\DBAL\Migrations\Version $version)
{
parent::__construct($version);
$this->platform->registerDoctrineTypeMapping('enum', 'string');
}
Here is the answer for Laravel 5.2.45+ (might work in 5.1 as well, have not tested or checked yet, please let me know so I can update this question.)
Add this line in your up method:
Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
Something like this:
public function up()
{
Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
Schema::table('users', function (Blueprint $table) {
$table->text('bio')->change();
});
}
I had the same problem with Laravel 5.1 and PostGres.
So basically I used the DB::statement to create the ENUM and solve the problem:
DB::statement("CREATE TYPE e_users AS ENUM('data1','data2')");
And then:
DB::statement("ALTER TABLE users ADD COLUMN column e_users");
Though the original author had issues with Laravel 4, this can safely be fixed in Laravel 5 by bumping the version of doctrine/dbal in your composer.json to ^2.6, as it was fixed in this PR on release 2.6.0
Make sure to check for compatibility-breaking changes in the release changelog
Currently, there is no legal solution for this problem except avoiding enums, but there is a workaround:
Create migration with the following:
public function up()
{
DB::statement("ALTER TABLE `table` CHANGE `example_enum_column` `example_enum_column` ENUM('enum1', 'enum2', 'enum3+');");
}
And that will do the trick with the ENUM update you are looking for. Additionally, you can create handle down functions to revert field status as it used to be:
public function down()
{
DB::statement("ALTER TABLE `table` CHANGE `example_enum_column` `example_enum_column` ENUM('enum1', 'enum2');");
}
Background
I am trying to extend class Blueprint to make my Blueprint.Finally,I found the way .But when I made attempt to overwrite some ColumnDefinition ,some trouble stopped me.
Problem 1
Schema::create('Person',function(Blueprint $table){
$table->string('id')->comment('身份证号');
$table->string('id')->comment('学号')->change();//this line doesn't work!
});
Like the code above,the second line in that Closure doesn't work and i don't know why.
What I know is that some 'Modify Cloumn' operations need a dependency called doctrine/dbal and I have installed it.
The function change() neither reports any error nor meets expectation.It is strange.
Please help me!
Problem 2
By reading the source code of Schema,I found the relationship between Schema and Blueprint is Schema->Builder->Blueprint.Schema::create() will call $blueprint->create() before the Closure function(Blueprint $table).It seems that it is the same effect whether I define the fields in the Closure or directly put the field definitions in the $blueprint->__constructor().But,when I run migrate,the Blueprint's constructor is called more than once.If I put all of the column definitions in that Closure,everyting is fine.Strange!
And,I also noticed that $table->unique() finally becomes alter table $table add unique,why not compile command before creating like create table $table(...,unique key $keyname (k1,k2,)).
At present,I believe that Blueprint saves column definitions in a array $commands[] and finally compiles the commands into sql.If so,why not support overwrite when before table is created?
I'm trying to read data from a .sql file in a seeder to fill 3-4 tables with some data and DatabaseSeeder.php looks like this
public function run() {
$this->call([
UsersTableSeeder::class,
// Bunch of seeders using Eloquent
SqlSeeder::class
]);
}
All other seeders execute and, actually, when trying to throw an exception in SqlSeeder.php I'm able to stop the seeding. However, SqlSeeder.php won't seed the database via php artisan migrate:fresh --seed, seems like it's bypassed. I always need to run php artisan db:seed --class SqlSeeder after, in order to make it seed the database. SqlSeeder.php looks like this
public function run() {
$path = base_path().'/database/seeds/sql/data.sql';
$sql = file_get_contents($path);
DB::unprepared($sql);
}
Why's that?
I solved my own issue by removing transactions from the .sql file I was trying to execute via DB::unprepared(). Oddly enough, transactions completely fail when executing php artisan migrate:refresh --seed, but they work if I later call the SqlSeeder individually via php artisan db:seed --class SqlSeeder. There are no foreign key constraints for now and InnoDB was chosen as engine, just to be sure, but still transactions both fail and work depending on the command.
I guess it all depends on how Illuminate\Database\Seeder::call works and calls seeder classes internally, but I'm not sure.
Check if seeding data in sql file is in right order.
For example if you have foreign key category_id that references to categories.id posts table will be empty without any errors when you use this sql file:
INSERT INTO posts (title, category_id) VALUES ('test', 1);
INSERT INTO categories (title) VALUES ('category');
You should seed categories first and only then posts.
For Laravel 5 all you have to do inside of your main seed file is:
\DB::unprepared(\File::get(base_path('path/to/your/sql/file.sql')));
I want to use Laravel's migration to manage my database. But I need to have a single configuration file where I store the schema. Something like this :
{
user: {
"id":"increments",
"name":"string",
"timestamps":"timestamps()"
}
}
And when I change this file again to the text below
{
user: {
"id":"increments",
"name":"string",
"password":"string",
"timestamps":"timestamps()"
}
}
I want to be able to run a command and have the database be changed without losing any data or creating an additional config file.
Can I achieve this using laravel migrations or if you know of any other solution that can help me and I would be able to use that on laravel without losing any of laravel's database management tools, please comment.
Thank you.
php artisan make:migration add_password_to_user ( are you sure the table is called user and not users? )
In your new migration
public function up()
{
Schema::table('user', function($table) {
$table->string('password');
});
}
Don't forget the rollback
public function down()
{
Schema::table('user', function($table) {
$table->dropColumn('password');
});
}
The table should be users if you have the model User .. otherwise make sure to have protected $table = 'user'; on the model.
https://laravel.com/docs/5.3/migrations
The --table and --create options may also be used to indicate the name of the table and whether the migration will be creating a new table. These options simply pre-fill the generated migration stub file with the specified table:
php artisan make:migration create_users_table --create=users
php artisan make:migration add_votes_to_users_table --table=users
When developing i'm having so many issues with migrations in laravel.
I create a migration. When i finish creating it, there's a small error by the middle of the migration (say, a foreign key constraint) that makes "php artisan migrate" fail. He tells me where the error is, indeed, but then migrate gets to an unconsistent state, where all the modifications to the database made before the error are made, and not the next ones.
This makes that when I fix the error and re-run migrate, the first statement fails, as the column/table is already created/modified. Then the only solution I know is to go to my database and "rollback" everything by hand, which is way longer to do.
migrate:rollback tries to rollback the previous migrations, as the current was not applied succesfully.
I also tried to wrap all my code into a DB::transaction(), but it still doesn't work.
Is there any solution for this? Or i just have to keep rolling things back by hand?
edit, adding an example (not writing Schema builder code, just some kind of pseudo-code):
Migration1:
Create Table users (id, name, last_name, email)
Migration1 executed OK. Some days later we make Migration 2:
Create Table items (id, user_id references users.id)
Alter Table users make_some_error_here
Now what will happen is that migrate will call the first statement and will create the table items with his foreign key to users. Then when he tries to apply the next statement it will fail.
If we fix the make_some_error_here, we can't run migrate because the table "items" it's created. We can't rollback (nor refresh, nor reset), because we can't delete the table users since there's a foreign key constraint from the table items.
Then the only way to continue is to go to the database and delete the table items by hand, to get migrate in a consistent state.
It is not a Laravel limitation, I bet you use MYSQL, right?
As MYSQL documentation says here
Some statements cannot be rolled back. In general, these include data
definition language (DDL) statements, such as those that create or
drop databases, those that create, drop, or alter tables or stored
routines.
And we have a recommendation of Taylor Otwell himself here saying:
My best advice is to do a single operation per migration so that your
migrations stay very granular.
-- UPDATE --
Do not worry!
The best practices say:
You should never make a breaking change.
It means, in one deployment you create new tables and fields and deploy a new release that uses them. In a next deployment, you delete unused tables and fields.
Now, even if you'll get a problem in either of these deployments, don't worry if your migration failed, the working release uses the functional data structure anyway. And with the single operation per migration, you'll find a problem in no time.
I'm using MySql and I'm having this problem.
My solution depends that your down() method does exactly what you do in the up() but backwards.
This is what i go:
try{
Schema::create('table1', function (Blueprint $table) {
//...
});
Schema::create('tabla2', function (Blueprint $table) {
//...
});
}catch(PDOException $ex){
$this->down();
throw $ex;
}
So here if something fails automatically calls the down() method and throws again the exception.
Instead of using the migration between transaction() do it between this try
Like Yevgeniy Afanasyev highlighted Taylor Otwell as saying (but an approach I already took myself): have your migrations only work on specific tables or do a specific operation such as adding/removing a column or key. That way, when you get failed migrations that cause inconsistent states like this, you can just drop the table and attempt the migration again.
I’ve experienced exactly the issue you’ve described, but as of yet haven’t found a way around it.
Just remove the failed code from the migration file and generate a new migration for the failed statement. Now when it fails again the creation of the database is still intact because it lives in another migration file.
Another advantage of using this approach is, that you have more control and smaller steps while reverting the DB.
Hope that helps :D
I think the best way to do it is like shown in the documentation:
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
See: https://laravel.com/docs/5.8/database#database-transactions
I know it's an old topic, but there was activity a month ago, so here are my 2 cents.
This answer is for MySql 8 and Laravel 5.8
MySql, since MySql 8, introduced atomic DDL: https://dev.mysql.com/doc/refman/8.0/en/atomic-ddl.html
Laravel at the start of migration checks if the schema grammar supports migrations in a transaction and if it does starts it as such.
The problem is that the MySql schema grammar has it set to false. We can extend the Migrator, MySql schema grammar and MigrationServiceProvider, and register the service provider like so:
<?php
namespace App\Console;
use Illuminate\Database\Migrations\Migrator as BaseMigrator;
use App\Database\Schema\Grammars\MySqlGrammar;
class Migrator extends BaseMigrator {
protected function getSchemaGrammar( $connection ) {
if ( get_class( $connection ) === 'Illuminate\Database\MySqlConnection' ) {
$connection->setSchemaGrammar( new MySqlGrammar );
}
if ( is_null( $grammar = $connection->getSchemaGrammar() ) ) {
$connection->useDefaultSchemaGrammar();
$grammar = $connection->getSchemaGrammar();
}
return $grammar;
}
}
<?php
namespace App\Database\Schema\Grammars;
use Illuminate\Database\Schema\Grammars\MySqlGrammar as BaseMySqlGrammar;
class MySqlGrammar extends BaseMySqlGrammar {
public function __construct() {
$this->transactions = config( "database.transactions", false );
}
}
<?php
namespace App\Providers;
use Illuminate\Database\MigrationServiceProvider as BaseMigrationServiceProvider;
use App\Console\Migrator;
class MigrationServiceProvider extends BaseMigrationServiceProvider {
/**
* Register the migrator service.
* #return void
*/
protected function registerMigrator() {
$this->app->singleton( 'migrator', function( $app ) {
return new Migrator( $app[ 'migration.repository' ], $app[ 'db' ], $app[ 'files' ] );
} );
$this->app->singleton(\Illuminate\Database\Migrations\Migrator::class, function ( $app ) {
return $app[ 'migrator' ];
} );
}
<?php
return [
'providers' => [
/*
* Laravel Framework Service Providers...
*/
App\Providers\MigrationServiceProvider::class,
],
];
Of course, we have to add transactions to our database config...
DISCLAIMER - Haven't tested yet, but looking only at the code it should work as advertised :) Update to follow when I test...
Most of the answers overlook a very important fact about a very simple way to structure your development against this. If one were to make all migrations reversible and add as much of the dev testing data as possible through seeders, then when artisan migrate fails on the dev environment one can correct the error and then do
php artisan migrate:fresh --seed
Optionally coupled with a :rollback to test rolling back.
For me personally artisan migrate:fresh --seed is the second most used artisan command after artisan tinker.