Description
Hi!
Recently I discovered an issue when using multiple column search with different relation using the same table. Here's what I mean.
I have a model with relations:
public function country_from()
{
return $this->belongsTo(Country::class, 'from_country_id');
}
public function country_to()
{
return $this->belongsTo(Country::class, 'to_country_id');
}
and two columns in the datatable with these relation (country_from.name, country_to.name). I need to use filtering by both columns at the same time and I got a problem: when the second relation is applied the join is omitted since it's already joined and same table used in WHERE condition:
select
`borders`.*
from
`borders`
left join `countries` on `borders`.`from_country_id` = `countries`.`id`
where
LOWER(`countries`.`name`) LIKE '%south africa%'
and LOWER(`countries`.`name`) LIKE '%zimbabwe%'
This happens because of this code:
laravel-datatables/src/EloquentDataTable.php
Lines 251 to 253 in 9e96d1f
It makes since until you need to join the same table. I figured out a way to make it work like it supposed to in my case, but Im not sure it's PR worth hack and it's not thoroughly tested :) Here's what I did.
Generate an alias for the table if it's already joined and return it with performJoin method (sorry, not the cleanest code):
protected function performJoin($table, $foreign, $other, $type = 'left')
{
$alias = $table;
$joins = [];
foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
$joins[] = Str::before($join->table, ' as ');
}
if (in_array($table, $joins)) {
$index = count(array_filter($joins, function ($n) use ($table) { return $n === $table; })) + 1;
$alias = $table . '_' . $index;
$other = str_replace($table, $alias, $other);
$table = $table . ' as ' . $alias;
}
$this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
return $alias;
}
and use this alias in the end of joinEagerLoadedColumn()
method:
$alias = $this->performJoin($table, $foreign, $other);
$lastQuery = $model->getQuery();
}
return $alias.'.'.$relationColumn;
after that the lib can generate accurate query:
select
`borders`.*
from
`borders`
left join `countries` on `borders`.`from_country_id` = `countries`.`id`
left join `countries_2` on `borders`.`to_country_id` = `countries_2`.`id`
where
LOWER(`countries`.`name`) LIKE '%south africa%'
and LOWER(`countries_2`.`name`) LIKE '%zimbabwe%'
Maybe I'm missing something and there's a native or more simple way to do that without code changes? Please let me know, thanks