This this the structure that I currently use
Model User :
class User extends Authenticatable implements MustVerifyEmail
public function groups()
{
return $this->belongsToMany('App\Group')
->withTimestamps();
}
Model Group :
class Group extends Model
public function users() {
return $this->belongsToMany('App\User')
->withTimestamps();
}
Pivot table :
Schema::create('group_user', function (Blueprint $table) {
$table->integer('group_id');
$table->integer('user_id');
$table->integer('role_id')->nullable();
$table->timestamps();
});
I would like to get all the users who are in same groups of the current user and don't return duplicate users (a user can be in multiple groups).
The ideal functions would be :
$user->contacts()
// Return an object with (unique) contacts of all current user groups
AND
$user->groupContacts($group)
// Witch is the same as $group->users
// Return an object with all the users of the current group
There is the not functional function i'm working on (Model User.php) :
public function contacts()
{
$groups = $this->groups;
$contacts = new \stdClass();
foreach ($groups as $key => $group) :
$contacts->$key = $group->users;
endforeach;
return $contacts;
}
I'm really not an expert with table structures so if there is a better way to do this, i'm only at the beginning of this personnal project so nothing is written in stone.
Optional stuffs :
Exclude current user from the list
With roles from pivot table
With softdelete
You can try something like this on your User model
public function contacts()
{
// Get all groups of current user
$groups = $this->groups()->pluck('group_id', 'group_id');
// Get a collection of all users with the same groups
return $this->getContactsOfGroups($groups);
}
public function groupContacts($group)
{
// Get a collection of the contacts of the same group
return $this->getContactsOfGroups($group);
}
public function getContactsOfGroups($groups)
{
$groups = is_array($groups) ? $groups : [$groups];
// This will return a Collection Of Users that have $groups
return \App\User::whereHas('groups', function($query) use($groups){
$query->whereIn('group_id', $groups);
})->get();
}
Related
Hello Actually am trying to create an app in which every project has some users i.e ProjectMembers.
here is project model with TeamMembers function.
class Project extends Model
{
use HasFactory;
function TeamMembers(){
return $this->hasMany(ProjectMember::class);
}
}
project members table schema.
Schema::create('projects_members', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('project_id')->nullable();
$table->unsignedBigInteger('user_id')->nullable();
$table->foreign('project_id')->references('id')->on('projects');
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
Now for updating project members i have to first delete relationships from Project members and then saving new one. because i have added multiselect dropdown. $request->team_members have type array.
public function update(Request $request, $id)
{
// return $request;
$project = Project::findorfail($id);
$project->name = $request->project_name;
$project->details = $request->details;
$project->start_date = $request->start_date;
$project->end_date = $request->end_date;
$members = $request->team_members;
ProjectMember::where('project_id', $id)->delete();
$this->update_project_memebers($members, $project);
return redirect('/projects');
}
public function update_project_memebers($members, $project){
foreach ($members as $member_id) {
$project_member = new ProjectMember();
$project_member->project_id = $project->id;
$project_member->user_id = $member_id;
$project_member->save();
}
}
here am deleting cuz if someone created project with two members and when the he/she want to update then he/she can remove one member from multiselect then i have to delete relationship cuz he/she selected only one user.
I don't think it's a good practice, so can i achieve this same func. with another way?
thankyou.
First of all please make a proper naming convention of pivot tabel according to laravel and same for the model name too.
As of now the solution is
define relation as
Project
public function teamMembers()
{
return $this->belongsToMany(ProjectMember::class, 'projects_members', 'project_id', 'member_id');
}
ProjectMember
public function projects()
{
return $this->belongsToMany(Project::class, 'projects_members', 'member_id', 'project_id');
}
So now instead of deleting use sync() method. AS
$project->teamMembers()->sync($members);
Important docs,
https://laravel.com/docs/8.x/eloquent-relationships#syncing-associations
I wanted to implement a follow system where a User can follow Comment, Category, Post and more. I have tried using Laravel Polymorphic relations for this but could not wrap my head around it. If someone can guide me it will be great.
Here is what I have tried.
User Model
public function categories()
{
return $this->morphedByMany(Category::class, 'followable', 'follows')->withTimestamps();
}
Category Model
public function followers()
{
return $this->morphMany(Follow::class, 'followable');
}
Follow Model
public function followable()
{
return $this->morphTo();
}
public function user()
{
return $this->belongsTo(User::class);
}
Follow migration
Schema::create('follows', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('user_id');
$table->morphs('followable');
$table->timestamps();
});
How can I get the all the categories, comments followed by a user. Also how I can get the Followers of a Cateogry or Commnets etc.
Please help.
You dont't need Follow model.
All you need is pivot table like so
followable
user_id - integer
followable_id - integer
followable_type - string
add folowers method to all your classes which you need to follow
For example
Category Model
public function followers()
{
return $this->morphToMany(User::class, 'followable');
}
Then in User Model
public function followers()
{
return $this->morphToMany(User::class, 'followable');
}
public function followedCategories()
{
return $this->morphedByMany(Category::class, 'followable')->withTimestamps();
}
public function followedComments()
{
return $this->morphedByMany(Comment::class, 'followable')->withTimestamps();
}
public function followedPosts()
{
return $this->morphedByMany(Post::class, 'followable')->withTimestamps();
}
// and etc
public function followedStuff()
{
return $this->followedCategories
->merge($this->followedComments)
->merge($this->followedPosts);
}
Then you can reach your goal by accessing to followers of certain category, comment or post or whatever you wish(if it followable of courcse)
For example:
$folowers = $category->folowers;
// will return all followers this category
$all = $user->followedStuff();
// will return collection of all things followable by the user
I have the following model relationships. If a user logs in as an employee, I want them to be able to get a list of employees for a their company and the roles they have been assigned:
class User {
// A user can be of an employee user type
public function employee()
{
return $this->hasOne('App\Employee');
}
//
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
class Employee {
// employee profile belong to a user
public function user()
{
return $this->belongsTo('App\User');
}
// employee belongs to a company
public function company()
{
return $this->belongsTo('App\Company');
}
}
class Company {
public function employees()
{
return $this->hasMany('App\Employee');
}
}
But the following query doesnt work. I get error Column not found: 1054 Unknown column companies.id in WHERE clause:
$employee = Auth::user()->employee;
$companyEmployees = Company::with(['employees.user.roles' => function ($query) use ($employee) {
$query->where('companies.id', '=', $employee->company_id)
->orderBy('users.created_at', 'desc');
}])->get();
The users and the employees table have a one to one relationship.
All employees have a base role type of employee in addition they may also have other roles such as manager, supervisor etc.
How do I write a query that gives me a company with all its employees and their roles?
I've tried to add a hasManyThrough relation to the Company model but that doesn't work either?
public function users()
{
return $this->hasManyThrough('App\User', 'App\Employee');
}
I think you're ring to get a list of coworkers for the current user and eager load the user and role?
$employee = Auth::user()->employee;
$companyEmployees = Company::with(['employees.user.roles')->find($employee->company_id);
Or perhaps:
$companyEmployees = Company::find($employee->company_id)->employees()->with('user.roles')->get();
$sorted = $companyEmployees->sortBy(function($employee){ return $employee->user->created_at; });
That might be a more direct route. Is your employee id in the user table or vice versa? The eloquent relationships are easy to set backwards.
Users::select('table_users.id')->with('roles')->join('table_employes', function($join) use ($employee) {
$join->on('table_employes.user_id','=','table_users.id')->where('table_employes.company_id', '=', $employee->company_id);
})->orderBy('tables_users.created_at')->get();
1. Create relationship for database table columns in migrtaion :
User Role
$table->foreign('user_id')->references('id')->on('users');
Users
$table->increments('id');
2. Create a model for each database table to define relationship
User.php (model)
public function userRoles()
{
return $this->hasOne('App\UserRoles', 'user_id', 'id');
}
Userroles.php (model)
public function user()
{
return $this->belongsTo('App\User', 'user_id', 'id');
}
3. Let controller handle database calls recommended to use REST api
Controller
use App\User;
use App\UserRoles;
class UserController extends Controller
{
public function index()
{
return User::with('userRoles')->orderBy('users.created_at', 'desc')->paginate(50);
}
}
I seen to of got tangled in Laravel's ORM with the following:
Scenerio: All Users have a Watchlist, the Watchlist contains other Users.
I can't seem the get the relationships to work correctly as they are cyclical, so far I have the following:
class UserWatchlist extends Model
{
protected $table = 'UserWatchlist';
public function Owner() {
return $this->belongsTo('App\User');
}
public function WatchedUsers() {
return $this->hasMany('App\User');
}
}
Schema::create('UserWatchlist', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('Users')->onDelete('cascade');
$table->integer('watched_id')->unsigned();
$table->foreign('watched_id')->references('id')->on('Users')->onDelete('cascade');
$table->timestamps();
});
class User extends Model
{
public function Watchlist() {
return $this->hasOne('App\UserWatchlist');
}
public function WatchedBy() {
return $this->belongsToMany('App\UserWatchlist');
}
}
It is not pulling through the correct in formation i'm expecting. Am I missing something fundamental?
Since UserWatchlist is a pivot table, i suppose you are facing a many to many relationship with both the elements of the relation being the same model (User)
If that is the case, you should not build a model for the pivot table UserWatchlist but all you have to do is to set the relation between the users through the pivot table:
class User extends Model
{
//get all the Users this user is watching
public function Watchlist()
{
return $this->belongsToMany('User', 'UserWatchlist', 'user_id', 'watched_id' );
}
//get all the Users this user is watched by
public function WatchedBy()
{
return $this->belongsToMany('User', 'UserWatchlist', 'watched_id', 'user_id' );
}
}
Check here for more info on many-to-many relationship
I have 3 models: User, Role, Tool where each user could have many roles, and each role could have many tools.
The many to many relationships work well in each case. I can access:
User::find(1)->roles
Tool::find(1)->roles
Role::find(1)->tools
Role::find(1)->users
My tables are:
users
id
name
roles
id
name
tools
is
name
role_user
id
role_id
user_id
role_tool
id
role_id
tool_id
In each model:
//In User Model
public function roles()
{
return $this->belongsToMany('Rol');
}
//In Role Model
public function users()
{
return $this->belongsToMany('User');
}
public function tools()
{
return $this->belongsToMany('Tool');
}
//In Tool Model
public function roles()
{
return $this->belongsToMany('Rol');
}
I need to get all the tools of a single user like: User::find(1)->roles()->tools. How can I do that?
Get all the roles of the user, then in a loop you get all tools of the role and merge them to an array where you store all tools.
$tools = array();
foreach(User::find(1)->roles as $role)
$tools = array_merge($tools, $role->tools->toArray());
This runs a query for every iteration, so for better performance you should use eager loading.
$tools = array();
foreach (User::find(1)->load('roles.tools')->roles as $role) {
$tools = array_merge($tools, $role->tools->toArray());
}
Now you can place this to a function called tools() in your User model.
public function tools()
{
$tools = array();
foreach ($this->load('roles.tools')->roles as $role) {
$tools = array_merge($tools, $role->tools->toArray());
}
return $tools;
}
You can call it like this: User::find(1)->tools().
I don't think that the framework has a better solution. One other method is to use the Fluent Query Builder and create your own query but I don't see how that would be better.
Define a hasManyThrough relationship in User::find(1)->roles()->tools
class User extends Eloquent {
public function tools()
{
return $this->hasManyThrough('Tool', 'Role');
}
}
Then you can access straight forward:
$user->tools