Using migrations to delete table with foreign key - laravel

I am trying to roll back my migrations.
My migrations file uses foreign keys like so:
$table->foreign('user_one')->references('id')->on('users');
$table->foreign('user_two')->references('id')->on('users');
My down() function is like so:
public function down()
{
Schema::drop('pm_convo');
Schema::drop('pm_convo_replys');
}
When I run my migrate command:
php artisan migrate:refresh --seed --env=local
I am getting the following error:
SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails (SQL: drop table `pm_convo`)
I am not exactly sure what to do to fix this.
I have tried: $table->dropForeign('pm_convo_user_one_foreign');, but I am getting errors with that as well.

I think this is a better way to do it:
public function down()
{
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
Schema::dropIfExists('tableName');
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}

pm_convo_replys has a foreign key that references pm_convo, thus you cannot delete pm_convo first without violating a foreign key constraint in pm_convo_replys.
To delete both you need to delete pm_convo_replys first.
public function down()
{
Schema::drop('pm_convo_replys');
Schema::drop('pm_convo');
}

I also faced these kind of issues. Migration file order is the main issue here. The best way is to create migration files one by one. Main entities should be created first. Migration should be refreshed with every migrate file creation. (with php artisan migrate:refresh)
According to #abkrim and #Eric
public function down()
{
Schema::disableForeignKeyConstraints();
Schema::drop('tableName');
Schema::enableForeignKeyConstraints();
}
Or safer:
protected function dropColumn($table, $column) {
try {
Schema::disableForeignKeyConstraints();
Schema::table($table, function (Blueprint $tbl) use ($column) {
$tbl->dropColumn($column);
});
} catch (Illuminate\Database\QueryException $e)
{
Schema::table($table, function (Blueprint $tbl) use ($column) {
$tbl->dropConstrainedForeignId($column);
});
} finally {
Schema::enableForeignKeyConstraints();
}
}
public function down() {
$this->dropColumn('users', 'foreign_column');
}

I think this is the most correct approach:
public function down()
{
Schema::table('[table]', function (Blueprint $table) {
$table->dropForeign('[table]_[column]_foreign');
$table->dropColumn('[column]');
});
}

prefer to do it this way
Schema::dropIfExists('tableNameChild');
Schema::drop('tableNameParents');

Important, this is for Laravel 5.4.
According to the docs
To drop a foreign key, you may use the dropForeign method. Foreign key constraints use the same naming convention as indexes. So, we will concatenate the table name and the columns in the constraint then suffix the name with "_foreign"
$table->dropForeign('posts_user_id_foreign');
Or, you may pass an array value which will automatically use the conventional constraint name when dropping:
$table->dropForeign(['user_id']);
I personally prefer the second one because of simplicity

You can do that thing very easily if you added cascade on the foeign key when creating the table. If you did it, then you can remove the table very easily without something like this for PostgreSQL.
DB::statement("drop table if exists tableName cascade");
All you have to do is to put the statement for SQL table in the raw format.

Related

Cannot drop foreign key during Laravel's migration refresh

When I try to run php artisan migrate:refresh --seed on my tables, it always get stuck on this one:
public function down()
{
if (Schema::hasTable('leads')) {
Schema::table('leads', function (Blueprint $table) {
$table->dropForeign('leads_dealer_id_foreign'); //this is the line
$table->dropIndex('leads_dealer_id_index');
$table->dropColumn('dealer_id');
Schema::dropIfExists('leads');
});
}
}
The error is: Base table or view not found: 1146 Table 'leads' doesn't exist (SQL: alter table leads drop foreign key leads_dealer_id_foreign)
I've commented the line that produces the error in the snippet above.
Why would it complain about the table not existing? Even if the table doesn't exist, I've wrapped everything inside Schema::hasTable('leads') so it shouldn't even execute that line.
What causes my leads table to drop early? I've looked at my other migrations and nowhere I'm dropping that table except on its own migration file.
Thanks
You must drop the foreign keys first, then drop the table. In order to do this move Schema::dropIfExists('leads'); outside the closure:
public function down()
{
if (Schema::hasTable('leads')) {
Schema::table('leads', function (Blueprint $table) {
$table->dropForeign('leads_dealer_id_foreign'); //this is the line
$table->dropIndex('leads_dealer_id_index');
$table->dropColumn('dealer_id');
});
Schema::dropIfExists('leads');
}
}

