Laravel Eloquent multiple wheres gives wrong results - laravel

Why this code below is returning wrong results?
$player->wins = Game::where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id)
->where('result', '=','1') // 1 = win
->get();
$player->losses = Game::where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id)
->where('result', '=','0') // 0 = lose
->get();
$player->matches = Game::where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id)
->get();
What i get is like 5matches / 5 wins / 5losses when in real its 5/5/0. How should i do it?

Move your home_player_x clauses into a nested where condition clause:
$player->wins = Game::where(function ($query) use ($player) {
return $query->where('home_player_1', $player->id)
->orWhere('home_player_2', $player->id)
->orWhere('home_player_3', $player->id)
->orWhere('home_player_4', $player->id);
})->where('result', 1)
->get();
...
This way, it doesn't conflict with that last ->where('result') clause.
Additionally, since you're reusing this clause multiple times, define it as a variable, and reuse it:
$conditional = function ($query) use ($player) {
return $query->where(function ($subQuery) use ($player) {
return $subQuery->orWhere('home_player_1', $player->id)
->orWhere('home_player_2', $player->id)
->orWhere('home_player_3', $player->id)
->orWhere('home_player_4', $player->id);
})
});
$player->wins = Game::where($conditional)->where('result', 1)->get();
$player->losses = Game::where($conditional)->where('result', 0)->get();
$player->matches = Game::where($conditional)->get();
Or, consider defining this as a Scope on the Game model, so you can call Game::playerMatches($player)->where('result', 1)->get(), etc. See the Documentation for that:
https://laravel.com/docs/8.x/eloquent#local-scopes
I won't really touch too much on this, but defining numbered columns, like home_player_1, home_player_2, etc. is generally considered bad data practice. You should define a home_players table, or games_players, with a type column for home or away table and associate Game and Players that way.

Check out the post on Logical Grouping in the Laravel Docs. I think based on that, your statement for matches should be:
$player->matches = Game::where(function ($query) use ($player) {
$query->where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id);
})->get();
I am not sure if this helps as I do not have the rest of the code, but please test it and let me know.
Also from the docs:
"In fact, you should generally always group calls to the orWhere method in parentheses in order to avoid unexpected query behavior."

Need to modify the orWhere() condition, Instead of above you can use below where clause:
$player->wins = Game::where('result', '=','1') // 1 = win
->where(function ($query) use ($player) {
$query->where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id);
})->get();
$player->losses = Game::where('result', '=', '0') // 0 = lose
->where(function ($query) use ($player) {
$query->where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id);
})->get();
$player->matches = Game::
where(function ($query) use ($player) {
$query->where('home_player_1', '=', $player->id)
->orWhere('home_player_2', '=', $player->id)
->orWhere('home_player_3', '=', $player->id)
->orWhere('home_player_4', '=', $player->id);
})->get();
When there were multiple orWhere() then normal conditions do not work, Need to add them under a single where.

Related

How to reuse parts of Eloquent builder in Laravel

Is there a way to reuse parts of a query in Laravel? For example if I have two queries which share some arbitrarily long section, can I create a function/variable that can be used in place of that section?
Toy queries:
$a = TableA::join('tableb', 'tablea.bid', '=', tableb.id)
->join('talbec', 'tableb.cid', '=', tablec.id)
->join('tabled', 'tablec.did', '=', tabled.id)
->where('tablea_col', '=', true)->get();
$b = TableA::join('tableb', 'tablea.bid', '=', tableb.id)
->join('talbec', 'tableb.cid', '=', tablec.id)
->join('tabled', 'tablec.did', '=', tabled.id)
->where('tableb_col', '=', true)->get();
I would like something like:
$shared = TableA::join('tableb', 'tablea.bid', '=', tableb.id)
->join('talbec', 'tableb.cid', '=', tablec.id)
->join('tabled', 'tablec.did', '=', tabled.id);
$a = shared->where('tablea_col', '=', true)->get();
$b = shared->where('tableb_col', '=', true)->get();
From Laravel 8+, you can clone it then reuse as you wish:
$shared = TableA::join('tableb', 'tablea.bid', '=', tableb.id)
->join('talbec', 'tableb.cid', '=', tablec.id)
->join('tabled', 'tablec.did', '=', tabled.id);
$a = $shared->clone()->where('tablea_col', '=', true)->get();
$b = shared->clone()->where('tableb_col', '=', true)->get();
before Laravel 8, use
$a = clone $shared;
$b = clone $shared;
$a = $a->where('tablea_col', '=', true)->get();
$b = $b->where('tableb_col', '=', true)->get();
You should be able to use a scope for this:
function scopeWithBCandD($query) {
$query->join('tableb', 'tablea.bid', '=', 'tableb.id')
->join('talbec', 'tableb.cid', '=', 'tablec.id')
->join('tabled', 'tablec.did', '=', 'tabled.id');
}
Which would permit:
TableA::withBCandD()->where('tablea_col', true)->get();
TableA::withBCandD()->where('tableb_col', true)->get();

How to join two queries as one in whereIn

