How to fetch data in one object using Laravel relationship - php

Previously I was fetching data using queries like below:
$specialitiesAndRoles = DB::table('user_facility')
->leftjoin('roles', 'user_facility.role_id', 'roles.id')
->leftjoin('specialities','user_facility.speciality_id','=','specialities.id')
->leftjoin('available_specialties','specialities.available_specialties_id' ,'=','available_specialties.id')
->where('user_facility.user_id', $user_id)
->select('user_facility.facility_id','user_facility.speciality_id','user_facility.is_facility_supervisor','user_facility.priv_key','user_facility.role_id','specialities.name','available_specialties.id','available_specialties.specialty_key')
->get();
$specialities = (object)$specialitiesAndRoles;
$response = ['facilities' => $specialities];
And my response was:
"facilities": [
{
"facility_id": 59,
"speciality_id": 1,
"is_facility_supervisor": 0,
"priv_key": "can_access_patient",
"role_id": 2,
"name": "Medical",
"id": 1,
"specialty_key": "medical_doctor"
Now I am using relationship and trying to get the same response.
My relationship code:
$specialitiesAndRoles = UserFacility::with([
'speciality' => function($q)
{
$q->select('id','speciality_key');
},
'roles' => function($q)
{
$q->select('id','name');
},
'availableSpeciality' => function($q)
{
$q->select('id','specialty_key');
}])->get();
And my response using relationship become in every object like below:
"facilities": [
{
"id": 2,
"user_id": 32,
"facility_id": 59,
"speciality_id": 1,
"is_facility_supervisor": 0,
"priv_key": "can_access_patient",
"role_id": 2,
"is_admin": null,
"created_at": "2019-07-15 11:30:13",
"updated_at": "2019-07-15 11:30:13",
"isDeleted": null,
"created_by": null,
"updated_by": null,
"is_primary": 0,
"speciality": {
"id": 1,
"speciality_key": "medical_doctor"
},
"roles": {
"id": 2,
"name": "Admin"
},
"available_speciality": {
"id": 2,
"specialty_key": "accu"
},
I don't want to make objects on every data from different tables, I just want to make same response which I was getting using queries and shared above.
How I can make this response using relationships?

You might simply change your query to this:
use App\Models\UserFacitily;
$facilities = UserFacility::leftJoin('roles', 'user_facility.role_id', 'roles.id')
->leftJoin('specialities','user_facility.speciality_id','=','specialities.id')
->leftJoin('available_specialties','specialities.available_specialties_id' ,'=','available_specialties.id')
->where('user_facility.user_id', $user_id)
->select('user_facility.facility_id','user_facility.speciality_id','user_facility.is_facility_supervisor','user_facility.priv_key','user_facility.role_id','specialities.name','available_specialties.id','available_specialties.specialty_key')
->get();

Related

Larvel querying relationship existence still returns empty records

I'm working in a Laravel 9 project and need to show only records where the deeply nested relationship has records, in my case, tiers.
My relationship right now is still returning me pingtree_entries even though tiers are empty, what am I missing?
Here's my top level query:
$pingtree = Pingtree::where('company_id', $company_id)
->where('id', $id)
->has('pingtree_entries.tiers')
->with('pingtree_entries.tiers')
->first();
This should be saying something like:
Get me my Pingtree by company ID and ID with my tiers associated to the pingtree_entries for the Pingtrees where there is more than 0 tiers.
My Pingtree model defines:
/**
* Get the pingtrees that the model has.
*/
public function pingtree_entries()
{
return $this->hasMany(PingtreeEntry::class);
}
My PingtreeEntry model defines:
/**
* Get the buyer tier that the model has.
*/
public function tiers()
{
return $this->hasMany(BuyerTier::class, 'id', 'buyer_tier_id');
}
This is outputting the following via Postman:
{
"model": {
"id": 1,
"user_id": 1,
"company_id": 1,
"pick_chance": 4,
"name": "omnis iusto consequatur",
"description": "Hic nihil suscipit error.",
"is_enabled": false,
"created_at": "2023-01-27T14:15:26.000000Z",
"updated_at": "2023-01-27T14:15:26.000000Z",
"deleted_at": null,
"is_deleting": false,
"pingtree_entries": [
{
"id": 1,
"user_id": 1,
"company_id": 1,
"buyer_id": 2,
"buyer_tier_id": 4,
"pingtree_id": 1,
"pingtree_group_id": null,
"processing_order": 1,
"is_enabled": true,
"created_at": "2023-01-27T14:15:26.000000Z",
"updated_at": "2023-01-27T14:15:26.000000Z",
"deleted_at": null,
"tiers": [
{
"id": 4,
"user_id": 1,
"company_id": 1,
"buyer_id": 2,
"country_id": 2,
"product_id": 3,
"name": "dignissimos voluptas et",
"description": "Dolore tempora et maxime nam.",
"processing_class": "et",
"is_default": false,
"is_enabled": false,
"created_at": "2023-01-27T14:15:25.000000Z",
"updated_at": "2023-01-27T14:15:25.000000Z",
"deleted_at": null,
"is_deleting": false
}
]
},
{
"id": 3,
"user_id": 1,
"company_id": 1,
"buyer_id": null,
"buyer_tier_id": null,
"pingtree_id": 1,
"pingtree_group_id": 1,
"processing_order": 1,
"is_enabled": false,
"created_at": "2023-01-27T14:15:26.000000Z",
"updated_at": "2023-01-27T14:15:26.000000Z",
"deleted_at": null,
"tiers": []
}
]
}
}
Note that the last PingtreeEntry has no tiers. So I don't want to show the whole PingtreeEntry model at all.
Attempted with whereHas
$pingtree = Pingtree::where('company_id', $company_id)
->where('id', $id)
->whereHas('pingtree_entries.tiers')
->with('pingtree_entries.tiers.buyer')
->first();
use :
$pingtree = Pingtree::where('company_id', $company_id)
->where('id', $id)
->with([
'pingtree_entries' => fn($q) => $q->has('tiers'),
'pingtree_entries.tiers',
])
->first();

Laravel : using where inside (with Model)

I have this Controller :
public function user_predects()
{
$matches=Match::with('Predect')->get();
return ($matches);
}
and it is get json data like this :
[
{
"id": 1,
"m_date": "2021-02-06 22:00:00",
"home": "Turkey",
"away": "Italy",
"h_goals": 0,
"a_goals": 0,
"predect": [
{
"id": 3,
"user_id": 10,
"match_id": 1,
"h_predect": 1,
"a_predect": 1,
"player_id": 1,
"point": 0,
"created_at": null,
"updated_at": null
},
{
"id": 4,
"user_id": 9,
"match_id": 1,
"h_predect": 2,
"a_predect": 1,
"player_id": 1,
"point": 0,
"created_at": null,
"updated_at": null
Now I want to view same json data but just for one user ,I used this but don't works :
public function user_predects($username)
{
$user = User::where('username',$username)->get()
$matches=Match::with('Predect')->where('Predect.user_id',$user[0]->id)->get();
return ($matches);
}
How can I view matches model with predect model for one user?
Try this one:
public function user_predects($username)
{
$user = User::where('username',$username)->first()
$matches = Match::with(['Predect' => function($query) use ($user) {
return $query->where('Predect.user_id', $user->id);
}])->get();
return ($matches);
}
You can also read about constraining Eager Loading from the official documentation: Constraining Eager Loads

Laravel 6 pluck in hasManyThrough

Controller:
$files = File::where('agent_id', $user->id)->with('posts')->get();
Model:
public function posts()
{
return $this->hasManyThrough('App\User', 'App\Post', 'id', 'id', 'post_id', 'user_id');
}
So this return a bunch of data, for example:
{
"success": [
{
"id": 2,
"post_id": 1,
"transaction_id": 4,
"agent_id": 2,
"status": 0,
"posts": [
{
"id": 1,
"name": "john",
"email": "john#gmail.com",
"phone": "489797878",
"type": "1",
"verified": 1,
"otp": null,
"created_at": "2019-11-23 10:17:31",
"updated_at": "2019-11-23 10:17:51",
"api_token": null,
"laravel_through_key": 1
}
]
}
...
}
What I want is, exclude some data, like email or verified and etc. I tried pluck('email') and also makeHidden but no success. any idea how can I do this?
How about doing some thing like below, ( haven't tested the code but should give you a clue )
files = File::where('agent_id', $user->id)
->with(['posts' => function ($q) {
$q->select('name','phone'); // specify whatever you want
}])->get(['column1','column2']);
Just use ->get() include list of those you want to get:
example:
$files = File::where('agent_id', $user->id)->with('posts')->get(['post_id', 'status']);

How to calculate the total amount for similar keys in PHP using Laravel eloquent/collections

I currently have the below json response that the API is returning. I am able to return it using Laravel Eloquent. There are several users and each user has a several receipts. A receipt has types and status. I want to try to get the total sum amount for each receipt that is related to its type and status. I was able to return the below json response using
$this->user->with('receipts')->has('receipts')->get(['id', 'name']);
I have tried using multiple laravel collections methods https://laravel.com/docs/5.8/collections#available-methods
But I am still unable to get the desired response.
{
"id": 1,
"name": "kent",
"receipts": [
{
"id": 1,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 100
},
{
"id": 2,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 100
},
{
"id": 3,
"user_id": 1,
"type_id": 2,
"status": 1,
"amount": 50
},
{
"id": 4,
"user_id": 1,
"type_id": 2,
"status": 0,
"amount": 30
},
{
"id": 5,
"user_id": 1,
"type_id": 2,
"status": 0,
"amount": 30
},
{
"id": 6,
"user_id": 1,
"type_id": 1,
"status": 0,
"amount": 20
},
{
"id": 7,
"user_id": 1,
"type_id": 1,
"status": 1,
"amount": 10
}
]
},
{
"id": 2,
"name": "allison",
"receipts": [
{
"id": 9,
"user_id": 2,
"type_id": 1,
"status": 0,
"amount": 20
}
]
}
]
I expect to get the below
{
"id": 1,
"name": "kent",
"receipts": [
{
"performance and deleted": 220,
"performance and not deleted": 10,
"project and deleted": 60,
"project and deleted": 50
}
]
},
{
"id": 2,
"name": "allison",
"receipts": [
{
"performance and deleted": 20,
"performance and not deleted": 0,
"project and deleted": 0,
"project and not deleted": 0
}
]
}
]
You should be able to get the sum of amount with
$this->user->with(['receipts' => function($query) {
$query->selectRaw("SUM(amount) as amount, type_id, status, user_id")->groupBy('type_id', 'status', 'user_id');
}])->has('receipts')->get(['id', 'name']);
You can use collection methods to get the desired output
$this->user->with(['receipts' => function($query) {
$query->selectRaw("SUM(amount) as amount, type_id, status, user_id")->groupBy('type_id', 'status', 'user_id');
}])->has('receipts')->get(['id', 'name'])
->each(function ($user) {
$user->setRelation(
'receipts',
$user->receipts->mapWithKeys(function ($receipt) {
return [
$receipt->type_id . ' and ' . $receipt->status => $receipt->amount // format the key as you wish
];
})
);
})
You may use foreach and other loops to make the json you want!
use This function to convert your collection to the json you want :
public function convert(Collection $collection)
{
$result_collection = $collection;
$payment_collections = [];
foreach ($result_collection->receipts as $receipt)
{
$payment["type_id${receipt->type_id} and status${$receipt->status}"] = $receipt->amount;
}
$result_collection->receipts = $payment_collections;
return $result_collection;
}
And This is same way to get total amount. Just put an foreach and add each amount to a variable that initialized with 0;
and there is other ways like change toArray function in your Resource Collection.
I wrote the script assuming your data is a PHP array so you may change some part of my code.
For example you may change:
$row['receipts']
// To
$row->receipts
anyway
// The function in your controller
function index(){
$users=User::whereHas('receipts')->with('receipts')->get()->toArray();
return convert($users);
}
// The helper function
function convert($data){
$data=collect($data);
$allTypes=[];
$allStatuses=[];
return $data->each(function($row) use (&$allTypes,&$allStatuses){
$types=collect($row['receipts'])->pluck('type_id')->toArray();
$statuses=collect($row['receipts'])->pluck('status')->toArray();
$allTypes=array_unique(array_merge($allTypes,$types));
$allStatuses=array_unique(array_merge($allStatuses,$statuses));
})->map(function ($row,$index) use (&$allTypes,&$allStatuses){
$result=[];
$receipts=collect($row['receipts']);
foreach ($allTypes as $type){
foreach ($allStatuses as $status){
$result["type_id {$type} and status {$status}: "]=$receipts->where('type_id',$type)->where('status',$status)->sum('amount');
}
}
$row['receipts']=$result;
return $row;
});
}

How to group same values in a parent array?

I want to create story for my ios app, I am trying to get useful json response for it. I want to show same user stories in a group inside of that user`s array.
Current JSON RESULT;
{
"current_page": 1,
"data": [
{
"id": 3,
"name": "Muhammed Ali Yüce",
"username": "ali",
"avatar": "1544128196.png",
"stories": {
"id": 3,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
}
},
{
"id": 2,
"name": "Ömer Faruk YÜCE",
"username": "omer",
"avatar": "1544128227.png",
"stories": {
"id": 2,
"user_id": 2,
"image": "1550228407.jpg",
"created_at": "2019-02-15 11:00:08",
"updated_at": "2019-02-15 11:00:08"
}
},
{
"id": 2,
"name": "Ömer Faruk YÜCE",
"username": "omer",
"avatar": "1544128227.png",
"stories": {
"id": 1,
"user_id": 2,
"image": "1550072626.jpg",
"created_at": "2019-02-13 15:43:47",
"updated_at": "2019-02-13 15:43:47"
}
}
],
"first_page_url": "/?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "/?page=1",
"next_page_url": null,
"path": "/",
"per_page": 10,
"prev_page_url": null,
"to": 3,
"total": 3
}
I did tried groupBy func for it but it was not what I excepted.
I want to get result like this;
{
"id": 3,
"name": "Muhammed Ali Yüce",
"username": "ali",
"avatar": "1544128196.png",
"stories": [
{
"id": 2,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
},
{
"id": 3,
"user_id": 3,
"image": "1550228567.jpg",
"created_at": "2019-02-15 11:02:47",
"updated_at": "2019-02-15 11:02:47"
}
]
StoryController.php
<?php
namespace App\Http\Controllers;
use App\Story;
use App\User;
use Illuminate\Http\Request;
use Image;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\LengthAwarePaginator;
class StoryController extends Controller
{
public function index(Request $request){
$userId = $request->id;
$followsArr = [$userId];
$follows = DB::table('follows')->whereNotIn('ismuted', [1])->where('follower', $userId)->get();
foreach ($follows as $follow) {
$friend = $follow->following;
$followsArr[] = $friend;
}
$itemCollection = collect($followsArr);
$stories = [];
Story::whereIn('user_id', $itemCollection)
->orderBy('created_at', 'DESC')
->get()->each(function ($story) use (&$stories){
$user = User::where('id', $story->user_id)->first();
$stories[] =
['id' => $user->id]
+ ['name' => $user->name]
+ ['username' => $user->username]
+ ['avatar' => $user->avatar]
+ ['stories' => $story->toArray()];
});
// Get current page form url e.x. &page=1
$currentPage = LengthAwarePaginator::resolveCurrentPage();
// Create a new Laravel collection from the array data
$itemCollection = collect($stories);
// Define how many items we want to be visible in each page
$perPage = 10;
// Slice the collection to get the items to display in current page
$currentPageItems = $itemCollection->slice(($currentPage * $perPage) - $perPage, $perPage)->all();
// Create our paginator and pass it to the view
$paginatedItems= new LengthAwarePaginator($currentPageItems , count($itemCollection), $perPage);
return response()->json($paginatedItems);
}
I hope you will understand what I mean, Thanks in advance :)
Assume you have User.php and Story.php Models
In User.php
public function stories()
{
return $this->hasMany(Story::class);
}
You can load story along with user. something like that
$user = User::where('id', $story->user_id)->with('stories')->first(); //Eager Load
or
$user = User::where('id', $story->user_id)->first();
$user->load('stories'); //Lazy Eager Load
Please read more about Laravel Eloquent: Relationships

Categories