Laravel eloquent query relationship with an added column using selectRaw - php

I started the query like this:
$students = StudRegProfile::with(['my_campus','work_experience' => function($query) {
$query->selectRaw('*, datediff(dateend, datestart) / 360 as years_of_experience');
}]);
Update:
My query is now like this:
$students = StudRegProfile::with(['my_campus','work_experience'])
->withCount([
'work_experience as years_of_experience' => function($query) {
$query->select(\DB::raw('SUM(datediff(dateend, datestart) / 360)'));
}
]);
Now I have years_of_experience as column in work_experience relationship. My output looks like this:
[
id => 1,
work_experience => [
id => 1,
years_of_experience => 2.4417,
]
]
But when I filter it like this:
$students->whereHas('work_experience', function($query) {
$query->whereRaw('years_of_experience >= 2');
});
It can't find my years_of_experience column.
Query Log:
Update:
My StudRegProfile hasMany work_experience. My work experience has datestart and endstart. I want to get the total difference in datestart and endstart so I can filter it as and input in my form

Related

Eloquent where clause returning wrong entries

In my Laravel/Lumen Project (Version 8) I try to retrieve data from my Oracle Database, but I get unexpected data.
My database contains following 4 entries:
ID
FOREIGN_ID
NAME
1
100
Entry1
2
100
Entry2
3
100
Entry3
4
200
Entry4
My model:
class Entry extends Model
{
protected $connection = 'MyConnection';
protected $table = 'MY_TABLE';
protected $fillable = ['foreign_id', 'name'];
protected $hidden = ['foreign_id'];
protected $casts = [
'foreign_id' => 'integer'
];
}
When I execute the following line of code, only Entry1 with ID 1 is returned, while I would expect an empty collection:
Entry::where([['id', '!=', 1], 'foreign_id' => 100, 'name' => 'Entry1'])->get();
To analyze the problem, I also tried to write lined up where clauses:
//returns all but Entry1; correct
Entry::where(['id', '!=', 1])->get();
//returns Entry2 and Entry3; correct
Entry::where(['id', '!=', 1])->where(['foreign_id' => 100])->get();
//returns only Entry1; wrong, should be an empty collection
Entry::where(['id', '!=', 1])->where(['foreign_id' => 100])->where(['name' => 'Entry1'])->get();
The generated sql query looks like this:
"select * from "MY_TABLE" where ("ID" != ? and "FOREIGN_ID" = ? and "NAME" = ?)"
The Lumen Version is: 8.3.4
EDIT:
I have tried this on another Laptop now. There I get an empty collection.
Have you any idea what configuration/setting might do the trick, that my query is interpreted in two different ways?
Try below Code
Entry::where([
['id', '!=', 1],
['foreign_id', 100],
['name', 'Entry1']
])->get();

How I get data by group User ID for foreach controller function in Laravel

How can I get data by grouping user_id for a foreach loop in a controller's function in Laravel. For example, user_id = 2, 5 rows available, user_id = 1, 10 rows available. Then show 2 arrays.
$lists = lists::wherestatus(1)->groupby('user_id')->get();
foreach($lists as $list){
$list = functionHere;
}
What function can I create for this on the controller for grouping?
I need more information, but based on what you shared, you should be able to do this (removing the foreach):
$lists = Lists::whereStatus(1)->get()->groupBy('user_id');
The difference is that if you use groupBy before get, you are grouping your query by user_id, so instead of getting 5 rows for user_id = 2 and 10 for user_id = 1, you are going to get 2 rows and just the latest data, so you need to use Collection's groupBy.
What you want to do is group all the information by user_id but have each row, a schema like this:
[
'1' => [ // user_id
['user_id' => '1', 'column1' => 'random value'],
['user_id' => '1', 'column1' => 'other value'],
// 8 remaining rows
],
'2' => [ // user_id
['user_id' => '2', 'column1' => 'other nice value'],
// 4 remaining rows
],
]
you should first in List model set:
public function scopeStatus(){
return $this->where('status','1');
}
and in your controller:
$products = List::status()->groupby('user_id')->get();

Eloquent: Composite WhereIn condition