In my Laravel-5.8 I have these queries:
$manager = DB::table('hr_employees')
->select('line_manager_id')
->where('hr_status',0)
->whereIn('employee_code', $employee_with_goals)
->get();
$employee_with_goals = DB::table('hr_employees')
->join('appraisal_goals', 'hr_employees.employee_code', '=', 'appraisal_goals.employee_code')
->select('hr_employees.employee_code')
->where('hr_employees.company_id', $userCompany)
->where('hr_employees.hr_status',0)
->where('appraisal_goals.is_published', '=', '1')
->where('appraisal_goals.is_approved', '=', '3')
->groupBy('hr_employees.employee_code')
->get();
$manager is the main query
How do I combine these two queries as one using $employee_with_goals as the variable in whereIn()?
You can use the pluck method to retrieve all values for a given key in a collection:
$manager = DB::table('hr_employees')
->select('line_manager_id')
->where('hr_status',0)
->whereIn('employee_code', $employee_with_goals->pluck('employee_code'))
->get();
You can actually use a subquery too:
$manager = DB::table('hr_employees')
->select('line_manager_id')
->where('hr_status',0)
->whereIn('employee_code', function ($query) use ($userCompany) {
$query
->table('hr_employees')
->select('hr_employees.employee_code')
->join('appraisal_goals', 'hr_employees.employee_code', '=', 'appraisal_goals.employee_code')
->where('hr_employees.company_id', $userCompany)
->where('hr_employees.hr_status',0)
->where('appraisal_goals.is_published', '=', '1')
->where('appraisal_goals.is_approved', '=', '3')
->groupBy('hr_employees.employee_code')
})
->get();
The code above is untested.

How I can ignore current row id one time only

I have custom query where ignored current row id:
$relatedVacancies = \App\Vacancy::whereHas('skills', function ($q) use ($vacancy) {
return $q->whereIn('skill_id', $vacancy->skills->pluck('skill_id'));
})->where('id', '!=', $vacancy->id)
->orWhere('employment', $vacancy->employment)->where('id', '!=', $vacancy->id)
->orWhere('title', 'like', '%'.$vacancy->title.'%')->where('id', '!=', $vacancy->id)
->get();
How I can use this condition one time only:
->where('id', '!=', $vacancy->id)
If you are trying to select based on three conditions:
->where([
('id', '!=', $vacancy->id),
('employment', '=', $vacancy->employment),
('title', 'like', '%'.$vacancy->title.'%'),
])->get();
Try this (based on https://laravel.com/docs/5.7/queries#parameter-grouping):
$relatedVacancies = \App\Vacancy::where('id', '!=', $vacancy->id)
->whereHas('skills', function ($q) use ($vacancy) {
return $q->whereIn('skill_id', $vacancy->skills->pluck('skill_id'));
})
->where(function ($query) {
$query->where('employment', $vacancy->employment)
->orWhere('title', 'like', '%'.$vacancy->title.'%');
})
->get();
Also check for this answer: https://stackoverflow.com/a/23009807/5458355

Laravel 5.2 : How to write query builder with 2 ON in this right join

I have this sql syntax
SELECT vehicles.license_plate, vehicles.year, vehicles.status, vehicles.zone_id, vehicles.car_class_id, harga_sewa.value, harga_sewa.description
FROM `vehicles`
RIGHT JOIN `harga_sewa` ON vehicles.zone_id = harga_sewa.zone_id
AND vehicles.car_class_id = harga_sewa.car_class_id
How I can write something like this?
DB::table('vehicles')
->rightJoin('harga_sewa', 'vehicles.zone_id', '=', 'harga_sewa.zone_id', AND vehicles.car_class_id = harga_sewa.car_class_id)
->select(*)
Try below code
DB::table('vehicles')
->rightJoin('harga_sewa', function ($join) {
$join->on('vehicles.zone_id', '=', 'harga_sewa.zone_id');
$join->on('vehicles.car_class_id', '=', 'harga_sewa.car_class_id');
})
->get();
On mobile, so can't test, but from memory this should work:
DB::table('vehicles')
->rightJoin('harga_sewa', 'vehicles.zone_id', '=', 'harga_sewa.zone_id')
->rightJoin('harga_sewa', 'vehicles.car_class_id', '=', 'harga_sewa.car_class_id')
->select('*')
->get();

Laravel Clear Model Queries

I have this code but I am not sure if is possible be more compact or I´m not sure if this is the way should looks this type of queries in laravel.
public function getRoleTransactionNameByID($id)
{
$role_transaction= $this->model->select(
'roles_transactions.id',
'roles.id as role_id',
'roles.role_name',
'modules.module_name',
'transactions.transaction_name',
'transactions.transaction_description',
'roles_transactions.transaction_action_id',
'transaction_actions.transaction_action_name',
'roles_transactions.created_at',
'roles_transactions.updated_at')
->join('roles', 'roles_transactions.role_id', '=', 'roles.id')
->join('transactions', 'roles_transactions.transaction_id', '=', 'transactions.id')
->join('transaction_actions', 'roles_transactions.transaction_action_id', '=', 'transaction_actions.id' )
->leftjoin('modules','transactions.module_id', '=', 'modules.id')
->where('roles_transactions.id', '=', $id)
->where('roles_transactions.deleted_at','=', null)
->orderby('roles.role_name', 'ASC')
->orderby('modules.module_name', 'ASC')
->orderby('transactions.transaction_name', 'ASC')
->get();
return $role_transaction;
}
Thank you for the help.

Resources