How to migrate tables in order in Laravel? [duplicate] - php

Is there a way how I can change the migrations order without remaking them all? Because now I have a problem with my foreign keys -_- (working with laravel)

Roll back all the migrations (or start with a fresh database);
Change the dates that form the first part of the migration filenames so they're in the order you want (eg. for 2014_06_24_134109_update_database.php, the date & time is 2014-06-24, 13:41:09);
Run the migrations again.
With respect to your comment about foreign keys... I'm not sure that the problem is with Laravel. More likely, it's just MySQL.
I avoid foreign keys because once you get a moderately complicated set of relations, you start to run into problems with database consistency like you're seeing - it's hard for the server to figure out what order to create the tables & relationships in, and it starts to cause difficulties with things like dump files (for backups).

You have to create a custom command that executes
php artisan migrate:refresh --path=/database/migrations/name_migration.php repeately with the migrations's name in the order you want.
Like this:
Create Command class with: php artisan make:command NameClass
Go to app/Console/Commands/ and find the class file NameClass.php
In the NameClass.php you have two attributes $signature (the name of the command) and $description (Information about what your command does).
Set the name and the description of your command.Ex: protected $signature='namecommand'; protected $descripton = 'This method migrate tables in order'
Inside the NameClass.php you have a method called handle(), here you have to declare the code you want to be executed when you write the command.
Register your command. Go to app/Console/Kernel.php and add your class to the list of Command Classes.
protected $commands = [
Commands\NameClass::class,
];
Write the command in the terminal. php artisan namecommand
Example:
php artisan make:command MigrateInOrder
app/Console/Commands/MigrateInOrder.php
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class MigrateInOrder extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'migrate_in_order';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Execute the migrations in the order specified in the file app/Console/Comands/MigrateInOrder.php \n Drop all the table in db before execute the command.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
/** Specify the names of the migrations files in the order you want to
* loaded
* $migrations =[
* 'xxxx_xx_xx_000000_create_nameTable_table.php',
* ];
*/
$migrations = [
'2020_04_18_005024_create_users_types.php',
'2014_10_12_000000_create_users_table.php',
'2014_10_12_100000_create_password_resets_table.php',
'2019_08_19_000000_create_failed_jobs_table.php'
];
foreach($migrations as $migration)
{
$basePath = 'database/migrations/';
$migrationName = trim($migration);
$path = $basePath.$migrationName;
$this->call('migrate:refresh', [
'--path' => $path ,
]);
}
}
}
Go to app/Console/Kernel.php and register your command
protected $commands = [
Commands\MigrateInOrder::class,
];
Excute the command
php artisan migrate_in_order

Taking inspiration from PhpMyAdmin, I put all foreign keys definitions in a specific far future file, eg : 2999_12_31_235959_foreign_key.php
<?php
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ForeignKeys extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
// Post_tag
Schema::table(Post::NOM, function (Blueprint $table) {
$table->foreign('id_post')
->references('id_post')
->on(Post::NOM);
$table->foreign('id_tag')
->references('id_tag')
->on(Tag::NOM);
});
}
}
The only con I see is not having foreign keys definition in migration.
For the pros :
Keeping database relations
Do not care of table creation order

The best and easiest thing would be to just rename the migration yyyy_mm_dd_hhmmss_migration_name. If your migration follows this sequence, Laravel will ensure to run the migration is sorted form of date,

Building on the answer of Galeokerdo which suggests creating a separate migration file for the foreign keys, and putting the date in the far future, I tried it and it worked great. But then I started thinking of the rollback. It turned out that Laravel takes the reverse order when rolling back migrations. That is, the latest file is rolled back first.
Since the rollback will not work with the foreign key constraints in place, I tried putting my foreign-key-removal code in the "down" method of the separate foreign key migration, having found out that the file will execute first before all other migration files. Like thus:
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('tablename', function (Blueprint $table) {
$table->dropForeign('tablename_foreignkey_foreign');
});
}
"tablename_foreignkey_foreign" is the name of the foreign key constraint. By default, it is
"nameofthetable_foreignkeycolumn_foreign"
I just wanted to share this in case anybody is struggling with it the way I did.

You only need to change migrations order. if bands or stage tables are below users table, MySQL don't find the references. =)

Related

Automated Laravel Migration unable to complete

I've a SAAS application where tenant separation is per database. When a new customer signs up,account is provisioned by series of automated custom Laravel commands (Using Task Scheduler/Cron Job). One of them is tenant database migration. On the process of updating the app I added new migrations to create an additional table and add and drop some columns from other tables. When the migration for new tenant is executed, only the old migrations are run. Migration will complete only when I run the command manually(Without cron job) on localhost or production. No errors to hint as to why the migration is not being completed. Am I missing something? Below is the code snippet for the command.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Account;
use App\Traits\SwitchToAccountsManager;
use App\Traits\SwitchToTenantDatabase;
use DB;
class MigrateNewTenant extends Command
{
use SwitchToAccountsManager,SwitchToTenantDatabase;
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'migrate:new';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Runs migration on all new tenants databases';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->SwitchToAccounts();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
$tenants=Account::where('db_created','Yes')->where('tables_created','No')->get();
$bar = $this->output->createProgressBar(count($tenants));
foreach ($tenants as $tenant) {
if(!empty($tenant->db_name)){
$account_id=$tenant->account_id;
//Set tenant database connection
$this->SwitchToTenantDB($tenant->db_name);
//Run migration
$this->info("Running migration for: ".$tenant->db_name);
$this->call('migrate',["--force" => true]);
//Switch back to tenants manager
$this->SwitchToAccounts();
//Mark tables as created/migrated
DB::table('accounts')
->where('account_id', $account_id)
->update(['tables_created' => 'Yes']);
}else{
$this->info("Skipping migration for: ".$tenant->name);
}
$bar->advance();
}
$bar->finish();
}
}
Due to incomplete migration customers are encountering errors. I've to re-run migrations manually.
I discovered the cron job was executing php artisan chedule:run command on staging application not production.

