Laravel 4 tables relationship Eloquent - php

I have four tables:
Users: id, username
Roles: id, name
Domains id, title
DomainsAssignedRolesUsers id, role_id, user_id, domain_id
I want to get all user roles for a domain.
I do:
User::find(1)->domains->first()->roles
But i get all domains roles, not only for my user. Help me to get user roles only for the selected domain/
My relations:
// User model:
public function rolesDomain() {
return $this->belongsToMany('Role', 'domainsAssignedRolesUsers', 'user_id', 'role_id');
}
public function domains() {
return $this->belongsToMany('Domain', 'domainsAssignedRolesUsers');
}
// Role model:
public function domains() {
return $this->belongsToMany('Domain', 'domainsAssignedRolesUsers');
}
// Domain model:
public function roles() {
return $this->belongsToMany('Role', 'domainsAssignedRolesUsers', 'domain_id', 'role_id');
}
public function users() {
return $this->belongsToMany('User', 'domainsAssignedRolesUsers', 'domain_id', 'user_id');
}

You want to get all the roles, from a specific domain, in relation with an user?
So this should do the trick:
User::find(1)->rolesDomain()->where('domain_id', $specificID)->get()
But if you want to only get the roles from the first domain for an user.
User::find(1)->domains()->first()->roles()->get();
And if you only want to retrieve the roles for a user.
User::find(1)->rolesDomain()->get()
And if you only want to retrieve all the roles from each domain in relation with an user.
User::find(1)->domains()->with('roles')->get()
Even if Eloquent documentation has a few example, This orm is really intuitive.

Check out Eloquent Triple Pivot (also on Packagist), it sounds like it does exactly what you want.
You'd set up your Models as User, Domain and Role (a User has many Domains and can have a Role in each). Then look at the docs on the Github page (particularly step 6), and you'd define this on your Domain model:
class Domain extends Eloquent {
...
public function getRolesAttribute() {
return $this->getThirdAttribute();
}
}
Then you can simply call
$user = User::find(1);
$domain = $user->domains->first();
// or
$domain = $user->domains->find(73);
$roles = $domain->roles;
// Or the above can be condensed into just...
$roles = User::findOrFail( 1 )
->domains()
->findOrFail( 73 )
->roles;

Related

Laravel pivot consultation

I need advice about my model relationships,
Logic
Group has many users
Group has many admins
User has many groups (as user)
User has many groups (as admin)
Database Structure
Group Table
User Table
Group_Users table (save id of user and id of group)
Group_Admins table (save id of user and id of group)
Relationship Code
User model
public function groupsUser() {
return $this->hasMany(GroupUser::class);
}
public function groupsAdmin() {
return $this->hasMany(GroupAdmin::class);
}
Group model
public function users() {
return $this->hasMany(GroupUser::class);
}
public function admins() {
return $this->hasMany(GroupAdmin::class);
}
GroupUser model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
GroupAdmin model
public function group() {
return $this->belongsTo(Group::class);
}
public function user() {
return $this->belongsTo(User::class);
}
Help wanted
Basically as the relationships between users and groups is many to many normally I shouldn't need models of GroupUser and GroupAdmin and then just using sync() function in order to add/remove users and group id's from those tables.
What is my concerns then?
Normally I use that type of connection when I want input bulk ids into database (let say adding tags to posts, suddenly relate 10 tags id to 1 post) that moment using sync() and removing GroupUser and GroupAdmin models makes sense but in my case as users joins/adds to groups one by one, what do you suggest for this relationships?
Is my current approach makes sense?
Is is better if I remove those GroupUser and GroupAdmin models and add them to user, group model like:
public function users()
{
return $this->hasMany(User::class, 'group_users', 'user_id', 'id');
}
and such so?
What do you think is the best practice?
users and groups is many to many
your tables like this?
users, user_group , groups ?
How about use 'belongsToMany' relation?
Laravel many to many relation
// User model
public function groups() {
return $this->belognsToMany(Group::class);
}
// Group model
public function users() {
return $this->belognsToMany(User::class);
}
And use like.
User::find(1)->groups; // return user 1 groups
User::find(1)->groups()->sync($groupIds); // relate user and groups
Group::find(1)->users; // return group 1 users
If you have role column in your users table, you cold add relation like.
// Group model
public function users() {
return $this->belognsToMany(User::class)->where('role', 'the role of normal user');
}
public function admins() {
return $this->belognsToMany(User::class)->where('role', 'the role of admin user');
}
Hope it helps you.

laravel- Eloquent relationship between users, user infos, user addresss, and user contacts

