How to perform a has many through statement using laravel eloquent? - laravel

Say i have three tables users,users_groups and groups.How can i get the user's groups through the users_groups table?
class User extends Eloquent {
protected $table = 'users';
}
class Groups extends Eloquent {
protected $table = 'groups';
}
class Usergroups extends Eloquent {
protected $table = 'users_groups';
}

As per your request, I've put together a simple example for your specific use case:
The Tables:
Eloquent suggests creating 3 database tables in such a scenario: users, groups and group_user.
The Laravel documentation states that:
The group_user table's name is derived from the aplhabetical order of the related model names.
The group_user table should contain the columns user_id and group_id which will contain the primary keys of group and user entries. The group_user table is what's known as a pivot table.
This conforms to 3NF (if you're interested).
The Models:
The User model should contain the following code:
<?php
class User extends Eloquent {
//...Other code…
public function groups()
{
return $this->belongsToMany('Group');
}
}
The Group model should contain the following code:
<?php
class Group extends Eloquent {
//...Other code…
public function users()
{
return $this->belongsToMany('User');
}
//...Other code…
}
You do not need a UserGroup model as found in your question.
Usage:
In order to retrieve all groups to which a particular user belongs you would do the following:
$user = User::find($user_id);
$user_groups = $user->groups();
Similarly in order to retrieve all users belonging to a particular group you would do the following:
$group = Group::find($group_id);
$group_users = $group->users();
In order to add/remove a user to a group would would do the following:
$user = User::find($user_id);
//Add a user
$user->groups()->attach($group_id);
//Detach a user
$user->groups()->detach($group_id);
Other:
You should read more in the Laravel docs about pivot tables here and about defining foreign keys (for your pivot table) in your migrations here.
I hope that helps!

Related

How to override laravel model query?

I have a main model called User that returns all the users of the application.
There is a table called invites which manages the users invited to access the invitee panel. The invites table is thus linked to users:
So we have a general User model which handle all the users, and other two types of users:
Patient: user who invited the tenant
Tenant: user who has access to a list of associated patients
What I am trying to do is to fetch a patient list of a certain tenant (logged in user) using the eloquent relationship system, so I don't have to write a query for the join every time. Is it possible to do this?
At the moment, I tried this:
class Patient extends User
{
use HasFactory;
//protected $table = 'users';
public function getList()
{
return $this->belongsToMany(User::class, 'invites', 'id', 'user_id');
}
}
but of course this relationship not works because the query that should execute must be this:
SELECT u.*
FROM users u
INNER JOIN invites i ON i.user_id = u.id
WHERE i.tenant_id = 1
where id is the reference of the current user logged in which I retrieve using laratrust auth: auth()->user()->id.
Would be possible to return all the patients associated to the logged in user automatically? So simply calling:
Patient::query();
How can I achieve this?
To achieve that you should define relation and reverse many to many relation:
in your user model:
class Tenant extends User
{
use HasFactory;
protected $table = 'users';
public function patients()
{
return $this->belongsToMany(User::class, 'invites', 'tenant_id', 'user_id');
}
}
And in Patient model define reverse many to many relation by reverse belongToMany params :
class Patient extends User
{
use HasFactory;
protected $table = 'users';
public function tenants()
{
return $this->belongsToMany(User::class, 'invites', 'user_id', 'tenant_id');
}
}
To use the auth id for each model you have 2 option:
Option 1:
add column in users table that named user_type wich have type enum('tenant','patient') and depend user type use the appropriate model
Option 2:
by using custom auth guards , take look to this article
https://www.codecheef.org/article/laravel-8-login-with-custom-guard-example

How to add additional column relationship in pivot table in Laravel

Version: Laravel 5.4
I have 3 Models
Model: Employee
protected $fillable = ['name'];
public function emails(){
return $this->belongsToMany('App\Email')->using('App\EmailEmployee');
}
Model: Email
protected $fillable = ['username'];
public function employees(){
return $this->belongsToMany('App\Employee')->using('App\EmailEmployee');
}
Every Employee has many email access and emails allocates to many employees. But I have another column in email_employee table
email_id (emails table)
employee_id (employees table)
assigned_by (employees table)
how to make relation of assigned_by column with employees table
Pivot Model
use \Illuminate\Database\Eloquent\Relations\Pivot;
class EmailEmployee extends Pivot{
public function assignedBy(){
return $this->belongsTo('App\Employee');
}
}
I tried
$email = Email::find(1);
dd($email->employee[0]->pivot->assignedBy);
But not working
Custom Intermediate Table Model
To solve your problem, you should look to use the ->using() method on the belongsToMany method.
The subsection "Defining Custom Intermediate Table Models" in this link briefly describes this. eloquent-relationships#many-to-many
You basically create a model for the pivot table so that you can define additional relations to it.
You can still access data from Blade and Controllers the way you are now as Laravel will still deal with the relationship for you. However, you can access the pivot table with ->pivot and as you have told laravel to use a model for the pivot table, you can also access all the relationship defined functions from that model.
Example:
Employee
class Employee extends Model
{
protected $fillable = ['name'];
public function emails(){
return $this->belongsToMany('App\Email')
->using('App\PivotModel');
}
}
Email
class Email extends Model
{
protected $fillable = ['username'];
public function employees(){
return $this->belongsToMany('App\Employee')
->using('App\PivotModel');
}
}
PivotModel
class EmailEmployee extends Pivot
{
public function assignedBy(){
return $this->belongsTo('App\Employee','assigned_by');
}
}
Be Sure to extend Pivot on the pivot model and not Model
Now you can just do:
$user->emails()->first()->pivot->assignedBy
The reason for the ->first() is that you have a many to many, meaning that you will be getting a collection of emails assigned to the user. You would normally loop through them but for this example, simply selecting the first will do the same.
If you just want the column value and not the relationship value, then add ->withPivot('assigned_by') which will allow you to access the value directly.
If you are wanting to audit when the assignment was made, then you may also want to add ->withTimestamps() if your pivot table has timestamps included, so that you can access those too.
Changes in Pivot model
Pivot Model
use \Illuminate\Database\Eloquent\Relations\Pivot;
class EmailEmployee extends Pivot{
public function assignedBy(){
return $this->belongsTo('App\Employee','assigned_by');
}
}
You can use an custom pivot model
EmailEmployee
class EmailEmployee extends Pivot
{
public function giver()
{
return $this->belongsTo('App\Employee');
}
}
Employee
class Employee extends Model
{
public function emails(){
return $this->belongsToMany('App\Email')->using('App\EmailEmployee');
}
}
Email
class Email extends Model
{
public function employees()
{
return $this->belongsToMany('App\Employee')->using('App\EmailEmployee');
}
}
So you can access giver by $email->pivot->giver;

laravel use field in Eloquent model from another table

I have a model named "User". I want "Password" field from Eloquent from another table, and when user calls the user::all() method, all selected fields from different tables come in the result.
How can i do that?
Results are not displayed in with() .
my problem solved by using $appends in Eloquent model .
my code :
class User extends Eloquent {
protected $table = 'user';
protected $attributes = ['password'];
protected $appends = ['password'];
public function getPasswordAttribute()
{
return $this->getPAsswordMethod();
}
}
Your question is extremely board and borderline unanswerable but I will give you a board solution.
You are able to establish relationships to other tables via the Model objects you create. Lets pretend you have a Password table which belongs to the User.
User model:
public function password()
{
return $this->hasOne(Password::class, 'FK', 'PK');
}
You can now do User::with('password')->get(['FieldName']); and this will give you all of the passwords which have the above relationship to a user.

Cannot access Collection::$items

I've got some troubles with an eloquent query.
Users have many feeds and feeds have many items.
I need to get all the items that belongs to the feeds of the user order by date.
I've got a pivot table:
feed_user
----------
- id
- feed_id
- user_id
and relationships are defined like this in my models:
class UsersController extends BaseController {
public function feeds() {
return $this->hasMany('feed');
}
class Feed extends \Eloquent {
protected $fillable = [];
public function users() {
return $this->belongsToMany('User');
}
public function items() {
return $this->hasMany('Item');
}
class Item extends \Eloquent {
protected $fillable = [];
public function feed() {
return $this->belongsTo('Feed');
}
But when I do this query...
Auth::user()->feeds->items->orderBy('date', 'DESC')->get();
It returns this error:
Cannot access protected property Illuminate\Database\Eloquent\Collection::$items
There are a couple issues here.
First, the relationship on User model is not correct. A hasMany relationship is one half a one-to-many relationship. This would assume that a feed belongs to one user, and that the feed table has the user_id field. A many-to-many relationship is defined by adding a belongsToMany relationship on both models. So, a user belongsToMany feeds, and a feed belongsToMany users.
class User extends \Eloquent {
public function feeds() {
return $this->belongsToMany('feed');
}
}
Next, the error you're seeing is because Auth::user()->feeds returns a Illuminate\Database\Eloquent\Collection object. You're then trying to access the items attribute on the Collection, which is protected and throws the error you're seeing.
Finally, since Laravel does not use joins for relationships, you cannot order a query by a field on a related table without manually doing the join yourself.
Try using eager loading:
Auth::user()->with('feeds.items')->orderBy('date', 'DESC')->get();

Laravel 4 - Display username based on ID

I have a posts and a users table.
In the posts table, i have a posts_author which is the ID of the user from the users table.
Is there an easy way to display the email address of the user, which is in the users table?
Cheers,
As long as you've set your relationships up it should just be a simple query.
http://laravel.com/docs/eloquent#relationships
Look at the one to many relationships.
(1 User, Multiple posts)
Remember to set the inverse of the relationship up also
If your model has the right relationships then should be as simple as $post->author->email().
You must tweak the author relationship because Eloquent assumes the key will be named author_id.
// Post
public function author() {
return $this->belongsTo('Author', 'posts_author');
}
// Author
public function posts() {
return $this->hasMany('Post');
}
Remember to use eager loading in case you are retrieving emails from more than one post object, or you will end up with n+1 queries.
Providing that you've configured the relationships properly, it should be pretty easy.
Post Model:
class Post extends Eloquent
{
protected $table = 'posts';
public function author()
{
return $this->belongsTo('User', 'posts_author');
}
}
Then User Model:
class User extends Eloquent
{
protected $table = 'users';
public function posts()
{
return $this->hasMany('Post', 'posts_author');
}
}
Then when loading the post you can do the following.
$post = Post::with('author')->find($id);
This will tell Eloquent to join on the users table and load the user data at the same time. Now you can just access all of the user information like this:
$post->author->username;
$post->author->email;
$post->author->id;
// etc etc
Obviously this is just a skeleton, but the assumption is that you have the rest setup.

Resources