Soft deleting with a relationship - laravel

I have a book and author table. A author has many books. A book has one author.
I wish to soft delete an author.
So I have a deleted_at field in the authors table (do I also need this on the books table?). There is also a author_id foreign key in the books table.
I call:
Author::destroy($id);
But I get the error:
Cannot delete or update a parent row: a foreign key constraint fails
I'm using larval 4.1
Here are my migrations:
Schema::create('authors', function($table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
$table->softDeletes();
});
Schema::create('books', function($table) {
$table->increments('id');
$table->integer('author_id')->unsigned();
$table->foreign('author_id')->references('id')->on('authors');
$table->string('title'); // Varchar
$table->string('isbn'); // Varchar
});

Ever thought of cascaded deletes ?
//Suggested implementation , will this work ?
$table->foreign('author_id')->references('id')->on('authors')->onDelete('cascade');
// my current implementation
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');

Related

email as a foreign key in larave

Can I make email as a foreign key ? $table->foreignId('email')->constrained('users')->onDelete('CASCADE'); . I wrote a seeder and is for an integer value for emai. I need to make email unique
This is my users table
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
To create an Foreign Key association with email column of users table, you cannot use foreignId method as it creates unsignedBigInteger equivalent column.
You can create the foreign key association as
//Some other table - for eg lets say posts
Schema::create('posts', function(Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->string('author_email');
$table->foreign('author_email') // a column on posts table
->references('email') //name of the column on users (referenced) table
->on('users') //name of the referenced table
->onDelete('cascade'); //constrain
});
Then using this foreign key association you can define the author relation in Post model linking it to the User model
//Post.php - eloquent model class
public function author()
{
return $this->belongsTo(User::class, 'author_email', 'email');
}
Note: For this to work as expected, email column on users table must contain unique values i.e have a unique index (as you have in the migration of users table)
Laravel Docs - Migrations - Foreign Key Constraints

Issues with foreign constraints -

I tried to follow the documentation of laravel and laracasts, however I get an error in my migrations concerning foreign keys.
I have articles about games that are written by authors (users), so I want the user Id for the article.
This is my games table:
public function up()
{
Schema::create('games', function (Blueprint $table) {
$table->id('id');
$table->timestamps();
$table->string('name', 100);
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->text('description');
$table->string('publisher');
$table->string('url');
});
}
And this my user table:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
If I understand correct I name the column in the games table 'user_id', and it references to the Id of the user, which is called 'id' in the user table?
When migrating however i get the error theres no user_id.
SQLSTATE[42000]: Syntax error or access violation: 1072 Key column 'user_id' doesn't exist in table (SQL: alter table gamesadd constraintgames_user_id_foreign foreign key (user_id) references users (id) on delete cascade)
Can someone tell me what I am doing wrong? Am I mixing up where I should refer to 'id' in the user table?
Migrations by default are run with the same order that they are been created, and in your case, the games migration is been executed before the user migration, and so you when migrating the games migration, there is no user table, and so
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Will fail.
In order to solve this problem, rename the user migration with a date before the one that has the games migration
Thanks to #lagbox for having pointed it out:
This line is not creating a new field, but is just adding a constrain
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
Instead you should first create the field and then create the constrain:
$table->bigInteger('user_id)->...;
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
The way I usually do it is :
Creating the migrations files (containing all the fields)
Creating alterations files (adding FK)
Like that, when I run php artisan migrate the order of the migrations doesn't block anything.
With your code above you are trying to add a foreign constraint on a field which doesn't exist yet

Cannot delete or update a parent row: Laravel

I want to delete a record in category table wherein it will also delete the subcategory record which has a the foreign key of category. How can I do this?
Also, an explanation would help as why it has happened. Thank you!
Controller
public function destroy(Category $category)
{
// return $category;
Category::where('id', $category->id)->delete();
Subcategory::where('category_id', $category->id)->delete();
return back();
}
Category migration
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Sub-category mgiration
Schema::create('subcategories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('category_id')->unsigned();
$table->string('subcatname');
$table->string('name');
$table->timestamps();
$table->foreign('category_id')->references('id')->on('categories');
});
this is simple because of the default delete: Restrict option in foreign key.
1.Add on delete cascade option to foreign key. This option will automatically remove any associated records from the subcategoires table when you delete the category record.
The modified fk statement looks like as follows:
ADD CONSTRAINT `category_subcategory_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE;
or you can go through
Laravel also provides support for creating foreign key constraints, which are used to force referential integrity at the database level. For example, let's define a user_id column on the posts table that references the id column on a users table:
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});
You may also specify the desired action for the "on delete" and "on update" properties of the constraint:
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
You need onDelete method. Just from Docs
$table->foreign('category_id')
->references('id')->on('categories')
->onDelete('cascade');

Laravel Migration : Errcode: 150 "Foreign key constraint is incorrectly formed"

I am trying to execute this migration :
Users :
Schema::create('comments', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name');
$table->string('last_name');
$table->string('email')->unique();
$table->string('avatar_url');
$table->string('email_verified_at')->nullable();
$table->string('password')->unique();
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
});
Articles :
Schema::create('articles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('title');
$table->longText('body');
$table->enum('state', ['draft', 'published']);
$table->bigInteger('user_id')->unsigned();
$table->timestamps();
$table->softDeletes();
$table->foreign('user_id')
->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
});
But when I migrate I get the following error :
SQLSTATE[HY000]: General error: 1005 Can't create table blog_api.#sql-2b70_7b (Errcode: 150 "Foreign key constraint is inc
orrectly formed") (SQL: alter table articles add constraint articles_user_id_foreign foreign key (user_id) references users
(id) on delete cascade on update cascade)
I already tried to rename big integer and big increments to simple integer and increments withouth success.
There should be one unassignedBigInteger and then you set your foreign key.
https://laravel.com/docs/5.8/migrations#foreign-key-constraints Please check the official documentation
Besides,
Please be carefull with order of migration. It starts from the first file through to latest one, so if you are trying to set foreign key for the table hasn't been created yet, it will throw an error.
E.g
Users table has foreign key relation with articles and like following;
create_users_table
create_articles_table
Since articles table not created yet, you will not be able to assign. For such cases like this, i suggest you to use "add_foreign_keys_to_articles" after all basic structure of tables created.
Schema::table('articles', function(Blueprint $table)
{
$table->foreign('user_id')
->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
});

How to create foreign key by Laravel migration?

How can we make a referenced key and foreign key in laravel by migrations.
Think I have two migration files in database directory in laravel, both of them create a different table in my database.
the first migration creates a table that is for posts which has a column in the name of Id.
the second migration create comments table that has a column in the name of post_id. Now the Id column in posts table is referenced key and the post_id in comments table is foreign key, how can I connect these two columns together?
It would be better to set unsignedInteger for foreign key type
$table->unsignedInteger('category_id')->nullable();
$table->foreign('category_id')
->references('id')
->on('categories')
->onUpdate('cascade')
->onDelete('some action');;
Take the example where you have a users table and a user_address table. A user can have many addresses and an address belongs to a user.
Default user table
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
user_addresses table with user_id as the foreign key
Schema::create('user_addresses', function (Blueprint $table) {
$table->bigIncrements('id'); // by default the primary key is set to unsigned big integer
$table->unsignedBigInteger('user_id'); //associate the address with a user
$table->text('address');
$table->string('city');
$table->string('country');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
After defining the migrations, next step is to define the relationship in their respective model classes
In the User Model, add
public function address(){
return $this->hasMany(UserAddress::class );
}
And in the UserAddress Model, add
public function user(){
return $this->belongsTo(User::class, 'user_id');
}
you use like this.
$table->integer('userId')->unsigned();
$table->foreign('userId')->references('id')->on('users')->onDelete('cascade')->onUpdate('cascade');
If you're trying to create a foreign key constraint for a table that references the 'id' column on a 'users' table for example. For a better developer experience, you can write it in this way:
$table->foreignId('user_id')
->constrained('users')
->onUpdate('cascade')
->onDelete('cascade');
Schema::table('posts', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});

Resources