Laravel : Define model for reverse OneToMany relationship - laravel

I have the following schema:
class Group extends Model
{
/**
* The users that belong to the group.
*/
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
}
What should my User model look like in the other side ?
class User extends Model
{
/**
* The group that owns the user.
*/
public function group()
{
return $this->???(Group::class)->withTimestamps();
}
}

It's also a belongsToMany, just the inverse. Try this paradigm:
return $this->belongsToMany(
'App\Models\Group',
'user_group',
'user_id',
'group_id'
)->withTimestamps();
Where the explicit params are:
Related Model
Table (Pivot table)
Foreign Pivot Key
Related Pivot Key

Related

Strange behavior on laravel many to many relationship

I have two models User and Tenant and in my project, a User can have many Tenants connected to him and Tenant can have many users connect to him.
This is my User model
public function tenants()
{
return $this->beLongsToMany(\App\Models\TenantsUsers::class, 'tenants_user', 'user_id', 'tenant_id');
}
This is my Tenant model
public function users()
{
return $this->beLongsToMany(\App\Models\TenantsUsers::class, 'tenants_user', 'tenant_id', 'user_id');
}
And this is my TenantsUsers model
class TenantsUsers extends Model
{
use UtilTrait;
use Notifiable;
protected $table = 'tenants_user';
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'user_id' => 'integer',
'tenant_id' => 'integer'
];
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
**/
public function tenants()
{
return $this->hasMany(\App\Models\Tenant::class, 'tenant_id');
}
public function users()
{
return $this->hasMany(\App\Models\User::class, 'user_id');
}
When I execute this function from the repository:
$userTemp = $this->userRepository->with(['tenants'])->findWhere(['email' => $userEmail])->first();
And I'm getting this error :
SQLSTATE[42712]: Duplicate alias: 7 ERROR: table name "typo_tenants_user" specified more than once (SQL: select
"typo_tenants_user".*, "typo_tenants_user"."user_id" as "pivot_user_id", "typo_tenants_user"."tenant_id" as
"pivot_tenant_id" from "typo_tenants_user" inner join "typo_tenants_user" on "typo_tenants_user"."id" =
"typo_tenants_user"."tenant_id" where "typo_tenants_user"."user_id" in (1))
What I'm doing wrong?
You don't need to create a model for pivot tables in Eloquent many-to-many relationships. Instead, use the related model's class when defining the relationship:
// User model
public function tenants()
{
return $this->belongsToMany(\App\Models\Tenant::class, 'tenants_user', 'user_id', 'tenant_id');
}
// Tenant model
public function users()
{
return $this->belongsToMany(\App\Models\User::class, 'tenants_user', 'tenant_id', 'user_id');
}
If you follow Eloquent naming conventions by defining the pivot table as tenant_user rather than tenants_user, things can be even further simplified to:
// User model
public function tenants()
{
return $this->belongsToMany(\App\Models\Tenant::class);
}
// Tenant model
public function users()
{
return $this->belongsToMany(\App\Models\User::class);
}

How to define this hasManyThrough relation?

I have the following models. Event belongs to a Casefile. Casefile and User are many-to-many.
class Casefile extends Model
{
public function users()
{
return $this->belongsToMany(User::class)->withTimestamps();
}
public function events()
{
return $this->morphMany('App\Event', 'casefile');
}
}
class User extends Authenticatable
{
public function casefiles()
{
return $this->belongsToMany(Casefile::class)->withTimestamps();
}
}
class Event extends Model
{
public function casefile()
{
return $this->belongsTo('App\Casefile');
}
public function users()
{
return $this->hasManyThrough('App\User', 'App\Casefile');
}
}
When I try to:
App\Event::find(526)->users()->get();
It gives:
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]:
Column not found: 1054 Unknown column 'casefiles.event_id' in 'field
list' (SQL: select users.*, casefiles.event_id from users
inner join casefiles on casefiles.id = users.casefile_id
where casefiles.event_id = 526)'
How can I define the "Event has many Users" relation through Casefile?
It's not possible to use HasManyThrough here without a pivot model for the casefile_user table.
You can define a BelongsToMany relationship instead:
public function users()
{
return $this->belongsToMany('App\User', 'casefile_user', 'casefile_id', null, 'casefile_id');
}
If you not followed laravel naming convention for column name. Then you can specify your column name like this
public function users()
{
return $this->hasManyThrough(
'App\User',
'App\Casefile',
'event_id', // Foreign key on casefiles table...
'user_id', // Foreign key on users table...
);
}
For more Laravel HasManyThrough Relationship

Laravel how to define 3 relationships with one model?

