2 ManyToMany relationship + 1 param in Laravel Eloquent - laravel

I have 2 tables A and B.
I make a many to many Relationship with a pivot table called A_B
Now I need to make other ManyToMany Relationship between A_B and User ( U )
So I have another table A_B_U
Now, What I need and can't do it, is writing a relationship from A to A_B_U.
I set U to a vale, so A_B -> A_B_U is now a belongsTo Relationship, I should be able to access it easily, but I can't write it, I can write the first relationship, but then, I can't write the second one.
I don't know neither how to pass a param in ManyToMany Rel.
In fact, it shoud be a belongsTo, not ManyToMany so I'm a bit lost in all that....
Any Idea how to do it?

What it looks like
category_tournament_user
/ \
category_tournament users
/ \
tournaments categories
Migrations
Schema::create('tournaments', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('categories', function(Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
});
Schema::create('category_tournament', function(Blueprint $table) {
$table->increments('id');
$table->integer('category_id');
$table->integer('tournament_id');
$table->timestamps();
});
Schema::create('category_tournament_user', function(Blueprint $table) {
$table->integer('category_tournament_id');
$table->integer('user_id');
});
Models
class Tournament extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function categoryTournaments()
{
return $this->hasMany(CategoryTournament::class);
}
}
class Category extends Model
{
public function tournaments()
{
return $this->belongsToMany(Tournament::class);
}
public function categoryTournament()
{
return $this->hasMany(CategoryTournament::class);
}
}
class CategoryTournament extends Model
{
protected $table = 'category_tournament';
public function category()
{
return $this->belongsTo(Category::class);
}
public function tournament()
{
return $this->belongsTo(Tournament::class);
}
public function users()
{
return $this->belongsToMany(User::class, 'category_tournament_user');
}
}
class User extends Authenticatable
{
public function categoryTournaments()
{
return $this->belongsToMany(CategoryTournament::class, 'category_tournament_user');
}
}
Get all users of a tournament
$tournament = App\Tournament::with('categoryTournaments.users')->find(1);
foreach($tournament->categoryTournaments as $categoryTournament) {
// To get the category of the tournament, this will return an App\Category
$category = $categoryTournament->category;
// If you have a name column on your categories table...
$categoryName = $category->name;
// To get the tournament.
$tournament = $categoryTournament->tournament;
// To get the name of the tourament (if there is a name column)
$tournamentName = $tournament->name;
$tournament->created_at; // etc...
// To get all the people participating in this tournament category
foreach($categoryTournament->users as $user) {
echo $user->email;
}
}
If you need to figure out how to traverse the relationships (getting all tournaments and categories a user is participating in, etc...) please feel free to ask.
Starting at the User
// This will list all tournament and category names a user belongs to.
$user = App\User::with('categoryTournaments.tournament', 'categoryTournaments.category')->find($userId);
foreach($user->categoryTournaments as $categoryTournament) {
echo 'Category Name: '.$categoryTournament->category->name;
echo 'Tournament Name: '.$categoryTournament->tournament->name;
echo '<br>';
}
Edit
users and category_tournament make a belongsToMany relationship.
categories and tournaments make a belongsToMany relationship.
category_tournament also has a belongsTo to both tournaments and categories
There is a possibility we can further simplify this if you remove the tables tournaments and categories and drop all their columns right into category_tournament. That way, you end up with only one belongsToMany relationship to manage.

Related

How make eloquent laravel relathionship migration with the same table?

if instead of having a users table where one user can follow many users. I would have a cows table where each cow has a single father and a single mother, where the parents can have many children. do I require an external table to store that or can I just add in my cows table the fields cow_father_id and cow_mother_id?
-referring to making 2 eloquent relationships of cows table with same cows table
and what this migration would look like?
You could do this. I've tested as well.
Migration
Schema::create('cows', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->integer('father_id')->nullable();
$table->integer('mother_id')->nullable();
$table->timestamps();
});
Model
class Cow extends Model
{
use HasFactory;
public function father()
{
return $this->belongsTo(self::class, 'father_id');
}
public function mother()
{
return $this->belongsTo(self::class, 'mother_id');
}
public function children()
{
return $this->hasMany(self::class, 'father_id')->orWhere('mother_id', $this->id);
}
}

Can't create one to many relationship on same model

I want to create sponsors users on my website. I use the same model as relationship.
User.php (model):
public function sponsor(): HasMany
{
return $this->hasMany(self::class, 'sponsored_id', 'sponsor_id');
}
public function sponsored(): BelongsTo
{
return $this->BelongsTo(self::class, 'sponsor_id', 'sponsored_id');
}
Sponsor rows :
Schema::table('users', function (Blueprint $table) {
$table->foreignId('sponsor_id')->nullable();
$table->foreignId('sponsored_id')->nullable();
});
My UserSeeder:
$sponsor = User::factory()->create(['name' => 'sponsor']);
$sponsor->sponsor()->save(
User::factory()->make()
);
As per your comment you are trying to retrieve one record from sponser so it should be
$sponsor->sponsor()->first()

Laravel Models and displaying them on view together

