Multi-Tenant App - Getting Username for Users from Pivot Table - php

I'm developing a multi-tenant application with single database approach. Each query is typically scoped by subdomain_id.
My database is structured as follows -
users : This table is shared by multiple tenants
id | first_name | last_name | created_at | updated_at
subdomains:
id | creator_id | name | slug | created_at | updated_at
subdomains_users: This is my pivot table
id | subdomain_id | user_id | username | created_at | updated_at
The relationships are defined as follows-
User:
public function subdomains(): BelongsToMany
{
return $this->belongsToMany(Subdomain::class, 'subdomains_users', 'creator_id', 'subdomain_id')->withPivot(['username'])->as('info')->using(SubdomainsUsers::class);
}
Subdomain:
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'subdomains_users', 'subdomain_id', 'owner_id')->withPivot(['username'])->as('info')->using(SubdomainsUsers::class);
}
Throughout my application, I'm required to access the username attribute. However, as you can see, this isn't straightforward; because a user can belong to multiple subdomains.
How do I go about retrieving the username of any user for the current subdomain?

You can do it like so:
in User model (assuming you have the current subdomain id in the session, or just replace it with what is appropriate for you):
public function getUsernameAttribute()
{
return $this->subdomains
->first(fn($subdomain) => $subdomain->id == session('subdomain_id'))
->pivot
->username;
}
and you'll be able to call $user->username to get the username for the current subdomain

Related

How I get users which are created by Auth::user

I have two table users and customer_details. I want to get users which are created by Auth::user(). The created_by column is in customer_details table.
User Table
| id | name | email | status |
|-----------------------------------------------|
| 1 | Admin | admin#email.com | Active |
| 2 | Customer | user#email.com | Active |
CustomerDetails Table
| id | user_id | added_by | address |
|-------------------------------------------|
| 1 | 2 | 1 | NY City |
This is my query
$customers = User::role('Customer')->whereIn('status', ['Active'])->get();
Want to get records where added_by is current auth user
$customers = User::role('Customer')->whereIn('added_by', Auth::id())->get();
I think this should help
here we are using Auth::id() to get the id of the current user and then using eloquent to search for it.
I am considering that here added_by column contains the ID;
Create a relation in your CustomerDetail model:
public function addedBy()
{
return $this->belongsTo(User::class, 'added_by');
}
Then, you can query using this relation:
CustomerDetail::whereHas('addedBy', function($query) {
return $query->where('id', auth()->id());
})->get();
This query returns all customer created by the user current logged in.
To get all users with it's customers created by the current logged in user, add a new relation, now to the user model:
public function customerDetail()
{
return $this->hasOne(CustomerDetail::class, 'added_by');
}
and query users with customers created byt the logged in user:
User::role('Customer')->whereHas('customerDetail', function($query) {
return $query->where('added_by', auth()->id());
})
->whereIn('status', ['Active'])
->get();

Attaching extra model to BelongstoMany relations

I have two tables (users and drinks) with a pivot table, the user has a hasOne relation with profiles table, is there a way to attach the profile table to the pivot table and get all data.
Table user
id | name | email
Table profile
id | user_id | picture
Table drinks
id | name | price
Pivot Table user_drinks
id | user_id | drink_id | quantity | price | status
Drink Model
public function users()
{
return $this->belongsToMany('App\User', 'user_drinks', 'drink_id', 'user_id')->withPivot('price', 'quantity')->withTimestamps();
}
User Model
public function drinks()
{
return $this->belongsToMany('App\Drink', 'user_drinks', 'drink_id', 'user_id')->withPivot('price', 'quantity')->withTimestamps();
}
public function profile() {
return $this->hasOne('App\Profile');
}
PS: I don't wanna write this with raw sql query, it's driving me nuts.
I wouldn't change the tables relation.
I'd use the ->with() function to get the profile information within the existing relations.
So $user->drinks()->where('drink_id', $drink_id)->with('profile')->get(); would be my guess.

Lumen/Laravel many-to-many (fetch data in the middle)