Is there a clean way to do a composite WHERE ... IN () condition with Eloquent/laravel.
The query result would be :
SELECT * FROM `table` WHERE (relation_type, relation_id) IN (('App\\Model', 1),('App\\Model', 3))
As you can see, that would be helpful for a single query fetch of an entity with polymorphic relation linked to 5 other models.
My current solution would be pure MySQL:
//Example :array of array with Model name & id
$couples = [
['relation_type' => 'App\\Model', 'relation_id' => 1],
['relation_type' => 'App\\ModelTwo', 'relation_id' => 2],
['relation_type' => 'App\\ModelThree', 'relation_id' => 5],
['relation_type' => 'App\\ModelTwo', 'relation_id' => 20],
//...
['relation_type' => 'App\\Model', 'relation_id' => 999],
];
$query = "SELECT * FROM table WHERE ('relation_type', 'relation_id') IN (("
.implode('),(', array_map(function ($entry) {
return "'".$entry['relation_type']."',".$entry['relation_id']; //I know , in relation_type the '\' needs to be escaped.
}, $couples))
."))";
$results = \DB::select($query);
}
Firstly you are able to put in DB::raw in both column and value, this will solve the problem of getting the SQL query correct, i tested the following on MySql 5.7 and it works. Db::raw just adds raw strings to the query, can be dangerous with injections.
->whereIn(DB::raw('(relation_type, relation_id)'), [DB::raw("('App\\Model', '2')")])
Now we just need to convert your array into that structure, my approach was a array_map foreach can also do the trick.
$couples = array_map(function ($item) {
$type = $item['relation_type'];
$id = $item['relation_id'];
return DB::raw("('$type', '$id')");
}, $couples);
Then call it with a simple Laravel query and you should be good to go.
$models = Model::whereIn(DB::raw('(relation_type, relation_id)'), $couples)->get()

Laravel ORM for Join Multiple Table

I have 9 tables that will love to join together all have the foreign key employee_id from employee table. How can I get ORM distribution for it. Below is the DB function that join all the function.
$modelEmployee = \DB::table('employees')
->select('*')
->join('employee_finances', 'employees.id', '=', 'employee_finances.employee_id')
->join('employee_addresses', 'employees.id', '=', 'employee_addresses.employee_id')
->join('employee_jobs', 'employees.id', '=', 'employee_jobs.employee_id')
->join('employee_admins', 'employees.id', '=', 'employee_admins.employee_id')
->join('employee_personals', 'employees.id', '=', 'employee_personals.employee_id')
->join('employee_memberships', 'employees.id', '=', 'employee_memberships.employee_id')
->where('employees.id', $id)
->get();
Step 1
First, create model for you employee table and add various relations to other table models
Eloquent Model for employees table
namespace App\Models;
class Employee extends \Illuminate\Database\Eloquent\Model {
public function employee_finances()
{
return $this->hasMany(\App\Models\EmployeeFinance);
}
public function employee_addresses()
{
return $this->hasMany(\App\Models\EmployeeAddress);
}
public function employee_jobs()
{
return $this->hasMany(\App\Models\EmployeeJob);
}
public function employee_admins()
{
return $this->hasMany(\App\Models\EmployeeAdmin);
}
public function employee_personals()
{
return $this->hasMany(\App\Models\EmployeePersonal);
}
public function employee_memberships()
{
return $this->hasMany(\App\Models\EmployeeMembership);
}
}
Step 2
Now create models for other join tables. Below is an example of employee_finances table. (similarly, create other models)
namespace App\Models;
class EmployeeFinance extends \Illuminate\Database\Eloquent\Model {
...
}
Step 3
Then for your query, you can use relations using with and whereHas functions of query builder. This equivalent to the result of the query mentioned in the question but the structure of the outcome will be different;
\App\Models\Employee::with('employee_finances','employee_addresses','employee_jobs','employee_admins','employee_personals','employee_memberships')
->whereId($employeeid)
->whereHas('employee_finances')
->whereHas('employee_addresses')
->whereHas('employee_jobs')
->whereHas('employee_admins')
->whereHas('employee_personals')
->whereHas('employee_memberships')
->get();
Result
Original Result object
The original resultant will be an object of common builder object where you cannot fire further relation actions which can be defined in Model level.
The original result will also be a flat array of the result and may have less. One example here would be the id column value would be replaced by the primary employee's table column id.
[
0 => [
'id' => 1,
'employee_name' => 'Employee',
'employee_finance_content' => 'finance_content',
'employee_personal_content' => 'personal_content',
'employee_jobs_content' => 'employee_jobs',
'employee_addresses_content' => 'employee_addresses',
'employee_admins_content' => 'employee_admins',
]
....
]
New result using Models
The result would be an instance of Employee model. The final result would be as an associative array where each relation would be an index of the array but the result will be an instance of the related Model, for example, the employee_finances would be an index or represent a column and the value contained within it will be an instance of EmployeeFinance on which you can further do ORM level activities.
[
0 => [
'id' => 1,
'employee_name' => 'Employee'
'employee_finances' => [
'id' => 2,
'employee_id' => 1,
'employee_finance_content' => 'finance_content'
],
'employee_addresses' => [
'id' => 10,
'employee_id' => 1,
'employee_address_content' => 'employee_address'
]
],
.....
]
you can use from this :
$row = $this->model->
where("id",$id)
->with("employee_finances")
->with("employee_addresses")
->with("employee_jobs")
->with("employee_admins")
->with("employee_personals")
->with("employee_memberships")
->with("employee_finances")
->get();
return $row->isEmpty() ? [] : $row->toArray();
plz define relations in your models with these names and use form that, here.

