Laravel relationship between multiple models - laravel

I have the folowing models User, Test, Attempts.
User has access to tests (many-to-many)
public function tests(){
return $this->belongsToMany('App\Test');
}
I have table attempts with folowing columns:
- user_id
- test_id
I need to obtain all user tests with related attempts.
How can I acquire that by using eager loading?
Thanks.

Ensure firstly that the reverse side of the relationship is setup so your Tests Model will require a belongsToMany relationship with Users like so:
public function Users(){
return $this->belongsToMany('App\User');
}
You can specify the table name for the pivot table by passing an additonal argument to the belongsToMany like so :
public function Users(){
return $this->belongsToMany('App\User', 'attempts');
}
To eager load columns from a pivot you can make use of the withPivot method

Related

Laravel BelongsTo relation - where on instance attribute

I have the following model:
class Order extends Model
{
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'shipping_email_address', 'email_address')
->where('customer_id', $this->customer_id);
}
}
Now when I call Order::with('user')->get(), it doesn't load the users.
I can access the user just fine when using Order::first()->user.
Is it possible to eager load a relationship with a where clause on a model instance attribute (like $this->customer_id)? Or is there another way to make a relationship based on two columns?
You can do this :
Your relation :
public function user()
{
return $this->belongsTo(User::class);
}
Then you can make query like this :
$userId = 5;
$result = Order::whereHas('user',function($q) use ($userId){
return $q->where('id',$userId);
});
Reply to your comment:
Having this relation :
public function user()
{
return $this->belongsTo(User::class);
}
Use this :
Order::with('user')->get()
This will retrieve all orders with its users. If you have some problem on that query then you have a wrong relationship. Make sure you have a foregin key in Orders table, if you dont espcify some foreign key on eloquent relationship, eloquent will understand than foreign key is : user_id, if not, especify putting more arguments to this function :
$this->belongsTo(User::class,...,...);
With function make join according to relationship configuration, just make sure the relation is ok. And all work fine !
If you want to keep your current flow, i would do it like so. Thou the josanangel solution is most optimal.
When getting orders include them using with. All these are now eager loaded.
$orders = Order::with('user');
Now utilize eloquent getters to filter the user by customer_id. This is not done in queries, as that would produce one query per attribute access.
public function getUserByCustomerAttribute() {
if ($this->user->customer_id === $this->customer_id) {
return $this->user;
}
return null;
}
Simply accessing the eloquent getter, would trigger your custom logic and make what you are trying to do possible.
$orders = Order::with('user')->get();
foreach ($orders as $order) {
$order->user_by_customer; // return user if customer id is same
}
Your wrong decleration of the relationship here is what is making this not function correctly.
From the laravel's documentation:
Eloquent determines the default foreign key name by examining the name of the relationship method and suffixing the method name with a _ followed by the name of the parent model's primary key column. So, in this example, Eloquent will assume the Post model's foreign key on the comments table is post_id.
in your case the problem is that laravel is searching for the User using user_id column so the correct way to declare the relation is
public function user()
{
return $this->belongsTo(User::class, 'customer_id'); // tell laravel to search the user using this column in the Order's table.
}
Everthing should work as intended after that.
Source: documentation

Check in relationship if a column is true, Laravel

I have 2 tables: roles & users.
In users I have role_id, and I want to check if that role has a column "access_admin_area" on true. If true, I am using a middleware.
Gate::define('admin', function ($user) {
return !empty($user->roles()->where('access_admin_area', true)->first());
});
From User model:
public function roles()
{
return $this->hasOne(Role::class);
}
SQLSTATE[42703]: Undefined column: 7 ERROR: column roles.user_id does not exist↵LINE 1: select * from "roles" where "roles"."user_id" = $1 and "role..
The error describes the issue pretty nicely here - the hasOne relationship method inside your User model expects the Role table row to have a user_id column that specifies a foreign key referencing the user table id column.
If I was you, I'd rather use hasMany relationhip between your User and Role model in this use case, since I expect your users and roles should have a many-to-many relationship
check out the many-to-many relationship eloquent and database structure in the laravel documentation https://laravel.com/docs/7.x/eloquent-relationships#many-to-many
Did you checked like this way:
public function roles()
{
return $this->hasOne('App\Role', 'id' , 'role_id');
}
You should change hasOne to belongsTo
then you can a simpler way to save yourselve from many where clauses in your controlleer is by creating another relationship with eg name as rolewithadminaccess
public function roles()
{
return $this->belongsTo(Role::class);
}
public function rolewithadminaccess()
{
return $this->roles()->where('access_admin_area', true)->limit(1);
}
then you can do this in your controller
return $user->rolewithadminaccess;