I am creating a bunch of models in my laravel project. There are four models, meaning four tables in my database. Namely the models are User, UserInfo,UserAddress,UserContact. The user table is the master table and the structure of the columns are as below:
users -> id , email, password,....other unimportant stuff.
user_info -> id, name, identity num, ......
user_address -> id, user_id, address1, address2,address3, shipping address,....
user_contact-> id, user_id, mobile_num,emergency_num,......
As you can see, the id column is the key identifier to know the entire information for any user. I am trying to define an eloquent relationship between them four and couldn't know if I am correct. This is what I have so far:
User Model:
public function user_info(){
return $this->hasOne('App\Models\UserInfo');
}
public function user_address(){
return $this->hasOne('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasOne('App\Models\UserContact');
}
UserInfo Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_address(){
return $this->hasMany('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
UserAddress Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_info(){
return $this->belongsTo('App\Models\UserInfo');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
UserContact Model:
public function user(){
return $this->belongsTo('App\Models\User');
}
public function user_info(){
return $this->belongsTo('App\Models\UserInfo');
}
public function user_address(){
return $this->belongsTo('App\Models\UserAddress');
}
So the question is that I am unsure for example, is user contact the child of user address or the other way round?
Is user contact the child of user info?
Can anyone shed some light on this?
Appreciate it.
Hi just keep all relations in User model and access them through it. In other Model just relation back to User Model. I am your structure modifying little bit, let user add multiple address check box for default shipping address, also multiple contacts if you want you can keep just one contact also.
users -> id , email, password,....other unimportant stuff.
user_info -> id,user_id ,name, identity num, ......
user_address -> id, user_id, address,shipping address,....
user_contact-> id, user_id, mobile_num,emergency_num,......
User Model
public function user_info(){
return $this->hasOne('App\Models\UserInfo');
}
public function user_address(){
return $this->hasMany('App\Models\UserAddress');
}
public function user_contact(){
return $this->hasMany('App\Models\UserContact');
}
in you all other user related models just add this
public function user(){
return $this->belongsTo('App\Models\User');
}
you can access relation through user model
$user_info = UserInfo::with('user')->first();
$user_info->user->user_contact();
if just user Model
$user = User::with(['user_info','user_contact','user_address'])->first();
echo $user->user_info->name;
update
user_id is the foreign key in each table other than user table, if you want to test the relations create User db seed and 4 factories (user, user_address, user_contact, user_info) to fill fake data, after creating models and data in database fetch first User and call its relations, do the same thing for other models fetch first record and call user relation from this model.
this is my UserTableSeeder class run method
public function run()
{
factory(App\User::class, 10)->create()->each(function ($user) {
$user->user_address()->save(factory(App\Models\UserAddress::class)->make());
$user->user_contact()->save(factory(App\Models\UserContact::class)->make());
$user->user_info()->save(factory(App\Models\UserInfo::class)->make());
});
}

Laravel Auth::user() session custom?

I have three table in database. one is users and second one is role and other is user_role.
in role table has id and name.
in user_role table has user_id and roll_id.
now I want to set session when user will log in to app. llike Auth::user()->roll
Create relationship in User model
public function roles()
{
return $this->belongsToMany(Role::class);
}
Create relationship in Role model
public function users()
{
return $this->belongsToMany(User::class);
}
Then you can attatch a role to a user like this:
Auth::user()->roles()->attach(id_of_the_role_from_roles_table);
and that will create a new entry in pivot table role_user and then you can make a function in user model
public function hasRole($role)
{
return $this->roles->contains('id', $role);
}
and you can call it where ever you want in your code. For example:
Auth::user()->hasRole(1);
That will return true or false and then you can do something with that info.

Laravel - How to chain Eloquent relationship - Eager Loading

I'm using Laravel 5.4, Laravel Roles from here and Eloquent relationships.
I'm trying to retrieve the users of a company along with their roles.
User::find(1)->roles gets me the user's roles whose id =1
Company::find(1)->users gets me all the users that belongs to the company whose id =1 (without the roles of users).
Company::find(1)->users->roles returns an error Property [roles] does not exist on this collection instance.
Questions
Is it possible to do what I want to do ?
If so, how should I do it ?
User.php
class User extends Authenticatable
{
use HasRoleAndPermission;
public function company()
{
return $this->belongsTo('App\Company');
}
public function user()
{
return $this->belongsTo(User::class);
}
}
HasRoleAndPermission.php
trait HasRoleAndPermission
{
public function roles()
{
return $this->belongsToMany(config('roles.models.role'));
}
}
Company.php
class Company extends Model
{
public function users() {
return $this->hasMany('App\User');
}
}
$company = Company::with('users.roles')->find(1);
Will load all the users, and all the roles for each user.
Update
According to your comment, you don't want the company data. Just users and roles Using eager loading and relationship existence.
$users = User::with('roles')
->whereHas('company' => function($query){
$query->where('name', '=', 'company'); //If you don't have the company ID
})->get();
Without relationship existence
$users = User::where('company_id', 1)->with('roles')->get();
1 company has many users.
1 users has many roles.
You are trying to get the roles of a collection of users (the property only exists for one user) thus, the property doesn't exists for the collection.
If you want to get all the roles of all users in the company, you might try the above code:
$roles = [];
Company::find(1)->users->foreach(function($user) {
$roles = array_merge($roles, $user->roles);
});
--------- edit ---------
For eager loading the roles of users, you must use with, as suggested by #Ohgodwhy, but I'd refactor a little:
$users = User::with('roles')->where('company_id', $companyId)->get();
Now you have the array of users eager loading their roles. You still can't access directly $users->roles, you must first get a user, only then get its roles.

Friendship system with Laravel : Many to Many relationship

I'm trying to create a Friendship system with Laravel (I'm starting with it) but I'm blocked with relationships. Here's the thing : there is one table Users and one table Friends which contains the following columns :
friends: id, user_id, friend_id, accepted.
It looks like a Many to Many so here's what I set on User class :
class User extends Eloquent {
function friends()
{
return $this->belongsToMany('User');
}
}
But when I try a :
$friends = User::find($id)->friends()->get()
I have this error :
Base table or view not found: 1146 Table 'base.user_user' doesn't exist
I would like to get a list of the Friends of a user, no matters if the user sent the invitation or received it. So the user can ba on user_id or on friend_id and then I retrieve the data of the other user depending of that column.
Any idea? Thank's!
EDIT : Here's the code I use :
$usersWithFriends = User::with('friendsOfMine', 'friendOf')->get();
$user = User::find(Auth::id())->friends;
foreach($user as $item) {
echo $item->first()->pivot->accepted;
}
tldr; you need 2 inverted relationships to make it work, check SETUP and USAGE below
First off the error - this is how your relation should look like:
function friends()
{
return $this->belongsToMany('User', 'friends', 'user_id', 'friend_id')
// if you want to rely on accepted field, then add this:
->wherePivot('accepted', '=', 1);
}
Then it will work without errors:
$user->friends; // collection of User models, returns the same as:
$user->friends()->get();
SETUP
However you would like the relation to work in both ways. Eloquent doesn't provide a relation of that kind, so you can instead use 2 inverted relationships and merge the results:
// friendship that I started
function friendsOfMine()
{
return $this->belongsToMany('User', 'friends', 'user_id', 'friend_id')
->wherePivot('accepted', '=', 1) // to filter only accepted
->withPivot('accepted'); // or to fetch accepted value
}
// friendship that I was invited to
function friendOf()
{
return $this->belongsToMany('User', 'friends', 'friend_id', 'user_id')
->wherePivot('accepted', '=', 1)
->withPivot('accepted');
}
// accessor allowing you call $user->friends
public function getFriendsAttribute()
{
if ( ! array_key_exists('friends', $this->relations)) $this->loadFriends();
return $this->getRelation('friends');
}
protected function loadFriends()
{
if ( ! array_key_exists('friends', $this->relations))
{
$friends = $this->mergeFriends();
$this->setRelation('friends', $friends);
}
}
protected function mergeFriends()
{
return $this->friendsOfMine->merge($this->friendOf);
}
USAGE
With such setup you can do this:
// access all friends
$user->friends; // collection of unique User model instances
// access friends a user invited
$user->friendsOfMine; // collection
// access friends that a user was invited by
$user->friendOf; // collection
// and eager load all friends with 2 queries
$usersWithFriends = User::with('friendsOfMine', 'friendOf')->get();
// then
$users->first()->friends; // collection
// Check the accepted value:
$user->friends->first()->pivot->accepted;
It's oviously a problem in your DB and also definition of the relation. Many-to-Many relation type expects you to use and intermediate table. Here's what you have to do :
Create a user_friend (id, user_id, friend_id) table in your schema.
Remove unnecessary fields from user and friend tables.
Create proper foreign keys . user.id-> user_friend.user_id , friend.id -> user_friend.friend_id
Better define full relation on the User and Friend models,
for example :
class User extends Eloquent {
function friends()
{
return $this->belongsToMany('User', 'user_friend', 'user_id', 'friend_id');
}
}
You can read much more in Laravel docs, HERE

Categories