GroupBy Query Laravel 5.1

I'm having problem in fetching the data using groupBy, I don't where I'm wrong, I have done it many times before, but today I'm wrong some where and I don't know where. Following is the Table from which I want to select the Data:
Table Name: user_questions
id | user_id | message | read_status_user | read_status_support | answered
Now suppose if one user sends more than one messages, then user_id will be repeated, So to want all the message from one particular user I'm firing the query like following:
UserQuestion::groupBy('user_id')->get();
This should give me the result like
user_id = 1 > message1
user_id = 1 > message2
....
user_id = 1 > message...(if any)
user_id = 2 > message1
user_id = 2 > message2
.....
So on...
But this is always giving me only one message from the particular user. I don't know why. Is there any mistake? I have tried another queries too, but all are giving me the same result.
Please help me with this. Everybody's help will be highly appreciated. Thanks to all of you in advance.
The issue here is that you are calling the groupBy function of the query builder object, which is what generates the query for your database. When you call the ->get() method, the query is executed and a Collection object containing the results is returned. What you are looking to use is the groupBy method of Laravel's Collection class, which means you need to put the ->groupBy('user_id') after the ->get().
Assuming you have the following data:
user_question
user_id question_id
1 1
1 2
1 3
2 4
3 5
3 6
Your current code
UserQuestion::groupBy('user_id')->get();
executes this query
select * from user_question group by user_id;
returning one row per user, since that's what group by does in MySQL.
user_id question_id
1 1
2 4
3 5
If instead, you do the following
$collection = UserQuestion::get();
the query is simply
select * from user_question
and when you call $collection->groupBy('user_id') on this collection, you get data structured like
[
1 => [
[ 'user_id' => 1, 'question_id' => 1 ],
[ 'user_id' => 1, 'question_id' => 2 ],
[ 'user_id' => 1, 'question_id' => 3 ]
],
2 => [
[ 'user_id' => 2, 'question_id' => 4 ],
],
3 => [
[ 'user_id' => 3, 'question_id' => 5 ],
[ 'user_id' => 3, 'question_id' => 6 ]
]
]
Try like this
$users = DB::table('table_name')
->groupBy('user_id')
->get();
after that push that to foreach loop
foreach ($users as $user)
{
var_dump($user->name);
}
ordering-grouping-limit-and-offset in Laravel
You've probably found the solution to your problem by now but otherwise, I would suggest to use the relationships. In the User model, I would do:
public function questions()
{
return $this->hasMany('App\UserQuestion');
}
Then I would get all the users and loop through them to get their messages.
$users = User::all();
$users->each(function ($user) {
$questions = User::find($user->id)->questions;
});

Categories