For a school assignment we have two tables and models players and countries
I know its either my models or my controller (I've had this problem before but in another assignment their was only one country so i just looped through a country variable and used arrays instead but this wont work for multiple countries)
When I try to display in the view i get "Trying to get property of non-object 'name' on the {{$player->country->name}} and this is the way the teacher has explicitly said we are to display it.
Currently before anything else id like to display all my players and their country names
Models
class Country extends Model
{
//
protected $table = 'countries';
protected $fillable=['name','flag'];
public function player(){
return $this->hasMany(Player::class);
}
}
class Player extends Model
{
//
protected $fillable =['name','age','role','batting','bowling','image','odiRuns','countries_id'];
public function country()
{
return $this->belongsTo(Country::class);
}
}
Tables
public function up()
{
Schema::create('countries', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('flag');
$table->timestamps();
});
}
public function up()
{
Schema::create('players', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->integer('age');
$table->string('role');
$table->string('batting');
$table->string('bowling');
$table->string('image');
$table->string('odiRuns');
$table->integer('countries_id')->unsigned();
$table->foreign('countries_id')->references('id')->on('countries');
$table->timestamps();
});
}
Controller
use App\Player;
use App\Country;
use Illuminate\Http\Request;
class PlayerController extends Controller
{
public function index()
{
//
$players=Player::all();
return view('index',compact('players'));
}
View
#extends('layout')
#section('content')
#foreach ($players as $player )
{{$player->name}}
{{$player->age}}
{{$player->role}}
{{$player->batting}}
{{$player->bowling}}
{{$player->odiRuns}}
{{$player->country->name}}
#endforeach
#endsection
Edit
players all have country id's relating to the countries table
Tables
players table
countries table
The problem is your missing foreign key in relation. When you are defining a relationship, if you explicitly don't tell which foreign key to use for the relationship, Laravel looks for a foreign key like relationname_primarykeyoftheparenttable. In your case its country_id but in your players table the column name is countries_id. So relationship is not building and you are getting error. Change the column name or tell the relationship which foreign key to use to build the relationship.
class Player extends Model
{
protected $fillable =['name','age','role','batting','bowling','image','odiRuns','countries_id'];
public function country()
{
return $this->belongsTo(Country::class,'countries_id');
}
}
Laravel Doc

Get all categories of post in Laravel

I create a table post__post_category_relations to save categories of post.
Schema::create('post__post_category_relations', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('post_id')->unsinged();
$table->integer('category_id')->unsinged();
$table->timestamps();
});
At blade template edit post, I want show list categories of post.
In Post model I wrote:
public function categories(){
return $this->belongsTo(PostCategoryRelations::class,'id','post_id','category_id');
}
But it only return one category. Can you show me how to show all categories? Thank so much!
This looks similar to Many To Many approach between posts and categories. And a junction table which connects post and category table should have post_id, category_id and other columns are not required like id , timestamps() i guess you won't be using them in your application.
Migration would minimize to
Schema::create('post__post_category_relations', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('post_id')->unsinged();
$table->integer('category_id')->unsinged();
});
For many to many you can add definitions in your models like
class Post extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'post__post_category_relations', 'post_id');
}
}
class Category extends Model
{
public function posts()
{
return $this->belongsToMany(Post::class, 'post__post_category_relations', 'category_id');
}
}
If you still want to keep other columns from junction table post__post_category_relations you can access them by defining as pivot attributes in your model like
class Post extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'post__post_category_relations', 'post_id')
->withPivot('id','cols')
->as('post__post_category_relation_cols');
}
}

How to use relationship in laravel?

I use work with relationship in laravel 5.6.
I create product table with migration:
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->text('description');
$table->string('tags');
$table->string('original_price');
$table->integer('view_order')->default(0);
$table->unsignedInteger('admin_id');
$table->foreign('admin_id')->references('id')->on('admins');
$table->boolean('status');
$table->timestamps();
});
And i create category table with migration:
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->boolean('status');
$table->timestamps();
});
And create product_categories table with migration:
Schema::create('product_categories', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('product_id');
$table->foreign('product_id')->references('id')->on('products');
$table->unsignedInteger('category_id');
$table->foreign('category_id')->references('id')->on('categories');
$table->timestamps();
});
Now, I use Bootstrap Multiselect for categories in one product.
In category model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function products()
{
return $this->belongsToMany(Product::class);
}
In Product model:
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function categories()
{
return $this->belongsToMany(Category::class);
}
How to add category_id and product_id in product_categories table with relationship?
Check the documantation related to Many to many Relationships.
Your pivot table doesn't follow Laravel's convention, either update your table name or update your relationships to address this issue.
The convention is the alphabetical order of the two models, thus your pivot table should be named: category_product
If you do not want to update the table name, update your relationships.
public function categories()
{
return $this->belongsToMany(Product::class, 'product_categories')
}
public function products()
{
return $this->belongsToMany(Category::class, 'product_categories')
}
Now to "save an entry to the pivot table" -or in other words: to create the relationship between the two models- you may use attach or sync method.
$product->categories()->attach($category);
$product->categories()->attach([$categoryId1, $categoryId2]);
sync is different.
The sync method accepts an array of IDs to place on the intermediate table. Any IDs that are not in the given array will be removed from the intermediate table.
To detach (delete entry in pivot table), simple use the detach method.
$product->categories()->detach([1, 2]);
Of course, do the same for Category.
Your model names are Product and Category and the derived relational table will be category_product because category came before product in alphabetical order.
You only have to add the pivot table:
public function categories()
{
return $this->belongsToMany(Product::class, 'product_categories')
}
public function products()
{
return $this->belongsToMany(Category::class, 'product_categories')
}
Now for save with relationship:
$product->categories()->attach($category);
$product->categories()->attach([$category_id_1, $category_id_2]);
You only have to add the pivot table:
public function products()
{
return $this->belongsToMany(Product::class, 'product_categories');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'product_categories');
}
By default, laravel derives the table name from the alphabetical order of the related model names. Here your model names are Product and Category and the derived relational table will be category_product because category came before product in alphabetical order. Either you can change the table name or you can override this my mentioning the table name as the second parameter in the relational method as follows.
public function products()
{
return $this->belongsToMany(Product::class, 'product_categories');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'product_categories');
}

Resources