Eloquent sort by relationship column - laravel

I'm kind of lost, i'm trying to count the distance and sort mission closest to the logged in user. The problem is that my lat and lng is in another table (Buildings), which is defined as a relation in Mission.
I'm using Laravel/Lumen's QueryBuilder to fetch records from the database.
$orderBy = "DEGREES(ACOS(COS(RADIANS($lat)) * COS(RADIANS(lat)) * COS(RADIANS($lng) - RADIANS(lng)) + SIN(RADIANS($lat)) * SIN(RADIANS(lat))))";
return DB::table('buildings')
->join('missions', 'building_id', '=', 'buildings.id')
->select('missions.*', 'buildings.lat', 'buildings.lng')
->orderBy(DB::raw($orderBy))
->get();
result:
{
"id": 5,
"building_id" : 2
...
"created_at": "2016-03-07 07:35:19",
"updated_at": "2016-03-07 07:35:19",
"lat": 33,
"lng": 55
}
But this returns quite ugly response and hard to work with. Since Mission have relation with a Building, I would like to load that table to the response too (Instead of displaying building_id). But with DB:Table() it's not possible(?)
{
"id": 5,
"building_id": 2
"building" : {
"id": 2
...
"lat": 33,
"lng": 55
}
...
}
This is the response I would like to get, and be sorted by lat/lng.
Is there any possible way to do this with Eloquents models?

Does this work to you?
$orderBy = "DEGREES(ACOS(COS(RADIANS($lat)) * COS(RADIANS(lat)) * COS(RADIANS($lng) - RADIANS(lng)) + SIN(RADIANS($lat)) * SIN(RADIANS(lat))))";
return Building::join('missions', 'building_id', '=', 'buildings.id')
->select(['missions.*', 'buildings.lat', 'buildings.lng'])
->with('missions')
->orderBy(DB::raw($orderBy))
->get();
PS: Don't forget to set the relation in your Building model, unless the with method will fail.

Related

Merge Model and its Relationship with result like join query in laravel

I'm new at Laravel and Programming at that. I have a problem joining model with its relationship, here is what my model:
class MainClass extends Model
{
public function first()
{
return $this->hasMany(First::class);
}
public function second()
{
return $this->hasMany(Second::class);
}
public function third()
{
return $this->hasMany(Third::class);
}
}
When i try to get MainClass records then load it's relationship like:
$main = Main::where('status', 'ready')->get()
$main->load(['first','second'])
Here's what i got:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"first":[
{"main_id": "1", "prop":"One"},
{"main_id":"1", "prop":"Two"}],
"second":[
{"main_id": "1", "other":"Yes"},
{"main_id":"1", "other":"Two"},
{"main_id":"1", "other":"Three"}]
},{
"id":"5",
"name":"Fifth Person",
"status": "ready",
"first":[
{"main_id": "5", "prop":"Five"},
{"main_id":"5", "prop":"Six"}],
"second":[
{"main_id": "5", "other":"Laptop"},
{"main_id":"5", "other":"Pc"}]
}]
How can i merge that relationship so the result will be like join query,
this is what i want:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"One",
"other:"Yes"
},{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"Two",
"other":"Two"
}]
I know there is a way to combine collection with merge or push in laravel, but i can't seem to get it right.
As of why not using join query, because i want to load relationship dynamically, so relation is not always loaded, but sometime they do. While join query, i have to write it manually (as far as i know) :-)
Maybe someone can point me somewhere, or maybe there is a package for something like this?
Thanks in advance
Use eager loading, fetching the collection, then run groupBy, then the each, then the map function to return the results formatted as your wish.
Why not just simply run the joins
You can do it with join;
$main = Main::query()->select(['main.id', 'main.name', 'main.status', 'f.prop', 's.other', 't.blabla'])
->leftJoin('first as f', 'f.main_id', 'main.id')
->leftJoin('second as s', 's.main_id', 'main.id')
->leftJoin('third as t', 't.main_id', 'main.id')
->where('main.status', 'ready')
->get();

Laravel JOIN DB Raw return hasMany Relathsionship