I am testing out Lumen here and have a question regarding many-to-many relationship.
I've read the documentation, but I've either overlooked the answer or I might be dumber then I think. Also have to add that I am pretty new to the MVC pattern.
So I have an example here where we can have many permissions, many users and each user can have many permissions.
I have 3 database tables:
-------------------------------------
| users | id | firstname | lastname |
-------------------------------------
----------------------------------------------------------------
| permissions_users | id | permission_id | user_id | from | to |
----------------------------------------------------------------
----------------------------------
| permissions | id | name | desc |
----------------------------------
And for now I've created 2 models:
User:
public function permissions(){
return $this->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id');
}
Permission:
public function users(){
return $this->belongsToMany('App\User', 'permissions_users', 'permission_id', 'user_id');
}
Now my question is, what if I want to fetch the "from" and "to" dates in the permissions_users table, what do I do?
Do I create a model called PermissionUser "between" that act as a middleman between User and Permission or is there another way?
Thanks
You can define these attributes also in select on relation. I think this will work for you.
public function permissions()
{
return $this->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id')->select(['from', 'to']);
}
You might need to add permission columns too in select else it might show only from and to in your relation object.
public function permissions()
{
return $this
->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id')
->withPivot('from', 'to');
}
foreach($user->permissions as $permission){
$permission->pivot->from;
$permission->pivot->to;
}

Laravel 5.5 User model and friends relationship (belongsToMany) by multiple columns

Problem
I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.
Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.
Current Implementation
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
}
Ideal Implementation
public function friends()
{
$a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
$b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');
return combine($a,$b);
}
Table Structure
+----------------------+
| users table |
+----------------------+
+----| id: primary UserID |
| | fname: string |
| +----------------------+
|
|
| +----------------------+
| | friends table |
| +----------------------+
| | id: primary iD |
| | |
+----| uid1: user_id |
| | |
+----| uid2: user_id |
+----------------------+
The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.
+-------------------------------+
| friends table (data) |
+--------|---------|------------+
| id | uid1 | uid2 |
+--------|---------|------------+
| 1 | 1 | 7 |
| 2 | 7 | 1 |
| 3 | 9 | 1 |
+-------------------------------+
User Model
<?php
namespace App\Modules\Users\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = [
'username', 'email', 'password', .... .
];
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
}
Environment
Server = Homestead/linux
PHP = 7
MySQL
Update
I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly
Friendship::where( [
[ 'uid1' ,'=', $uid],
])->orWhere( [
[ 'uid2', '=', $uid]
])->all();
You can add additional conditions when you're declaring relationship by simply chaining it.
<?php
//...
class User extends Model {
//...
public function friends() {
return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
}
//...
But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)
For example the above might result in a SQL that looks like this
SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?
Which is a correct SQL statement but without grouping you will not get the result that you're expecting.
Another way is to use accessor and two separate relationships
<?php
//...
public function friends1() {
return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}
public function friends2() {
return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}
public function getFriendsAttribute() {
return $this->friends1->merge($this->friends2);
}
//...
But this way you get two separate trips to DB.

Laravel count Eloquent belongsToMany related model

I'm new to Laravel, and I got stuck with the following issue:
I have a table for the users, and groups, and a table for connecting them. The general task any user can join any group.
----------------------------------------------
| users | groups | user_groups |
|--------------------------------------------|
| id - int pk | id - pk | id - pk |
| name text | name | user_id - fk |
| email | | group_id - fk |
| phone | | any_attr |
----------------------------------------------
I have the following models:
class User
{
...
public function groups()
{
return $this->belongsToMany(Group::class, 'user_groups')->withPivot(['is_notification_requested']);
}
...
}
class Group
{
...
public function users()
{
return $this->belongsToMany(User::class, 'user_groups');
}
...
}
How do I get all of the groups, with a count of the members? I need the Group model, and a count of the users in the group.
If you're using Laravel 5.3, you can simply add withCount('relationship') as documented here: https://laravel.com/docs/5.3/eloquent-relationships#counting-related-models
Here's an example following your code:
$groups = Group::withCount('users')->get();
Now you can do this:
foreach($groups as $group) {
echo $group->user_count
}

Categories