Multiple foreign keys referencing to one primary key - php

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();

Related

Laravel Relationship with integer[] type of postgresql column

I have categories table and products table. in products table have category_id column type of integer[].
ex: {1,2,3}
.
And I need products list with category relation which categories.id exist products.category_id
I tried in model Product:
public function category()
{
return $this->belongsTo(Category::class, \DB::raw("ANY(category_id)"), 'id');
}
no get category is null.
you should use belongs to many relation.
because integer[] type is for saving arrays of ints.
try to set it in your model like this:
in your Product(model) you will get this relation method:
public function categories(): BelongsToMany
{
return $this->belongsToMany(Category::class);
}
And in your Category(model):
public function products(): BelongsToMany
{
return $this->belongsToMany(Product::class);
}
Refrence
You can try this using laravel query builder
public function category()
{
return DB::table('products')
->join('categories', 'products.category_id', '=', 'categories.id')
->get();
}
First of all, I dont think it's possible to do this with the Laravel Relationship Methods.
Second of all, if you are using Postgres, which is a relational Database, you should definitely read up on the fundamentals of database normalization.
I would recommend you have a so called pivot table, that links your products to your categories, which could look something like this:
Disclaimer: You dont need to create a Model for this. Just make a migration with php artisan make:migration create_categories_products_table
categories_products
| id | category_id | product_id |
|---------------------|------------------|---------------------|
| 55 | 1 | 5 |
| 56 | 2 | 5 |
| 57 | 3 | 5 |
| 58 | 1 | 6 |
This table links your tables and this is much more easy to handle than some arrays stored as json.. maybe think about it, it is not that much work to do. You can read upon it on the Laravel Documentation or try searching on google for pivot tables and normalization.
When you have done that:
Now you can just use the Laravel belongsToMany Relationship like so:
// Product.php
public function categories()
{
return $this->belongsToMany(Category::class, 'categories_products');
}
// Category.php
public function products()
{
return $this->belongsToMany(Product::class, 'categories_products');
}
I can't relation but with attribute i can get categories
firstly cast category_id to array and
public function getCategoriesAttribute()
{
return Category::whereIn('id',$this->category_id)->get();
}
and it works

Laravel Lumen Many to One return []

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.

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: Perform collection formatting after each select query

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()}}

Categories