How we get specific columns from multiple relations using With() in Laravel - laravel

I need some specific columns from two relations.
In my questions model I have two relations
public function ans_options()
{
return $this->hasMany('App\Models\AnswerChoices', 'ac_quest_id', 'q_id');
}
public function question_category()
{
return $this->hasOne("App\Models\Categories", 'cat_id', 'q_category');
}
I tried
Questions::with(array(
'questionCategory' => function($query) {$query->select('cat_id','cat_value');},
'ans_options' => function($query1) {$query1->select('ac_id','ac_choiceTxt');}
))->get();
am getting only the columns of question_category not in ans_options
{
"q_id": 349,
"q_project_id": 140,
"q_text": "<p>Gender</p>",
"question_category": {
"cat_id": 1,
"cat_value": "normal"
},
"ans_options": []
}
But when I try the below code all columns of ans_options are getting.
Questions::with('questionCategory:cat_id,cat_value','ans_options')->get();
like
{
"q_id": 349,
"q_project_id": 140,
"q_text": "<p>Gender</p>",
"question_category": {
"cat_id": 1,
"cat_value": "normal"
},
"ans_options": [
{
"ac_id": 334,
"ac_quest_id": 349,
"ac_choiceTxt": "Male",
"ac_modifiedOn": "2021-11-24T06:22:00.000000Z",
"ac_status": "active"
},
{
"ac_id": 335,
"ac_quest_id": 349,
"ac_choiceTxt": "Female",
"ac_modifiedOn": "2021-11-24T06:22:00.000000Z",
"ac_status": "active"
}
]
}
I need only ac_id and ac_choiceTxt from ans_options. How can I achieve that?

to make Laravel able to load the relation, you should select the foreign key that responsible for that relation
Questions::with(array(
'questionCategory' => function ($query) {
$query->select('cat_id', 'cat_value');
},
'ans_options' => function ($query1) {
$query1->select(
'ac_id',
'ac_choiceTxt',
'ac_quest_id'
);
}
))->get();
just add 'ac_quest_id' to your select.

You can make model where available only this fields
Extend current model from new (with removing columns from curent)
use "with" from new short model
I don't know another way at now...

Then we can add the primary key here also. It will get the same result and then no need of closures here.
Questions::with('questionCategory:cat_id,cat_value',
'ans_options:ac_id,ac_choiceTxt,ac_quest_id')
->get();

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 - 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.

Laravel: how to parse string to json

I've created this code from laravel:
public function findConfig($id)
{
$config = DB::table('configuration')
->join('model', 'model.configuration_id','=', 'configuration.id')
->select('configuration.id','configuration.description', 'model.name','configuration.price')
->where('configuration.id','=', $id)
->get();
$encode = json_encode($config, JSON_UNESCAPED_SLASHES);
$response = Response::make($encode, 200);
$response->header('Content-Type', 'application/json');
return $response;
}
then the return is somehow like this
[{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "k5-A",
"price": "300000"
},
{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "r-A",
"price": "300000"
}
]
How can I remove the slashes and instead of string as return type, it should be in JSON?
As lukasgeiter said, generally it isn't a good idea to store json in a db. It may get difficult to filter by that field.
If you decide to do so, and need to get the decoded data, you can use an accessor in the model. I don't know if it is the best practice. If the description is saved in the db as a json you can do this:
For the "configuration" table you may have a "Configuration" model (The official Laravel website recommends to name the table in plural, and the model in it's singular, like: table -> configurations and the model configuration). In that file you can add this:
public function getDescriptionAttribute($value)
{
return json_decode($value, true);
}
Now, the description field is returned as an array.
You can see more about accessors and mutators here: http://laravel.com/docs/4.2/eloquent#accessors-and-mutators

Resources