Is it possible to dynamically set model for Eloquent Relationships? - laravel

I have 2 user roles. In database I have own profile tables for both of roles ( model_profiles and client_profiles). Is there any way to set related Profile model dynamically? I've tried this:
//User model:
public function profile(){
return $this->role == 'model' ? $this->hasOne('App\Models\Model\Profile') : $this->hasOne('App\Models\Client\Profile');
}
But in this case I can't use some Eloquent methods like User::with('profile')->whereIn('id', [1,2,3])->get(); because $this->role is null until user model is loaded.
Is there any way to use Profile model based on user role and don't lose any Eloquent query methods?

You can use Polymorphic relationships (More Information)

Related

Laravel 9.* belongsToMany

I have DB structure:
user
user_id
office
office_id
property
property_id
office_user
office_user_id
office_id
user_id
office_user_property
office_user_id
property_id
Is there way to acess to Property model from User model via belongsToMany?
What you are looking for is the hasManyThrough
(https://laravel.com/docs/9.x/eloquent-relationships#has-many-through), but it only work for one connection in between, and you have two.
What you could do is define a hasManyThrough relation between user and office_user_property and define a hasOne relation between office_user_property and property
belongsToMany refers to Many To Many. This relationship for your case defines that has many properties, while a property is owened by many users. In a nutshell three database tables can be used to define this relationship. properties table, users table, and user_property table. where the user_property table contains user_id and property_id columns.
In the user model, the relationship can be defined as:
/.../
public funciton properties(){
return $this->belonsToMany('App\Property');
}
To access properties for a user:
$user = App\User::find(1);
foreach ($user->properties as $property) {
//
}
Ref: Laravel 5.2 Docs

create whare clause on model attribute

How to create where clause on laravel model attribute
I have the following relation between user and books. where user hasMany books and the book model belongs to single user
I want to select all books with pages > 100 that belongs to user_id = 2
I use laravel 5.2 with mysql and defined a model for User and another model for Book
When I want to get all books for specific user, I user
return User::find(2)->books;
and this works fine. But I want to get the books where pages > 100. I use:
return User::find(2)->books->where([['pages', '>', 100], ['chapters', '>', 3]]);
but doesn't work
User model:
class User extends Authenticatable
{
public function books()
{
return $this->hasMany('App\Book');
}
}
Book model
class Book extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
}
I expect to get all the books with user_id = 0 and pages > 100 and chapters > 3
You'll want to access the relationship method books(), not the property books. Some quotes from the documentation:
Querying Relations
Since all types of Eloquent relationships are defined via methods, you may call those methods to obtain an instance of the relationship without actually executing the relationship queries. In addition, all types of Eloquent relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database.
Relationship Methods Vs. Dynamic Properties
If you do not need to add additional constraints to an Eloquent relationship query, you may access the relationship as if it were a property.
Example solution:
return User::find(2)
->books()
->where([['pages', '>', 100], ['chapters', '>', 3]])
->get();
Note that we're using books() to access the HasMany relationship, and using the where() query builder method on it to create a constraint. Then, in order to complete and execute the query, we call get() at the end. If you don't, you'll just return the daisy chained query builder.
Your previous code might not error, because the value returned from User::find(2)->books will be a Collection object, which actually has a where() method. It just likely didn't have any matches because of the array format you passed.
To add where clouses on related models, we can use whereHas() function.
Since you want Books, Start from Book model.
$books = Book::where([
['pages', '>', 100],
['chapters', '>', 3],
])
->whereHas('user', function($query) {
$query->where('id', 2);
})
->get();

Invalid argument supplied for foreach() in laravel when use Eloquent: Relationships