Laravel eloquent model not able to find foreign key

Here's the relevant models.
App\CourseItem => https://pastebin.com/PbYJAan1
App\CourseItemEvent => https://pastebin.com/RV6FBiac
If you look at App\CourseItem
I must define the foreign key
public function courseitemevent()
{
return $this->hasOne(CourseItemEvent::class, 'courseitem_id');
}
It is ignoring all the tablenames i am defining
Even thought ^ works fine i thought it would be cool to find out why
Please check out this migration structure.this is how you make a foreign key.
//this is just an example for foreign key.user_id of the user_permission table is referencing the user table id.
public function up()
{
Schema::create('user_permissions', function (Blueprint $table) {
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}

General error: 1824 Failed to open the referenced table

I am trying to set foreign key of my 'books' table with 'categories' table using php artisan migrate, but I got the following error:
Illuminate\Database\QueryException
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'categories' (SQL: alter table `books` add constraint `books_category_id_foreign` foreign key (`category_id`) references `categories` (`id`))
books migration file:
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories');
$table->string("image");
$table->string("title");
$table->string("description")->nullable();
$table->string("author");
$table->string("cover");
$table->integer("nod")->nullable();// Number of downloads
$table->integer("rating")->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('books');
}
categories migration file:
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string("title");
$table->string("image");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
I really need help with this to use in my mobile app API. I hope someone can help me.
The problem is on the migration itself. Have a look carefully at this
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'categories' (SQL: alter table `books` add constraint `books_category_id_foreign` foreign key (`category_id`) references `categories` (`id`))
You are trying to open the categories table but it basically wasn't there or wasn't created yet. If you use GUI like HeidiSQL or Navicat, or PMA, You will be able to see it.
Laravel migration takes the timestamp on the beginning of the file to decide which migration should be migrated first in sequence.
Make sure you create the categories table first before the books table (this also applies for any tables that has reference). Or simply just rename the file (change the timestamp) like E.g:
2020_01_01_1234_create_books_table.php
2020_01_01_5678_create_categories_table.php
to this
2020_01_01_1234_create_categories_table.php
2020_01_01_5678_create_books_table.php
Then run php artisan migrate:fresh to refresh your migration.
I faced the same issue with you since yesterday and I later saw my mistakes, I was able to understand the cause of the problem.
There are so many factors to consider
Make sure the date for the parent table (categories) is earlier than the date for the child table (books) so that during the migration, the parent table will be created first because the child table might want to reference id in a table that does not exist.
Make sure to follow the convention for naming
you can refactor your migration file like this
$table->foreignId('category_id')->constrained('categories');
or
$table->foreignId('category_id')->constrained();
example of one of my migration files
public function up()
{
Schema::create('project_details', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->id();
$table->foreignId('project_id')->constrained()->onDelete('cascade');
$table->string('name', 150)->nullable();
$table->string('description', 600)->nullable();
$table->string('location', 150)->nullable();
$table->integer('completed_percent')->nullable()->default(0);
$table->foreignId('manager_id')->constrained('staffs');
$table->foreignId('sponsor_id')->constrained('sponsors')->nullable();
$table->foreignId('donor_id')->constrained('sponsors')->nullable();
$table->foreignId('mda_id')->constrained('sponsors')->nullable();
});
}
You try get category for book before you create category table and book table cant understand what you referenced for.
Solution #1
Declare your category table before book table, just rename date in migration file name. Category table must be created before book table.
Solution #2
Create reference after you create category table.
Remove
$table->foreign('category_id')->references('id')->on('categories');
from book migration and create references after you up category table.
categories migration file:
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string("title");
$table->string("image");
$table->timestamps();
});
Schema::table('books', function (Blueprint $table) {
$table->foreign('category_id')->references('id')->on('categories');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
Main idea is make all relations when all tables created.
Also, use php artisan migrate:fresh for fast wipe and recreate tables
I had the same error just right now.
It has something related to creating those migrations.
The problem I had because I refactored the table name manually and didn't take care of the connection between the tables and instantly tried to migrate them.
The solution I did and worked for me is I deleted the migrations manually and created them again using php make:magirate.
In my opinion you need to change the engine of the SQL to InnoDB, this issue was struggling with me for a lot of time all you need to do is adding
<?php
$table->engine = 'InnoDB';
?>
to the table migration file
reference :
https://web-brackets.com/discussion/4/-solved-sqlstate-hy000-general-error-1824-failed-to-open-the-referenced-table-alter-on-foreign-key-
The table (Categories) you are referencing its "id" is either not created or its created after the "books" table. You can manually delete both tables and create them again with "Categories" been first or you can manually change the date of the "Categories" to a date before the "books" and you are good to go.
Make sure you have such a table in your database. If you use a lot of database, then you need to specify the database for constrained
$connection_db = DB::connection('connection_name')->getDatabaseName();
$table->foreign('category_id')->references('id')->on("$connection_db.categories");
Make sure both the tables are created using the same engine. In my case, I created two tables with two different engines (MyISAM and InnoDB). Changing both the table engines to InnoDB did the trick.

Laravel Migration to change table name

I want to change my two table name in the Laravel, so do I have to manually change the table name or it can be possible through migration.
from the docs laravel.com/docs/5.1/migrations#renaming-and-dropping-tables
To change a table name, you can do this:
Schema::rename($currentTableName, $newTableName);
You can use the drop or dropIfExists methods to remove an existing table:
Schema::drop('users');
Schema::dropIfExists('users');
Just add that to a migration and it should work.
You can rename table like that
Schema::rename('old_table', 'new_table');
BUT be careful if you have foreign keys, indexes and unique-s.
you will not be able to deleted them after renaming, like thiat
Schema::table('new_table', function (Blueprint $table) {
$table->dropForeign(['transaction_id']);
});
because they will have old names and these names have table name in them.
Thus, I recommend deleting foreign keys and other stuff first
Schema::table('old_table', function (Blueprint $table) {
$table->dropForeign(['transaction_id']);
});
Schema::rename('old_table', 'new_table');
Schema::table('new_table', function (Blueprint $table) {
$table->foreign('transaction_id')->references('id')->on('transactions');
});
Firstly, use CLI command to create a migration:
php artisan make:migration rename_table
Now, in the up method of the new migration class, use the rename method to change table name:
Schema::rename('old_table_name', 'new_table_name');
Next, execute the migration command:
php artisan migrate
To rename an existing database table, use the rename method:
Schema::rename($from, $to);
To drop an existing table, you may use the drop or dropIfExists methods:
Schema::drop('users');
Schema::dropIfExists('users');
Firstly, run this in your terminal to create a migration file to rename a table:
php artisan make:migration rename_old_name_to_new_name_table
Then in the up method, you should have this:
public function up()
{
Schema::rename('old_table_name', 'new_table_name');
}
Then in the down method, you should have this in case you want to revert previous changes made:
public function down()
{
Schema::rename('new_table_name', 'old_table_name');
}

How is a pivot table created by Laravel?

In Laravel 4, when working with many-to-many relationships as described in the 4.2 docs, how can I actually get Laravel to create the pivot table for me?
Do I need to add something in my migrations for the two models that are involved? Do I need to manually create a migration for the pivot table? Or how does Laravel know to create the pivot table?
All I've done so far is add the belongsToMany information to the two respective models, i.e.
class User extends Eloquent
{
public function roles()
{
return $this->belongsToMany('Role');
}
}
However, that does not trigger creation of the pivot table. What step am I missing?
It appears as though the pivot table does need to be created manually (i.e. Laravel does not do this automatically). Here's how to do it:
1.) Create a new migration, using singular table names in alphabetical order (default):
php artisan make:migration create_alpha_beta_table --create --table=alpha_beta
2.) Inside the newly created migration, change the up function to:
public function up()
{
Schema::create('alpha_beta', function(Blueprint $table)
{
$table->increments('id');
$table->integer('alpha_id');
$table->integer('beta_id');
});
}
3.) Add the foreign key constraints, if desired.
(I haven't gotten to that bit, yet).
Now to seed, say, the alpha table, using keys from beta, you can do the following in your AlphaTableSeeder:
public function run()
{
DB::table('alpha')->delete();
Alpha::create( array(
'all' => 'all',
'your' => 'your',
'stuff' => 'stuff',
) )->beta()->attach( $idOfYourBeta );
}
I use Jeffrey Way's Laravel-4-Generators or Laravel-5-Generators-Extended.
then you can just use this artisan command:
php artisan generate:pivot table_one table_two
To expand on Ben's answer (I tried to edit it but reviewers said it added too much):
To add the foreign key constraints, make sure if alpha id is unsigned, alpha_id is also unsigned in the pivot table. This migration would run after (2) in Ben's answer since it alters the table created then.
public function up()
{
Schema::table('alpha_beta', function(Blueprint $table)
{
$table->foreign('alpha_id')->references('id')->on('alpha');
$table->foreign('beta_id')->references('id')->on('beta');
});
}
For Many to Many relationships you can create the Migration file of the Database manually like this:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateAccountTagTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('account_tag', function (Blueprint $table) {
// $table->timestamps(); // not required
// $table->softDeletes(); // not required
$table->integer('account_id')->unsigned();
$table->foreign('account_id')->references('id')->on('accounts');
$table->integer('tag_id')->unsigned()->nullable();
$table->foreign('tag_id')->references('id')->on('tags');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('account_tag');
}
}
Note: in case you have timestamps on the pivot table you must set withTimestamps on the relationship of both ends like this:
return $this->belongsToMany(\Mega\Modules\Account\Models\Tag::class)->withTimestamps();
.
return $this->belongsToMany(\Mega\Modules\Account\Models\Account::class)->withTimestamps();
Create new migration:
php artisan make:migration create_alpha_beta_table --create=alpha_beta
Inside the newly created migration:
public function up() {
Schema::create('alpha_beta', function(Blueprint $table) {
$table->increments('id');
$table->unsignedBigInteger('alpha_id');
$table->unsignedBigInteger('beta_id');
// foreign keys
$table->foreign('alpha_id')->references('id')->on('alphas');
$table->foreign('beta_id')->references('id')->on('betas');
});
}
for the latest Laravel's versions:
composer require --dev laracasts/generators
php artisan make:migration:pivot table1 table2
In addition to all the above answers
There is no need to have an AI index for a pivot table. Its uniquely defined by its touple (key1,key2).
The primary key should be the composition (key1,key2). The benefits are that the touples are unique and all queries are best optimized.
So here comes a real life example:
Schema::create('bill_user', function (Blueprint $table) {
// unsigned is needed for foreign key
$table->integer('user_id')->unsigned();
$table->integer('bill_id')->unsigned();
$table->primary(['user_id', 'bill_id']);
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
$table->foreign(bill_id')
->references('id')->on('bills')
->onDelete('cascade');
});
following the latest laravel conventions, the up method should be
public function up() {
Schema::create('country_timezone', function (Blueprint $table) {
$table->foreignId('country_id')->references('id')->on('countries');
$table->foreignId('timezone_id')->references('id')->on('timezones');
});
}
the simplest but modern way of writing pivot table migration, where the Country and Timezone are models with many-to-many relationship. And id and timestamps are not necessary to include but straightforward manner
in the older version, you can use some generator or artisan to make pivots,
but in the newer version, this work is too easy.
you must only make migration to do that like the below code.
php artisan make:migration category_post --create=category_post
after run code
make migration with this params
$table->foreignId('post_id')->constrained('post');
$table->foreignId('category_id')->constrained('category');

Resources