Many-to-many in same model - php

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.)

Related

I cannot delete data which have many-to-many relationship in laravel 9

I am using PHP 8.2.0, MySQL 8.2.0, and Laravel 9.48.0. This is my database migrations file pivot table (category_menu):
public function up()
{
Schema::create('category_menu', function (Blueprint $table) {
$table->foreignId('category_id')->constrained();
$table->foreignId('menu_id')->constrained();
});
}
This is the CategoryController.php:
public function destroy(Category $category)
{
Storage::delete($category->image);
$category->menus()->delete(); // many-to-many relationship
$category->delete();
return to_route('admin.categories.index');
}
Lastly, this is the MenuController.php:
public function destroy(Menu $menu)
{
Storage::delete($menu->image);
$menu->categories()->delete(); // many-to-many relationship
$menu->delete();
return to_route('admin.menus.index');
}
I have tried deleting one of the menu/category, but laravel keeps sending out an error:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (larareserve.category_menu, CONSTRAINT category_menu_menu_id_foreign FOREIGN KEY (menu_id) REFERENCES menus (id))
delete `menus` from `menus` inner join `category_menu` on `menus`.`id` = `category_menu`.`menu_id` where `category_menu`.`category_id` = 4
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (larareserve.category_menu, CONSTRAINT category_menu_category_id_foreign FOREIGN KEY (category_id) REFERENCES categories (id))
delete `categories` from `categories` inner join `category_menu` on `categories`.`id` = `category_menu`.`category_id` where `category_menu`.`menu_id` = 7
I thought, this error might have to do with the migration's pivot table (category_menu). But, I just don't know how to fix this. I am currently one month old learning the laravel framework and right now, I am working on the tutorial project from youtube. Please help (educate) me anyone. I am sorry for all inconveniences.
Alright. Already got the solution from Laravel Cannot delete or update a parent row: a foreign key constraint fails
so what I did was, in my database migrations file pivot table (category_menu):
public function up()
{
Schema::create('category_menu', function (Blueprint $table) {
$table->foreignId('category_id')->constrained();
$table->foreignId('menu_id')->constrained()->onDelete('cascade');
});
}
CategoryController.php:
public function destroy(Category $category)
{
Storage::delete($category->image);
$category->menus()->delete(); // many-to-many relationship
$category->delete();
return to_route('admin.categories.index');
}
MenuController.php:
public function destroy(Menu $menu)
{
Storage::delete($menu->image);
//$menu->categories()->delete(); // many-to-many relationship
$menu->delete();
return to_route('admin.menus.index');
}
By adding ->onDelete('cascade') on the migration file, I can already delete the menu. I also put the syntax only on the menu item in the migration file and commented the line to delete the menu's category method on the MenuController, so that whenever I deleted the menu, the category won't be deleted. If I deleted the category, the menu related to it will also be deleted.
This is yet another solution for another type of outcome. Let say, whenever I want to delete the menu, only the menu gets deleted. And whenever I want to delete the category, only the category gets deleted.
Migration File (category_menu):
public function up()
{
Schema::create('category_menu', function (Blueprint $table) {
$table->foreignId('category_id')->constrained()->onDelete('cascade');
$table->foreignId('menu_id')->constrained()->onDelete('cascade');
});
}
CategoryController.php:
public function destroy(Category $category)
{
Storage::delete($category->image);
// $category->menus()->delete(); // many-to-many relationship
$category->delete();
return to_route('admin.categories.index');
}
MenuController.php:
public function destroy(Menu $menu)
{
Storage::delete($menu->image);
// $menu->categories()->delete(); // many-to-many relationship
$menu->delete();
return to_route('admin.menus.index');
}

Laravel how to get User Profile field from separate table

