Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use column searches in same table relations #2871

Open
affaron opened this issue Oct 7, 2022 · 3 comments
Open

Can't use column searches in same table relations #2871

affaron opened this issue Oct 7, 2022 · 3 comments

Comments

@affaron
Copy link

affaron commented Oct 7, 2022

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:

if (! in_array($table, $joins)) {
$this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
}

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

@yajra yajra added the Self Join label Oct 8, 2022
@yajra
Copy link
Owner

yajra commented Oct 8, 2022

@affaron thank you for investigating. This is currently a package limitation and doesn't work yet with a self-join relationship. If you can add a support for it, please do not hesitate to submit a PR.

@DjVinnii
Copy link

DjVinnii commented Sep 6, 2023

Is there any update on this? It looks like I'm running into the same problem. To me it seems the addition of aliases should fix this problem.

@affaron
Copy link
Author

affaron commented Sep 6, 2023

Is there any update on this? It looks like I'm running into the same problem. To me it seems the addition of aliases should fix this problem.

I can share my final solution or make a PR a bit later (updated version of the code I mentioned in the original post)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants