I'm trying to delete a user but there is ForeignKey constraints that I also need to delete.
In my User model, I have
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
public $incrementing = false;
protected $fillable = [
'name',
'email',
'password',
'timezone',
'profile_picture',
'notification_key'
];
protected $hidden = [
'password',
'pivot',
'admin'
];
public static function boot()
{
parent::boot();
static::creating(function ($instance) {
$instance->id = Uuid::uuid4();
});
}
public function groups()
{
return $this->belongsToMany(Group::class)
->withPivot('user_role')
->withTimestamps();
}
public function events()
{
return $this->belongsToMany(Event::class);
}
}
migrations for relation are
class CreateEventUserTable extends Migration
{
public function up()
{
Schema::create('event_user', function (Blueprint $table) {
$table->uuid('event_id');
$table->uuid('user_id');
$table->primary(['event_id', 'user_id']);
$table->foreign('event_id')->references('id')->on('events');
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('event_user');
}
}
and
class CreateGroupUserTable extends Migration
{
{
Schema::create('group_user', function (Blueprint $table) {
$table->uuid('group_id');
$table->uuid('user_id');
$table->string('user_role')->nullable();
$table->timestamps();
$table->boolean('owner');
$table->primary(['group_id', 'user_id']);
$table->foreign('group_id')->references('id')->on('groups');
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('group_user');
}
}
so I was trying to delete user like this
public function delete($user)
{
$user = User::findOrfail('id', $user->id);
$res = $user->groups()->events()->delete();
if ($res) {
return response('Success, user was deleted', 204);
} else {
return response()->json(error);
}
}
but still, I'm receiving
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`event_activities`, CONSTRAINT `event_activities_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)) (SQL: delete from `users` where `id` = someID) in file /home/server/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 664
I was hoping to do deletion in the manner by relationship in the User model, but I'm still receiving an Integrity error, so what is the proper way of doing this?
There are 3 ways to achieve this:
Using detach
$user->groups()->events()->detach();
$user->groups()->detach();
Utilise the deleting event on related models like in this answer
Migrations.
// in user_roles
$table->integer('group_id');
$table->foreign('group_id')->references("id")->on("groups")->onDelete("cascade");
This translates into:
When group 'id' is deleted on 'groups', delete this row.
Apply same thing to groups for events.
Edit:
Looking at your migrations, you implemented 3rd solution, but you seem to forget
->onDelete('cascade');
Related
I am currently learning Laravel through a personal project.
Context
In a blog like application, I need to link an article to its author. When I save the article, I get the error below.
Error
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (parabolica-dev.articles, CONSTRAINT articles_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: insert into articles (title, content, excerpt, updated_at, created_at) values (rgergregerg, regergergregerg, regregregregreg, 2020-04-29 09:55:12, 2020-04-29 09:55:12))
Models
Article
class Article extends Model
{
protected $fillable = ['title', 'content', 'excerpt', 'user_id'];
public function user() {
return $this->belongsTo('App\User');
}
}
User
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
public function article()
{
return $this->hasMany('App\Article');
}
}
Migrations
Users
class CreateUsersTable extends Migration
{
public function up()
{
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();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
Articles
class CreateArticlesTable extends Migration
{
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->text('excerpt');
$table->text('content');
$table->string('type');
$table->string('status');
// Relationship between article and user
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('articles');
}
}
Controller
ArticleController
class ArticleController extends Controller
{
public function store(StoreArticle $request)
{
$validatedData = $request->validated();
$user = Auth::user()->id;
$article = Article::create($validatedData);
$article->user_id = $user;
$request->session()->flash('status', 'Article was created!');
return redirect()->route('articles.show', ['article' => $article->id]);
}
}
Solutions tried
Adding user_id to the $fillable array in my Article model, I still get the error.
Adding the nullable() method to user_id in my migration. Saving the article goes through without the error message but the user_id is recorded as null in my table afterwards.
Those are the 2 most proposed solutions across SO / LaravelCasts from what I found. Any suggestions on what I did wrong ?
Thanks for helping me !
The create method creates and saves a new instance of your model. Since the model does not include the users id at that point, it fails.
You could fix that by adding user_id to the fillables array of your model and also add the user id to the $validatedData array before creating the model.
Alternatively, you can also create a new instance of your model with the new keyword, set all data and explicitely save it once you're done:
$article = new Article($validatedData);
$article->user()->associate( Auth::user() );
$article->save();
You have to change this three lines. You insert a row but at the time user_id is null. That's why it shows the error because you assigned the user_id field not nullable.
$article = new Article;
$article->fill($validatedData);
$article->user_id = Auth::user()->id;
$article->save();
I am currently learning Laravel through a personal project.
Context
In a blog like application, I need to link an article to its author. When I save the article, I get the error below.
Error
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (parabolica-dev.articles, CONSTRAINT articles_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id)) (SQL: insert into articles (title, content, excerpt, updated_at, created_at) values (rgergregerg, regergergregerg, regregregregreg, 2020-04-29 09:55:12, 2020-04-29 09:55:12))
Models
Article
class Article extends Model
{
protected $fillable = ['title', 'content', 'excerpt', 'user_id'];
public function user() {
return $this->belongsTo('App\User');
}
}
User
class User extends Authenticatable
{
protected $fillable = [
'name', 'email', 'password',
];
public function article()
{
return $this->hasMany('App\Article');
}
}
Migrations
Users
class CreateUsersTable extends Migration
{
public function up()
{
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();
});
}
public function down()
{
Schema::dropIfExists('users');
}
}
Articles
class CreateArticlesTable extends Migration
{
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string('title');
$table->text('excerpt');
$table->text('content');
$table->string('type');
$table->string('status');
// Relationship between article and user
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
});
}
public function down()
{
Schema::dropIfExists('articles');
}
}
Controller
ArticleController
class ArticleController extends Controller
{
public function store(StoreArticle $request)
{
$validatedData = $request->validated();
$user = Auth::user()->id;
$article = Article::create($validatedData);
$article->user_id = $user;
$request->session()->flash('status', 'Article was created!');
return redirect()->route('articles.show', ['article' => $article->id]);
}
}
Solutions tried
Adding user_id to the $fillable array in my Article model, I still get the error.
Adding the nullable() method to user_id in my migration. Saving the article goes through without the error message but the user_id is recorded as null in my table afterwards.
Those are the 2 most proposed solutions across SO / LaravelCasts from what I found. Any suggestions on what I did wrong ?
Thanks for helping me !
The create method creates and saves a new instance of your model. Since the model does not include the users id at that point, it fails.
You could fix that by adding user_id to the fillables array of your model and also add the user id to the $validatedData array before creating the model.
Alternatively, you can also create a new instance of your model with the new keyword, set all data and explicitely save it once you're done:
$article = new Article($validatedData);
$article->user()->associate( Auth::user() );
$article->save();
You have to change this three lines. You insert a row but at the time user_id is null. That's why it shows the error because you assigned the user_id field not nullable.
$article = new Article;
$article->fill($validatedData);
$article->user_id = Auth::user()->id;
$article->save();
I have two tables :
1) users
Schema::create('users', function (Blueprint $table) {
$table->engine = "InnoDB";
$table->string('id')->unique();
$table->string('name')->nullable();
$table->string('surname')->nullable();
$table->string('email')->unique()->nullable();
$table->string('address')->nullable();
$table->string('telephone')->nullable();
$table->timestamps();
});
2) users_games
Schema::create('user_games', function (Blueprint $table) {
$table->engine = "InnoDB";
$table->increments('id');
$table->string('user_id');
$table->boolean('state')->default(false);
$table->timestamps();
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
Every user can have many games so i want every game->user_id to match with the user's id.
I have the below function where i create a user :
public function createNewUser(){
// Check here if user is about to win,
$mUniqueID = uniqid("",true); // create an id
$user = new User();
$user->id = $mUniqueID;
$saved = $user->save();
$user = User::find($mUniqueID);
$currentGame = new UserGame(['state' => false]); // It is in 'fillable' array - boolean
$user->games()->save($currentGame);
$mUserInformation = [
'mUniqueID' => $mUniqueID,
'game_id' => $user->games()->latest()->first(),
];
if($saved)
return $mUserInformation;
else
return redirect()->route('game');
}
The error i get :
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(db_name.user_games, CONSTRAINT user_games_user_id_foreign
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE)
(SQL: insert into user_games (state, user_id, updated_at,
created_at) values (0, 59380, 2017-06-07 14:18:52, 2017-06-07
14:18:52))
I can't understand why this error occurs. If you need any more information please ask and i will provide.
EDIT 1 :
Also, in my database an id of user is : 59380b495c1942.30562655 but the error mentions only 59380, shouldn't it be 59380b495c1942.30562655 ?
EDIT 2:
User.php model
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
// all fillables here
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
public function games()
{
return $this->hasMany('App\UserGame');
}
}
UserGame.php model
class UserGame extends Model
{
protected $fillable = [
'state'
];
public function user()
{
return $this->belongsTo('App\User');
}
}
So if you want to use InnoDB engine in /config/database.php change 'engine' => null, to 'engine' => 'InnoDB'
To use uuid you can add laravel-uuid by add composer require webpatser/laravel-uuid, after add the aliases in config/app.php
Change Migrations $table->increments('id') to $table->uuid('id') and add $table->primary('id')
In models add public $incrementing = false; Hope help you
In the end add trait
namespace App;
use Webpatser\Uuid\Uuid;
trait Uuids
{
protected static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->{$model->getKeyName()} = Uuid::generate()->string;
});
}
}
In model also add use Uuids;
I have one foreign key in my database named images.
This is its Migration:
class CreateImagesTable extends Migration
{
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->integer('product_r_id')->unsigned();
$table->string('name', 50);
$table->text('images', 50);
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
Schema::table('images', function (Blueprint $table) {
$table->foreign('product_r_id')->references('id')->on('products_r')->onDelete('cascade')->onUpdate('cascade');
});
}
public function down()
{
Schema::drop('images');
}
}
Its Model looks like this:
class Images extends Model
{
protected $table = 'images';
protected $fillable = ['product_id', 'product_r_id', 'name', 'images'];
public function product()
{
return $this->belongsTo('App\Product', 'product_id');
}
public function productR()
{
return $this->belongsTo('App\ProductR', 'product_r_id');
}
}
ProductR Model looks like this:
class ProductR extends Model
{
protected $table = 'products_r';
protected $fillable = ['email', 'title', 'filename', 'inputMpg', 'number_of_chapters'];
public function images()
{
return $this->hasMany('App\Images');
}
}
And Product Model like this:
class Product extends Model
{
protected $table = 'products';
protected $fillable = ['email', 'title', 'filename', 'inputMpg', 'number_of_chapters'];
public function scenesImages()
{
return $this->hasMany('App\Images');
}
}
So I basicaly try to save in two different forms different products with their image into the same table in my database (images).
Running my Program returns me this error:
QueryException in Connection.php line 655: SQLSTATE[23000]: Integrity
constraint violation: 1452 Cannot add or update a child row: a foreign
key constraint fails (mydb.images, CONSTRAINT
images_product_id_foreign FOREIGN KEY (product_id) REFERENCES
products (id) ON DELETE CASCADE ON UPDATE CASCADE) (SQL: insert
into images (name, images, product_r_id, updated_at,
created_at) values (ki, 0Chrysanthemum.jpg, 10, 2016-05-20 10:50:51,
2016-05-20 10:50:51))
I think the issue arises because of these lines:
$table->integer('product_id')->unsigned();
[...]
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade')->onUpdate('cascade');
You cannot just create an image without filling out product_id which seems to be the case because the error
insert into images (name, images, product_r_id, updated_at, created_at) ...
shows that you're inserting into images without product_id which cannot be null and has a foreign key constraint.
I suppose you can do a
$table->integer('product_id')->unsigned()->nullable();
so you don't need to assign it when inserting.
I have some trouble getting the foreign key.
My Migrations looks like this (shortened them):
<?php
class CreateProductsTable extends Migration
{
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('email');
$table->string('title');
$table->string('filename');
$table->integer('number_of_chapters');
$table->text('input_mpg');
$table->timestamps();
});
}
public function down()
{
Schema::drop('products');
}
}
<?php
class CreateChaptersTable extends Migration
{
public function up()
{
Schema::create('chapters', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_id')->unsigned();
$table->time('input-chapter-start1');
$table->time('input-chapter-end1');
$table->timestamps();
});
Schema::table('chapters', function($table) {
$table->foreign('product_id')->references('id')->on('products');
});
}
public function down()
{
Schema::drop('chapters');
}
}
And my 2 Model like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Chapters extends Model
{
protected $table = 'chapters';
protected $fillable = ['input-chapter-start1', 'input-chapter-end1'];
public function product()
{
return $this->belongsTo('App\Product');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
protected $fillable = ['email', 'title', 'filename', 'inputMpg', 'number_of_chapters'];
public static $rules = [
'email' => 'required|email|max:50',
'title' => 'required|max:50',
'filename' => 'required|max:50',
'input_mpg' => 'required'
];
public function Chapters()
{
return $this->hasMany('App\Chapters');
}
}
And just save it like this in my Controller
$product->save();
$Chapters->save();
And get following error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or
update a child row: a foreign key constraint fails
(generator.chapters, CONSTRAINT chapters_product_id_foreign
FOREIGN KEY (product_id) REFERENCES products (id)) (SQL: insert
into chapters (input-chapter-start1, input-chapter-end1,
updated_at, created_at) values (12:12:12, 12:12:12, 2016-04-25
11:41:31, 2016-04-25 11:41:31))
EDIT
Controller looks like this:
namespace App\Http\Controllers;
class ProductController extends Controller
{
protected $request;
public function request(Request $request)
{
$this->request = $request;
}
public function createProduct(Request $request)
{
$product = new Product;
$Chapters = new Chapters($request->all());
$data = $request->all();
$projectEmail = $request->input('email');
$projectTitle = $request->input('title');
$projectFile = $request->input('filename');
$projectChapters = $request->input('number_of_chapters');
$validator = Validator::make($request->all(), Product::$rules);
if($validator->fails())
{
return Redirect::back()->withInput()->withErrors($validator);
}
$product->fill($data);
if($product->save())
{
$Chapters->product()->associate($product);
$Chapters->save();
return redirect()->route('root')->with('message', 'success')->withInput();
}
else
{
return redirect()->route('newProduct')->with('message', 'Error')->withInput();
}
}
}
Edit I tried Samsquanch suggestion:
And added this in my controller:
$product->save();
$Chapters->product()->associate($product);
$Chapters->save();
but still get this error message:
BadMethodCallException in Builder.php line 2093: Call to undefined
method Illuminate\Database\Query\Builder::products()
The problem is that you're not telling Laravel or MySQL what the foreign key should be.
You have two options here (both from the documentation: https://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models)
The first option would be to save chapters through product:
$chapters = $product->chapters()->saveMany($Chapters); // or just->save() if it's only one
The second (and how I generally do it) would be to use associate() which relies on the belongsTo relationship in your Chapters model:
$product->save();
$Chapters->product()->associate($product);
$Chapters->save();
There's also a third, but not recommended, option of just setting the foreign key yourself manually.
Edit:
$product->chapters()->associate($Chapters);
$product->save();