I have a Model which is called Championship. Championship may have 3 judges which are called Main Judge, Main Secretary and Judge Operator.
All of them linked to User Model and stored in the database as user ID.
My relationships looks like this
class Championship extends Model
{
protected $table = 'championships';
public function mainJudge()
{
return $this->hasOne('App\User', 'id', 'main_judge');
}
public function mainSecretary()
{
return $this->hasOne('App\User', 'id', 'main_secretary');
}
public function judgeOperator()
{
return $this->hasOne('App\User', 'id','judge_operator');
}
}
But I can't undertand how to define inverse relationship in User model
class User extends Authenticatable
{
public function sex()
{
return $this->belongsTo('App\Models\Sex');
}
public function player()
{
return $this->hasOne('App\Models\Player', 'user_id');
}
public function championship()
{
????
}
You just have to add it like you are adding other relations :
public function championship()
{
return $this->belongsTo('App\Championship');
}
When you do :
$championship = Championship::find($id);
$mainJudge = $championship->mainJudge;
$mainSecretary = $championship->mainSecretary;
// All objects will be exactly same
dd($mainJudge->championship,$mainSecretary->championship,$championship);
I assume all the user records have a foreign key to championships table championship_id
When you call the $user->championship relation it will return you the championship wrt to its foreign key championship_id
No need to worry you are just confusing the inverse relations:
See it this way:
Your mainJudge, mainSecretary, judgeOperators are of type App\User and every user have a championship_id when you will call the (App\User)->championship it will always return you its respective championship or null if the championship_id is empty.
Its just matter of perspective.
Just try the above code it will clear out your confusion.

Amending foreign key on a Laravel relationship

In Laravel (v5.7.12), I have two models - User and Project.
A user has an id and can have many projects. A project has an owner_id.
I can't seem to configure the relationship correctly. In my user model, I have:
/**
* Get the projects associated with the user.
*/
public function projects()
{
$this->hasMany('\App\Project', 'owner_id', 'id');
}
In my project model, I have:
/**
* Get the owner associated with the user.
*/
public function owner()
{
$this->belongsTo('\App\User', 'id', 'owner_id');
}
But calling either $user->projects() or $project->owner() returns null.
How should I configure my non-standard relationship keys?
You forgot to return the method:
public function projects()
{
return $this->hasMany('\App\Project', 'owner_id');
}
Do this also for the second one:
public function owner()
{
return $this->belongsTo('\App\User', 'owner_id');
}

Get posts from multiple users in Laravel

In my site, I have a table of Users. Users can follow each other. A user can created any number of Post's.
I want to be able to see the most recent Post's from the users I've followed.
Currently my models are defined like this:
User Model:
class User extends Authenticatable
{
public function followers(){
return $this->hasMany('App\Follower', 'following');
}
public function following(){
return $this->hasMany('App\Follower', 'id');
}
public function posts(){
return $this->hasMany('App\Post', 'createdby');
}
}
Follower Model:
class Follower extends Model
{
public function postsFollowing(){
return $this->hasMany('App\Post', 'createdby', 'following');
}
}
Post Model:
class Post extends Model
{
public function user(){
return $this->belongsTo('App\User', 'createdby', 'id');
}
}
My tables are as such:
Table Name, column names
User id, name
Follower id, following
Post id, created_by
In the Follower table, id represents the user, and following represents the user being followed. If user 3 follows user 537, then id = 3, following = 537. Hope that made sense.
What I've tried:
User::following()->posts - doesn't work because
User::following() returns an Eloquent Collection object. You have
to loop through this
Looping through my followed users to get their Post's - This
doesn't work either since I want to get the top n entries sorted by
date.
Update #1
Follower Model (Updated)
class Follower extends Model
{
public function followingPosts(){
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'following', 'createdby', 'id'
);
}
}
Controller
$user = Auth::user();
$posts = $user->followingPosts;
I updated followingPosts() in the Follower class with the above. The result: $posts is null
Update #2
I moved the followingPosts() to the User model:
public function followingPosts(){
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'following', 'createdby'
);
}
Controller:
$user = Auth::user();
$posts = $user->followingPosts;
Now I just get all posts, even from the users I didn't follow.
Your requirement - "Users can follow each other. A user can created any number of Post's. Being able to list recent posts (limited to number) of followers or whom user is following".
You can define many-to-many relationship on the User Model (Many-To-Many relationship on self - User Model).
Create two Pivot tables
Follower-User Pivot Table
class CreateFollowerUserPivotTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('follower_user', function (Blueprint $table) {
$table->integer('follower_id')->unsigned();
$table->foreign('follower_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
$table->primary(['follower_id', 'user_id']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('follower_user');
}
}
Following-User Pivot Table
class CreateFollowingUserPivotTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('following_user', function (Blueprint $table) {
$table->integer('following_id')->unsigned();
$table->foreign('following_id')->references('id')->on('users')->onDelete('cascade');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->timestamps();
$table->primary(['following_id', 'user_id']);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('following_user');
}
}
Then define the relationships in your User Model
class User extends Model
{
public function followers()
{
return $this->belongsToMany(User::class, 'follower_user', 'user_id', 'follower_id')->withTimestamps();
}
public function following()
{
return $this->belongsToMany(User::class, 'following_user', 'following_id', 'user_id' )->withTimestamps();
}
//Assuming posts table has user_id as foreign key
public function posts()
{
return $this->hasMany(Post::class);
}
//Assuming posts table has user_id as foreign key
public function recent_posts()
{
return $this->hasMany(Post::class)->take(10)->orderBy('created_at', 'desc');
}
}
Now to get who a given user is following
//Say for example we take the logged in user
$user = User::with('following.recent_posts')->whereEmail(auth()->user()->email);
foreach($user->following as $following)
{
$posts = $following->recent_posts;
}
Hope this is what you are trying to accomplish.
You can use has-many-through for this as:
public function followingPosts()
{
return $this->hasManyThrough(
'App\Post', 'App\Follower',
'follow', 'createdby', 'id'
);
}
Then you can access the posts as:
$user->followingPosts; // returns collection of post model
Note: Assuming you have a follow column in Follower table.

Resources