Laravel - refactor table names (migration) will Models/Controllers go with it?

I would like to rename a table in the database from topics to galleries and I have created a migration that will rename my table.
Schema::rename('foo', 'bar');
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RenameTopicsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
//
Schema::rename('topics', 'galleries');
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
//
Schema::rename('galleries', 'topics');
}
}
However will the Topic Model and Topic Controller be automatically renamed? Or will I have to refactor my code? Does Laravel provide a way to do this easily?
In short my question is - How do you change your schema easily in laravel? (models/controllers/database/requests/transformers ect..)
To answer this question. Laravel does not provide a out-of-the-box way to rename your tables at the same time as your Models/Controllers.
You must manually refactor your code after you change your database schema.
An example of this is lets say i have a posts table and i want to rename it to blogs. Well my posts model and posts controller wont be helpful after i update the schema so i will need to change those over as well. Routes will need to be updated. If I am using views those will need to be updated. In my case i was using transformers and requests so those need to be manually updated.
If you can, try to avoid changing your schema :D

Importing Mysql statements into Laravel

I'm new to using Laravel.
I have a .sql file where created a whole bunch of tables("CREATE TABLE my_table......."). Is there a way to somehow import these statements into Laravel? I could always manually rewrite these tables in raw php, but I feel that this would take too long and there is possibly an easier way to do it.
You would use migrations in Laravel to do this for example
I want to create a table called tasks I would use this command in artisan
php artisan make:model Task
This would create a model called task and a migration for this table.
You can then access the migration file and input something like this
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTasksTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->increments('task_id');
$table->string('name');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('tasks');
}
}
You would then run the artisan command to create this table
php artisan migrate
This then automatically creates your table.
Its a very useful feature and you can also rollback your migrations or even refesh it meaning it will remove the table and then reinstate it with no data in.
php artisan migrate:refresh
link to the docs
http://laravel.com/docs/5.1/migrations

Data migration from old table into new table, with Laravel 4

Is it possible to copy data from old table into new table instead of rename? We are planning a major database schema upgrade and would like to preserve current data tables, so the migration down() can be as simple as dropping newly created tables.
we realize this breaks backward compatibility as migrate:rollback doesn't really rollback any new data into previous state; but enabling such thing will be very costly due to the scale of schema update, we are content with a simple 1-way migration, as long as it preserves old tables.
Can this be done within Laravel's migration and schema alone?
Thanks to suggestion from #TonyArra and #Fractaliste, we now do something like following, this allow us to test run migration and rollback without worrying about data lost.
use Illuminate\Database\Migrations\Migration;
use MyNewModel;
class DataConvert extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
foreach(MyOldModel::all() as $item)
{
MyNewModel::create(array(...));
}
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
MyNewModel::truncate();
}
}
As far as I know, there's no copy function in Laravel to do this, but it's fairly easy with models. For example, if you wanted to move data from the table users to newusers, you could add the following to the NewusersTableSeeder run function:
$users = User::all()->toArray();
foreach ($users as $user) {
$user['newField'] = "data";
Newuser::create($user);
}
(recommend that this be done in the seeder, as you should already have Eloquent::unguard(); in DatabaseSeeder.php)
Into the down() function and just before dropping your tables, I think you can perform an export of your data.
The basic use of migration is to create/drop tables. But nothing prevents you to make a more complex one. And the artisan tool provides access to any Laravel's functionality (except network one's like Input or Cookies I think)
Not sure it helps but i wrote a small class that helps copying data between two databases with totally different structure according to rules you provide on a xml file, see https://github.com/Binternet/redb
So maybe you can fire this up when you finish the last migration

Doctrine Migrations: altering a column to be nullable in production

I'm fairly new to Doctrine Migrations so apologies if this is really obvious.
Updated to provide more information
I have a Symfony2 entity mapping as below:
/**
* #ORM\Column(type="string")
*/
private $name;
This was added to a migration and deployed with everything working as it should. The column then needed to be updated to accept null values so it was changed to:
/**
* #ORM\Column(type="string", nullable=true)
*/
private $name;
The problem is that this has no impact on the resulting migration file:
$ php app/console cache:clear
$ php app/console doctrine:migrations:diff
$ tail -50 app/DoctrineMigrations/Version20131028205742.php
<?php
namespace Application\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20131028205742 extends AbstractMigration
{
public function up(Schema $schema)
{
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql", "Migration can only be executed safely on 'mysql'.");
}
public function down(Schema $schema)
{
// this down() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() != "mysql", "Migration can only be executed safely on 'mysql'.");
}
}
No ALTER statements have been added to handle null values. I could drop and rebuild the database but as this specific migration has already been deployed this will result in problems in the production database. I can see this situation occurring again in the future so would like to understand it a bit more.
Is this a limitation of Doctrine and/or the Symfony2 Doctrine Migrations bundle? Is there a way to get around this without writing a custom migration?
Please note, all my other migrations are working fine, the only issue is adding nullable options to existing fields.
Doctrine's diff works in that way it compares your entities metadata with existing database schema. So if you run doctrine:schema:update after you've ran the migration - doctrine doesn't notice any change because db schema is already changed (and therefore fits to entites metadata). And basically after you run the migration you don't need to run update anymore.

Categories