Eloquent hasOne vs belongsTo degenerate to same function if both keys are specified?

For the case of a one-to-one relationship, if I fully specify the keys in the method calls, is there a difference between hasOne and belongsTo relationships? Or, asked differently, if I used hasOne on both sides of the relation, would it be the same result?
Yes it works for some cases to specify the keys and make the relation work. And with some cases I mean mainly retrieving results. Here's an example:
DB
users profiles
----- --------
id id
etc... user_id
etc...
Models
Using "wrong" relations with hasOne twice
class User extends Eloquent {
public function profile(){
return $this->hasOne('Profile');
}
}
class Profile extends Eloquent {
public function user(){
return $this->hasOne('User', 'id', 'user_id');
}
}
Queries
Let's say we wanted to get the user from a certain profile
$profile = Profile::find(1);
$user = $profile->user;
This is working. But it's not working how it's supposed to be. It will treat the primary key of users like a foreign key that references user_id in profiles.
And while this may work you will get in trouble when using more complicated relationship methods.
For example associate:
$user = User::find(1);
$profile = Profile::find(2);
$profile->user()->associate($user);
$profile->save();
The call will throw an exception because HasOne doesn't have the method associate. (BelongsTo has it)
Conclusion
Whereas belongsTo and hasOne may behave similar in some situations. They are clearly not. More complex interactions with the relationship won't work and it's nonsense from a semantic point of view.

Laravel Eloquent - Pivot for three tables

I have the following three tables: Permissions, Users, Clients (the admin).
Users to Clients is Many-to-Many. Permissions are created by my administration, not the Client, but the client can then assign what permission each of its user has.
Now, I want to create a pivot table for this. This client_permission_user would take all three id from the tables. Correct? How do I implement this in Eloquent?
In essence, I want to know how I can create a 3-table pivot table and use Eloquent to get my result. For instance, if this was as 2-table pivot (for instance between Client and User), then the pivot table would have been:
client_user
id
client_id
user_id
And my models would have been
Class Client extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
}
Class User extends Eloquent {
public function clients()
{
return $this->belongsToMany('Client');
}
}
So what happens when I have three tables?

Where do i define the juncion table in many-to-many relationship in Laravel's Eloquent?

Here in the eloquent i see the Many to Many relationship:
http://laravel.com/docs/eloquent
I am not using Migrations and made two tables 'users' and a table 'roles' in phpmyadmin.
They both have a 'id' and 'name' column. Now i made the following models:
class User extends Eloquent {
public function roles()
{
return $this->belongsToMany('Role');
}
}
class Role extends Eloquent {
public function users()
{
return $this->belongsToMany('User');
}
}
My first question is. Do is still need to make junction table in phpmyadmin?
And if yes how do i tell Eloquent that (for example 'users_roles') is my junction table?
You must indeed have the table, and you can either follow Laravel conventions or specify it manually in the call to $this->belongsTomany();. Both ways are documented in the Eloquent documentation. The convention is in alphabetical order and singular table names (roles, users, role_user). To specify it in the call you can specify all sorts of things: return $this->belongsToMany('ForeignModel', 'pivot_table', 'local_id', 'foreign_id');
Yes, you still need to create the table.
In your models, add the table name as a second argument to belongsToMany.

Resources