Primary key and foreign key - Table entry deletion - php

Table: Users (For storing user login and personal info)
Primary key- ID
"id" is using as foreign key in the tables complaints and books.
My question is... How can I delete user entries in complaints and
books table when I want to delete a user from users table (in laravel
5.2)
Thanks in advance

In your model you can leverage model events to achieve what you want:
public static function boot() {
parent::boot();
static::deleting(function($user) {
if(!$user->books->isEmpty()) {
foreach($user->books as $book) {
$book->delete();
}
}
if(!$user->complaints->isEmpty()) {
foreach($user->complaints as $complaint) {
$complaint->delete();
}
}
});
}
https://laravel.com/docs/5.2/eloquent#events

You can just add an ->onDelete('cascade') to your foreign key (in your migration) if you generally want to delete related rows.
For further information:
https://laravel.com/docs/5.2/migrations#foreign-key-constraints

Related

Laravel - Set data to null before deleting column from other table

I have 2 tables. (1) being users, and (2) being foods.
In the [users] table, there is a food_id bracket that is linked as a foreign key to an item/column's id in the other table [foods].
I am able to make a reservation of a [food] column, although I want to be able to press a 'confirm' button on the item once reserved, which will delete the item's targetted column in the Database.
Although since both tables are linked with a foreign key, I know that I need to set the parent key to null in order to be able to fully delete the target column. Otherwise it throws me an error that I can't delete/update a parent item with children objects.
(my food's object primary ID being linked to the authenticated user's food_id foreign key.)
This current code I tried only throws me the following error: "Call to a member function onDelete() on null"
$foodsId = User::find(auth()->user()->foods_id);
$foodsId->onDelete('set null');
$foodsId->save();
$foodDel = Foods::find($id);
$foodDel->delete();
Don't exactly know what to think here.
You could edit the foreign key constraint to do this automatically, but what you're trying to do can be done with these lines.
$food = Food::findOrFail(auth()->user()->food_id);
auth()->user()->fill(['food_id' => null])->save(); // use forceFill() if food_id is not in the User's fillable fields.
$food->delete();
To have this happen automatically, you could make a migration with the command
php artisan make:migration changeFoodIdForeignKeyConstraint --table=users
function up()
{
Schema::table('users', function (Blueprint $table) {
$table->dropForeign(['food_id']);
$table->foreign('food_id')
->references('id')->on('foods')
->onUpdate('cascade')
->onDelete('set null');
});
}
Another option is to use a model event on the Food model
class Food extends Model
{
/**
* The "booted" method of the model.
*
* #return void
*/
protected static function booted()
{
static::deleting(function ($food) {
User::where('food_id', $food->id)->update(['food_id' => null]);
});
}
Actually have found my own solution. I went to directly target my first foreign key, to then asign a null parameter to it, THEN fetch the targetted ID of my item and delete its column.
$user = auth()->user();
$user->food_id = null;
$foodDel = Foods::find($id);
$foodDel->delete();

Many-to-many in same model

I need to use a many-to-many relationship to one model. I have an Article model, and I want to make a function so that other articles, typically recommended, can be attached to one article.
This is the function, it should work correctly.
$article = Article::where('id', $request->article_id)->first();
$articles_ids = json_decode($request->articles_ids);
$article->articles()->attach($articles_ids);
I have a question about how to create a table of relations in the database and in the model correctly, I did it like this, but even the migration does not work for me
Model
public function articles()
{
return $this->belongsToMany('App\Models\Article');
}
public function article_recommended()
{
return $this->belongsToMany('App\Models\Article');
}
db
Schema::create('article_article_recommended', function (Blueprint $table) {
$table->unsignedBigInteger('article_recommended_id')->nullable();
$table->foreign('article_recommended_id')
->references('id')->on('article_recommended')->onDelete('set null');
$table->unsignedBigInteger('article_id')->nullable();
$table->foreign('article_id')
->references('id')->on('articles')->onDelete('cascade');
});
error in migration
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table
'article_recommended' (SQL: alter table `article_article_recommended` add constraint
`article_article_recommended_article_recommended_id_foreign` foreign key
(`article_recommended_id`) references `article_recommended` (`id`) on delete set null)
What are you trying to do should be fairly simple , it's like a following system where each user is related to many users ( same model ) but also same table !
you are here trying to create another table which i consider unnecessary , you only need two tables
articles & recommendations
and the recommendation tabel will act as a pivot table for articles with its self thus creating a many to many relationship with the same table .
Article.php
public function recommendations() {
return $this->belongsToMany(Article::class , 'recommendations' , 'article_id' , 'recommended_article_id');
}
create_recommendations_table.php
Schema::create('recommendations', function (Blueprint $table) {
$table->primary(['article_id','recommended_article_id']);
$table->foreignId('article_id');
$table->foreignId('recommended_article_id');
$table->timestamps();
$table->foreign('article_id')->references('id')->on('article')->onDelete('cascade');
$table->foreign('recommended_article_id')->references('id')->on('articles')->onDelete('cascade');
});
usage
$article->recommendations()->attach($articles_ids);
be sure that the ref-column has exact the same type as the source column (signed, unsigned etc.)

How to delete rows from a pivot table in Laravel?

I have a films table which contains a many to many relation e.g AgeRatings with a pivot table called film_age_rating which contains a film_id as a foreign key I have this with 3 other relations too.
Right now my app has no functionality to make a deletion request to remove a film, so right now I hard delete rows in the films DB table. When I delete a film from the films table it deletes items, but the data within the pivot table remains unchanged which I don't want to happen.
films_table
public function up()
{
Schema::create('films', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name')->nullable();
}
film_age_rating
public function up()
{
Schema::create('film_age_ratings', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('age_rating_id');
$table->uuid('film_id');
$table->timestamps();
});
}
Film Model
public function ageRatings(): BelongsToMany
{
return $this->belongsToMany(
AgeRatings::class,
'film_age_rating',
'film_id',
'age_rating_id'
);
}
Age Rating Model
public function film(): BelongsToMany
{
return $this->belongsToMany(
Film::class,
'film_age_rating',
'age_rating_id',
'film_id'
);
}
I know an option is to add an onDelete cascade to the pivot tables, but that will require lots of migration tables. Is there another way to tackle this without adding a DELETE request for now or is adding the cascade the only option?
Could you please advise me on the most efficient option?
The only way I can imagine is to use softDeletes
On this way, there will be only one query to delete a film, and it will be a logical delete.
You can delete data using the sync() method. It releases the relation from the pivot table. I assuming that you want to delete a film. So this is a sample method in your controller.
public function deleteFilm($id)
{
$film = Film::find($id);
$film->ageRatings()->sync([]);
$film->delete();
}

Laravel belongsToMany retrieve more then one row

So im creating a booking system where you can create maps and assign them to an event. I have 3 tables to handle this, events, maps, and event_maps
I have after reading the Laravel Documentation i decided to set up a belongsToMany relation.
But when i try to retrieve my maps thru my event model i only get one the first row.
in my controller i do
public function displayForm($id)
{
$event = EventModel::find($id);
print_r($event->maps);
}
The result is a Illuminate\Database\Eloquent\Collection Object with the last out of 2 maps, and i can't for my life figger out how to get them all.
My EventsModel
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'map_id',
// Foreign key name of the model that you are joining to
'event_id'
);
}
My MapsModel
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model on which you are defining the relationship
'event_id',
// Foreign key name of the model that you are joining to
'map_id'
);
}
The database looks something like this
events
- id
- lots of irrelevant data
maps
- id
- lots of irrelevant data
event_maps
- id
- event_id
- map_id
I was thinking that perhaps i should use another relation type, but as far as i understand they don't use a relation table like event_maps.
Everything else work as expected.
Anyone who could clear up this mess? :)
The ids are inverted in the relation. Try this:
public function maps()
{
return $this->belongsToMany('App\Models\Booky\MapsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'event_id'
// Foreign key name of the model on which you are defining the relationship
'map_id',
);
}
And:
public function event()
{
return $this->belongsToMany('App\Models\Booky\EventsModel',
// Table name of the relationship's joining table.
'event_maps',
// Foreign key name of the model that you are joining to
'map_id'
// Foreign key name of the model on which you are defining the relationship
'event_id',
);
}

Laravel updateExistingPivot with multiple primary keys

Problem
I want to update a row in a pivot table that have 2 primary keys. But updateExistingPivot want only a single primary key.
$user = App\User::find(1);
$user->roles()->updateExistingPivot($roleId, $attributes);
My DB-tables
Campaign
User
Campaign_user (primary keys are user_id and campaign_id)
My Question
Should I change my pivot table so it only have 1 primary key called id. Or can I keep it with 2 primary keys, and still update it, with Eloquent?
I think for best practice you should add a key id in your Campaign_user table, structure should:
Campaign_user
id|user_id|campaign_id
In User Model
public function campaign()
{
return $this->belongsToMany('Campaign', 'Campaign_user','user_id','campaign_id')->withPivot('extra attribute if any');
}
In Campaign Model
public function users()
{
return $this->belongsToMany('User', 'Campaign_user','campaign_id','user_id')->withPivot('extra attribute if any');
}
Now your code is:
$user = App\User::find($userId);
$user->campaign()->updateExistingPivot($campaignId, array('any attribute'=>$value));

Categories