i have case in my query, i want expect like this
one project hasMany User
total_feedback is calculated from id in feedback table
where the project_id in the feedback table has a relation to the pivot table, namely project_user , i want to calculated how much feedback on a project,
i want expect return JSON like this
"success": 1,
"data": [
{
"id": 1,
"Project_name": "Project Tania Yessi Laksmiwati",
"user_name": {
"User A",
"User B",
"User C",
"User D",
}
"total_feedback": 0
},
{
"id": 2,
"Project_name": "Project Bakijan Bancar Anggriawan",
"user_name": {
"User F",
"User G",
"User C",
}
"total_feedback": 10
},
{
"id": 3,
"Project_name": "Project Mahesa Vega Mahendra",
"user_name": {
"Users A"
},
"total_feedback": 6
},
return JSON above is one project hasMany users
but, now i get return json like this bellow :
"success": 1,
"data": [
{
"id": 1,
"Project_name": "Project Tania Yessi Laksmiwati",
"user_name": "Ilyas Simanjuntak",
"total_feedback": 0
},
{
"id": 2,
"Project_name": "Project Bakijan Bancar Anggriawan",
"user_name": "Ilyas Simanjuntak",
"total_feedback": 0
},
one project return just one users, even though the project with id 1 has 3 users, like project_user table like this bellow
project_id | user_id
1 2
1 4
1 5
this is my query
$user = $this->request->attributes->get('_user');
$query = "SELECT A.id, A.`name` AS Project_name, D.`name` AS user_name, COUNT(C.`id`) AS total_feedback FROM `project` A
JOIN `project_user` B ON A.`id` = B.`project_id` AND B.`user_id` = $user->id
LEFT JOIN `feedback` C ON C.`project_id` = B.`project_id` AND C.`request_id` = B.`user_id`
JOIN `users` D ON D.`id` = B.`user_id`
GROUP BY A.`id`";
$getFeedback = DB::select(DB::raw($query));
but i get project with ID 1 just return one users,, in my case above how to return one project with many users from database, i use the DB query ,, or any suggestion ? Thanks! regards.
If you already have relationships setup, why aren't you using Eloquent for this? You can easily do this with Eloquent with() and withCount() methods. Assuming you have setup your model relationships correctly, you can do something like this instead:
Auth::user()
->projects()
->with(['users', function($query) {
return $query->pluck('name');
}])
->withCount('feedback as total_feedback')
->get();

Laravel - How to combine multiple queries as one Eloquent Query

In my Laravel-5.8, I have these four queries accessng the same model:
$allLeaves = HrLeaveRequest::where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$pendingLeaves = HrLeaveRequest::where('leave_status', 1)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$rejectedLeaves = HrLeaveRequest::where('leave_status', 3)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
$approvedLeaves = HrLeaveRequest::where('leave_status', 4)->where('company_id', $userCompany)->whereYear('created_at', date('Y'))->count();
How do I combine the four queries as one
something similar to this
$gender_unpublished_record = HrEmployee::selectRaw('count(gender_code) as count,gender_code, if (gender_code = 1, "Male", "Female") as gender')->whereNotIn('employee_code', $publishedgoals)->where('company_id', $userCompany)->where('hr_status', 0)->groupBy('gender_code')->get();
The one above only have 0 or 1. But what I want to achive takes care of everything in the table, leave_status as 1, 3 and 4
Thank you
in your Company Model you should have the relation:
public function HrLeaveRequests()
{
return $this->hasMany(HrLeaveRequest::class,'company_id');
}
now you could use withCount:
$value=Company::where('company_id',$userCompany)->withCount(['HrLeaveRequests as allLeaves'=>function($query){
$query ->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as pendingLeaves'=>function($query){
$query->where('leave_status', 1)->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as rejectedLeaves'=>function($query){
$query->where('leave_status', 3)->whereYear('created_at', date('Y'));
},
'HrLeaveRequests as approvedLeaves'=>function($query){
$query->where('leave_status', 4)->whereYear('created_at', date('Y'));
},
])->get();

How to make a condition based on relation ship count in Laravel Eloquent?

I would like to add a condition based on the tasks relationship count,
Here is the code:
return TeamleaderDeal
::withCount('tasks')
->get();
The result is:
[
{
"id": 4,
(...)
"dealPhase": "Refused",
"tasksCount": 5,
(...)
},
{
"id": 5,
(...)
"tasksCount": 0,
"companyLanguage": "nl",
(...)
},
{
"id": 16,
(...)
"dealPhase": "New",
"tasksCount": 17,
(...)
},
{
(...)
How to only return results where tasksCount equal to 5?
You may use has method like this:
// Retrieve all team-leader deals that have 5 tasks...
return TeamleaderDeal
::has('tasks', '=', 5)
->get();
Check Laravel docs for more info.

Change Laravel Relationship Output Structure

I'm using Laravel 5.2 and I have Role and Permission models with
Role.php
public function permissions()
{
return $this->hasMany('App\Permissions');
}
And if I call
return Role::with('permissions')->get()
it will return
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [
{
"permission_id": 1,
"role_id": 2
},
{
"permission_id": 2,
"role_id": 2
},
{
"permission_id": 3,
"role_id": 2
},
{
"permission_id": 4,
"role_id": 2
},
{
"permission_id": 5,
"role_id": 2
}
}]
Is it possible to change the "permissions" structure to something like these?
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [1,2,3,4,5]
}]
If you want to get an array (as title says), use toArray() method:
return Role::with('permissions')->get()->toArray();
It will convert the collection to an array.
If you need to get custom formatted JSON (as your example shows), use toArray(), then rebuild this array with using foreach or array_map()/array_filter() methods and encode result into JSON with json_encode().
I would recommend you to send data as is (without rebuilding it's structure) to frontend or whatever and work with it there.
I order to extract a Collection of permission IDs you can use the pluck() function:
$permissionIds = $role->permissions->pluck('permission_id');
You can also write a getter function in your Role model:
public function getPermissionIds()
{
return $this->permissions->pluck('permission_id');
}
and use it like:
$permissionIds = $role->getPermissionIds();
You can even override the magic __get() function:
public function __get($attr)
{
if ($attr === 'permissionIds') {
return $this->getPermissionIds();
} else {
return parent::__get($attr);
}
}
and access the permission IDs like an attribute:
$permissionIds = $role->permissionIds;
In Laravel 5.2 the returned value of models is a Collection instance which can be used to transform the result
$roles = Role::with('permissions')->get();
$roles->transform(function($role){
$role['permissions'] = $role['permissions']->pluck('permission_id')->toArray();
return $role;
});
return $roles;
This code will provide the desirable result.
Note: You can even chain the transform function after the get function.
I hope this answer will help to you,
$role = Role::all();
foreach ($role as $index){
$permissions= $index->permissions;
foreach ($permissions as $permission){
$permissionId[] = $permission->permission_id;
}
unset($index->permissions);
$index['all_permissions']= $permissionId;
}
return response()->json($role, 200);
This is work for me. So check for your code.

Resources