I wanna get the class name of a user via the user ID. When I input the ID of a user so I will wanna get the class name. I have three tables such as users table, classes table, and class_users table. The class_users table is born from two users table and classes table.
A users table has an id, name, email, password.
A classes table has an id, class_code, class_name.
A class_users table has an id, class_id, user_id
And this problem relates to Eloquent Relationships.
Thank you for help.
My Route:
Route::get('/find_classes/{id}','StudentController#find_classes');
My Controller function:
public function find_classes($id)
{
$users = User::find($id);
foreach($users->classes as $class)
{
echo $class->name . '<br';
dd($class);
}
}
My User Model:
public function classes()
{
return $this->belongsTo('App\Classes','class_users','user_id','class_id');
}
Looks like you might have the wrong relationship set up on your User model. You have a one to many set up, but your DB is setup to handle a many to many. I suggest you change your User model relationship:
public function classes()
{
return $this->belongsToMany('App\Classes');
}
Note, you may need to name the FK on that relation, as I see you have class_id on the table, but your actual class is named 'Classes'. Check through your relationships to ensure this is explicit on the FK where it doesn't follow Laravel convention exactly.
With this relationship, your foreach loop should work. It would be a good idea for efficiency, as mare96 noted, to eager load the classes on the $users collection when you query:
$users = User::with('classes')->find($id);

making model relationship to user, user can only access its own data

i have 2 main models and some child models with relationController to main models, now i need to add user id to both main and child models so user can only access its own data since users data stay on the same table.
i create belongsToMany relationship from user.php to the models and vice versa with pivot table but nothing happen
i have no idea how to do this since i need simplified database management in case i need to do migration..
can someone share your experience on this..
I can suggest you that you just add user_id [for Backend => backend_users_id ] to models which data you want access to owner only.
now in main model you can define belongsTo relation and in user you can define hasMany relation
main model relationship [if you want to restrict the user in backend side then you need to add backend user relation and same in backend user model]
class MainModel extends Model
{
// Adding relation to user model
public $belongsTo = [
'user' => 'RainLab\User\Models\User',
'backend_users' =>'Backend\Models\User' // for Backend
];
}
adding a relation to the user model [ you need to put this code in your plugin's boot method ]
// Extending User Model
\RainLab\User\Models\User::extend(function($model) {
$model->hasMany['mainmodel'] = ['HardikSatasiya\Plugin\Models\MainModel'];
});
// for Backend users
\Backend\Models\User::extend(function($model) {
$model->hasMany['mainmodel'] = ['HardikSatasiya\Plugin\Models\MainModel'];
});
Now access data [ Front-end side ]
// Returns the signed in user
$user = \Auth::getUser();
dd($user->mainmodel); // it will return collection of related mainmodels
// it will return related data and now its filter by owner
dd($user->mainmodel[0]->otherRelatin);
// for Backend users
// Returns the signed in user
$user = \BackendAuth::getUser();
dd($user->mainmodel); // it will return collection of related mainmodels
// it will return related data and now its filter by owner
dd($user->mainmodel[0]->otherRelatin);
Example filter data in listview based on logged in admin user [ OctoberCMS do not give such functionality out of the box, you can not hide a portion of data records you can hide entire menu or all records based on rights and roles but can not hide partial records ]
public function listExtendQuery($query)
{
$user = \BackendAuth::getUser();
$query->where('backend_users_id', $user->id);
}
to add backend_users_id you can use this code
class MainModel extends Model {
public function beforeSave()
{
$user = \BackendAuth::getUser();
$this->backend_users_id = $user->id;
}
}
if any doubt please comment.

Eloquent ORM optional Relationship

just a short question, I'm new to Eloquent and the relationships.
I want to keep my database clean so I created a User-Model and a Administrator-Model.
Now I'm stucked with the relationship... What I wanna do is the following:
On the users-table I have an attribute called account_type.
If that one is set to admin or administrator I want to "implement" the Administrator-Model to the User-Model.
Am I doing a totally wrong approach here or is there a easy "laravel-style" solution for this?
Class Administrator cannot be implemented in User, because it's not an interface, If you want to use Administrator class, make a relation in User model
public function admin()
{
return $this->hasMany('Administrator');
}
then,
$users = User::whereHas('admin', function($q) {
$q->where('account_type', 'administrator'); // or admin
})->get();
make belongsTo relation in Administrator if you want
reference link: Eloquent ORM

Resources