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;
}
Related
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.
I'm quite new in Lumen but I have to do this because i have final task about Laravel.
So, i do have these two tables, the users and userTypes table.
usertypes table
+-----------------------+
| userTypeId | typeName |
+-----------------------+
| 1 | admin |
| 2 | buyer |
| 3 | store |
+-----------------------+
users table
+----------------------------------+
| id | name | email | userTypeId |
+----------------------------------+
| 1 | john | e#e.com | 2 |
+----------------------------------+
Now, what i was hoping the output for is something like this:
{
"data" : {
"id" : 1,
"nama" : "john",
"email" : "e#e.com",
"usertypes" : {
"typesName" : "buyer"
}
}
}
I've tried hasMany() and hasOne() and more but the "userTypes" field still return []. Here's the model for both of that.
User.php
....
public function usertype() {
return $this->hasMany(UserTypes::class, 'userTypeId');
}
....
UserTypes.php
.....
public function User() {
return $this->belongsTo(User::class);
}
.....
And here's the UserController.php
...
public function user($id) {
$user = User::with(['usertype'])->findOrFail($id);
return response()->json(['data' => $user]);
}
...
Any way to fix this? I appreciated for anyone who willing to help me. Thank you 🙏🙏
Its better to use find method you use route model binding. when you pass id
to method User $user auto find user from databse. now we have $user so we
call relation $user->usertype.
public function user(User $user) {
return response()->json(['data' => $user->usertype]);
}
So it appears that i'm not fully understand the meaning of the "third parameters" and thanks to someone in telegram group that helping me out, in the User model it should be:
return $this->hasOne(UserTypes::class, 'userTypeId', 'userTypeId');
and it works. Second parameter is the foreign key on the users table, third parameter is the primary column name in that userTypes table. Hope it clears the dumb newbie like me.
I've been struggling with this for a couple of weeks and I can't seem to find the answer anywhere.
I am trying to reference three foreign keys into one primary key on another table.
Here are some information:
User Table
|---------------------|
| id |
|---------------------|
| 1 |
|---------------------|
| 2 |
|---------------------|
| 3 |
|---------------------|
Service Table
Service table with three foreign keys referencing to user_id
|---------------------|------------------|------------------|------------------|
| id | tenant | service_person | landlord |
|---------------------|------------------|------------------|------------------|
| 1 | 1 | 2 | 3 |
|---------------------|------------------|------------------|------------------|
User Model
public function service(){
return $this->hasMany(Service::class, 'id');
}
Service Model
public function tenant(){
return $this->belongsTo(User::class, 'id', 'tenant');
}
public function service_person(){
return $this->belongsTo(User::class, 'id', 'service_person');
}
public function landlord(){
return $this->belongsTo(User::class, 'id', 'landlord');
}
So when I try to query with User::find()->service with tinker, only one of my three users find results, which is the service_person. The other ones just return an empty object.
Query result:
>>> User::find(1)->service
=> Illuminate\Database\Eloquent\Collection {#3125
all: [
App\Service {#3156
id: 1,
tenant: 2,
service_person: 1,
landlord: 3
},
],
}
>>> User::find(2)->service
=> Illuminate\Database\Eloquent\Collection {#3165
all: [],
}
>>> User::find(3)->service
=> Illuminate\Database\Eloquent\Collection {#3166
all: [],
}
What I am trying to achieve is looking for all the services related to that user, doesn't matter if that user is the tenant, service_guy or landlord, so I can show it on the front end.
Any idea on how can I achieve that?
Ideally I do not want to do a many to many relationship and create a pivot table.
Thank you in advance
i think the problem is for the User model 's relations:
User Model:
public function servicesTenants(){
return $this->hasMany(Service::class, 'tenant');
}
public function servicesPerson(){
return $this->hasMany(Service::class, 'service_person');
}
public function servicesLandlord(){
return $this->hasMany(Service::class, 'landlord');
}
now, you can try:
$user=User::with(['servicesLandlord','servicesPerson','servicesTenants'])->find($user_id);
if you want to get all user 's services regardless of the relation you can try:
$userServices=Service::where('tenant',$user_id)->orWhere('service_person',$user_id)->
orWhere('landlord',$user_id)->get();
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.
Imagine following DB tables:
Clients Users
| Id | name | user_id | | ID | name |
| -- | ----- | ------ | | -- | ------ |
| 1 | NULL | 1 | | 1 | David |
| 2 | Peter | NULL |
Not each client is automatically user, but user may have client account. Users table contains only registered users, if user is client (dont have to be) the client account is created.
I have succcessfully made relations between these table is Laravel. Eloquent querying woks fine, eg.:
clients.php
public function userAcc() {
return $this->hasOne('User', 'id', 'user_id');
}
user.php
public function clientAcc() {
return $this->hasOne('Clients', 'user_id', 'id');
}
The problem is that when i query these tables:
Clients::with('userAcc')->get()
In view i have to make lots of ifs, like:
#if($client->userAcc)
{!! $client->userAcc->name !!}
#else
{!! $client->name !!}
#endif
Is there any workaround in laravel that allows me to format collections on each select query? Something like Accessor but on whole collection, so i will be able to do something like this in view:
{!! $client->realname !!}
And it writes client name from particular table.
Many thanks for any suggestions
This is the Laravel way to accomplish this:
class Client extends Model {
public $appends = ['realname'];
public function userAcc() {
return $this->hasOne('User', 'id', 'user_id');
}
public function getRealnameAttribute(){
return $this->userAcc? $this->userAcc->name : $this->name;
}
Now it will be accessible through $client->realname and it will be included in $client->toJson() and $client->toArray()
You can make a method for that:
public function getName()
{
return $this->userAcc?$this->userAcc->name:$this->name;
}
In your blade just call the function:
{{$client->getName()}}