I am new to Laravel and Eloquent is quite a challenge for me to understand. I have a User and a UserProfile model and table. UserProfile table has user_id (FK to user's id), 'key, and value fields.
I want to get the values of all the UserProfile fields associated with the user_id. Here is my code but nothing works. I am sure I am making some stupid mistakes but still learning :) Laravel.
UserProfile Model
class UserProfile extends Model
{
public $timestamps = FALSE;
protected $fillable = [
'user_id',
'key',
'value',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
User Model method
public function profileFields(){
return $this->hasMany(UserProfile::class);
}
UserProfile Migration
public function up()
{
Schema::create('user_profiles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned();
$table->string('key', 191);
$table->longText('value');
$table->foreign('user_id', 'user_profile_uid_fk')
->references('id')
->on('users')
->onDelete('cascade');
$table->unique(['user_id', 'key'], 'user_profile_unique_key');
});
}
I am trying to get the profile fields for the user using User::findOrFail(10)->profileFields but it is giving me property not defined exception.
Need Help: Can anyone help me to make it work so I can get all user_profiles
fields from the profile table?
Error Output (Tinker)
>>> User::findOrFail(10)->profileFields
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]: Base
table or view not found: 1146 Table 'velvetpaper.user_user_profile'
doesn't exist (SQL: select user_profiles.*,
user_user_profile.user_id as pivot_user_id,
user_user_profile.user_profile_id as pivot_user_profile_id from
user_profiles inner join user_user_profile on user_profiles.id
= user_user_profile.user_profile_id where user_user_profile.user_id = 10)'
The relation between users and user_profiles is a one to many.
You might have not restarted Tinker since you are getting the wrong error, dont forget to exit Tinker after the modification in the code. Once tinker is started, code changes wont affect it.
you can use join to implement this stuff. like this...
this is query builder
$data['profile']=DB::table(usertable)
->where('usertable.id',$id)
->leftjoin('userprofiletable','usertable.id','=','userprofiletable.user_id')
->first();
return view('profile_view',$data)
//view
$profile->fullname
$profile->sex
$profile->phone
...

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();
}

how I can add 2 auto-increment columns in the same table in the laravel database

I want to know if I can add 2 auto-increment columns in the same table in laravel? but the second has different value to start with it?
uniID I want to start from 43600000,
Schema::create('students', function (Blueprint $table){
$table->increments('id');
$table->increments('uniID');
$table->integer('student_id');
$table->timestamps();});
DB::statement("ALTER TABLE students AUTO_INCREMENT = 43600000;");
Laravel doesn't support this because databases don't generally support it. The increments() and bigIncrements() column types cannot be used multiple times in the same table Schema and will fail on create:
PDOException: SQLSTATE[HY000]: General error: 1 table "students" has more than one primary key
But if uniId will always be 43600000 larger than id, you can use a computed attribute in Eloquent:
class Student
{
public function getUniIdAttribute()
{
return $this->id + 43600000;
}
}
Then you can use this in your controllers or Blade templates:
>>> $user = Student::first()
=> App\Student{#3078
id: 1,
...
}
>>> $student->uniId
=> 43600001
The downside to this approach is that you won't be able to use uniId as a foreign key in other tables.

Laravel - A show can have multiple providers

So I am trying to figure a solution to this but not sure exactly how to do this. I have a table that stores all the shows that happen. In a given show I can have multiple providers attend that show. A provider could also attend many shows as well. So how do I store this in the DB and do the eloquent relationship?
Show Schema
Schema::create('shows', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('number')->unsigned();
$table->dateTime('airDate');
$table->string('podcastUrl')->nullable();
$table->timestamps();
});
Provider Schema
Schema::create('providers', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('shortName')->nullable();
$table->string('image')->nullable();
$table->string('social')->nullable();
$table->timestamps();
});
Would I store the provider_id in the shows schema?
Update 1
So I created a new migration for a pivot table
Schema::create('provider_show', function (Blueprint $table) {
$table->integer('provider_id')->unsigned()->index();
$table->foreign('provider_id')->references('id')->on('providers')->onDelete('cascade');
$table->integer('show_id')->unsigned()->index();
$table->foreign('show_id')->references('id')->on('shows')->onDelete('cascade');
$table->primary(['provider_id', 'show_id']);
});
Then in the show model I created the following
public function providers()
{
return $this->belongsToMany(Provider::class);
}
Now when I am saving a new show I added a multiselect to select the providers I want
$show = new Show;
$show->name = $request->name;
$show->number = $request->number;
$show->airDate = $request->airDate;
$show->podcastUrl = $request->podcastUrl;
$show->providers()->attach($request->providerList);
$show->save();
Session::flash('message', "Created Successfully!");
return back();
Then when I save I get the following error
SQLSTATE[23000]: Integrity constraint violation: 19 NOT NULL constraint failed: provider_show.show_id (SQL: insert into "provider_show" ("provider_id", "show_id") select 1 as "provider_id", as "show_id" union all select 2 as "provider_id", as "show_id")
Create a provider_show migration which will act as your pivot table.
This table would contain both provider_id and show_id which will provide the many-to-many relationship between those entities.
Then on your Provider model you can provide a shows() method which returns a BelongsToMany relationship.
// In your Provider model
public function shows()
{
return $this->belongsToMany('App\Show');
}
Note that Laravel by default looks for a pivot table name based alphabetically on the two relationships.
You can also add the inverse on your Show model by providing a providers() method that also returns a BelongsToMany relationship.

Categories