Can't create one to many relationship on same model - laravel

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

Related

Laravel define belongsToMany relation ships without providing second parameter

In laravel i try to make a simple relation-ship between two table as users and wallets without providing second parameter, but when i try to access between them i get error:
Base table or view not found: 1146 Table 'sample.user_wallets' doesn't exist
//user
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('parent_id')->nullable();
//...
$table->softDeletes();
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->useCurrent();
});
//wallets
Schema::create('wallets', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('wallet_name');
$table->string('wallet_number');
$table->timestamps();
});
//user_wallet
Schema::create('user_wallet', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->foreignId('wallet_id')->constrained()->cascadeOnDelete();
$table->primary(['user_id','wallet_id']);
});
User model:
public function wallet(): BelongsToMany
{
return $this->belongsToMany(UserWallet::class);
}
Wallet model:
public function user(): BelongsToMany
{
return $this->belongsToMany(User::class);
}
and by this below code i try to access user's wallets:
$this->user_wallets = auth()->user()->with('wallet')->get();
IN Your User Model:
change
public function wallet(): BelongsToMany
{
return $this->belongsToMany(UserWallet::class);
}
To : THis
public function wallets(): BelongsToMany
{
return $this->belongsToMany(Wallet::class,'user_wallet');
}
In Your Wallet Model:
public function users(): BelongsToMany ///not user
{
return $this->belongsToMany(User::class);
}
Note: U dont need UserWallet Model Since it is belongsTOMany Relationship
Suggestion: In real life example a user have many wallet and a wallet is only belongs to one user so the relation is HasMany(on to Many)
It should be plural. wallets and users
User Model:
public function wallets(): BelongsToMany //not wallet
{
return $this->belongsToMany(Wallet::class);
}
Wallet model:
public function users(): BelongsToMany //not user
{
return $this->belongsToMany(User::class);
}

RelationShip Eloquent hasOne

I do not understand how the relationShips are working with Eloquent. Imagine an user with one role. I wrote this in my model User :
public function role()
{
return $this->hasOne('App\Models\Role');
}
And this in my model Role :
public function user()
{
return $this->belongsTo('App\User');
}
After that i would like to retrieve the role of the user connected , like that :
Auth::user()->role->role_name
But it throw an exception :
Undefined column: 7 ERROR: column roles.user_id does not exist
Does it not work like that?
You're missing the user_id foreign column in the roles table, Eloquent assumes that column to exist in order to link a User with a Role
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('role_name');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
});
Update: given a hasOne relationship
App\User model
public function role()
{
return $this->hasOne('App\Models\Role');
}
App\Model\Role model
public function user()
{
return $this->belongsTo('App\User');
}
DatabaseSeeder
$user = factory('App\User')->create();
$user->role()->create([
'role_name' => 'Admin'
]);
routes/web
use Illuminate\Support\Facades\Auth;
Route::get('/', function () {
return Auth::user()->role->role_name;
});
Results => Admin
You should use the belongsTo() relationship in your User model for the role relationship :
public function role()
{
return $this->belongsTo('App\Models\Role');
}

on cascade delete on many to many relationship in laravel

I had used many to many relationship.i have three table named:product,tag,productstag. in here I want whenever I am going to delete a product it will also delete the relationship it had on productstag table.
public function up()
{
Schema::create('productstags', function (Blueprint $table) {
$table->integer('product_id');
$table->integer('tag_id');
$table->primary(['product_id','tag_id']);
$table->timestamps();
});
}
as you can see I have used product_id and tag_id as the primary key.
so I can't use this
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('products')->onDelete('cascade');
so what's the alternative?
on my product model
public function tags()
{
return $this->belongsToMany('App\Tag','productstags','product_id','tag_id')->withTimestamps();
}
on my tag model:
public function products()
{
return $this->belongsToMany('App\Product','Productstags','tag_id','product_id');
}
on my produduct destroy function:
public function destroy(Request $request,$id)
{
$product=Product::findOrFail($id);
if($request->file('image')==''){
$input=$request->except('photo_id');
}
else{
$input=$request->all();
unlink(public_path()."/images/".$product->image->name);
}
$product->delete($input);
Session::flash('deleted_user','the user has been deleted');
return redirect(route('product.index'));
}
It's not as pretty as cascade but you could override the delete method and do this:
public function delete(){
$this->name_of_the_relationship()->delete();
return parent::delete();
}

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

2 ManyToMany relationship + 1 param in Laravel Eloquent

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.

Resources