Skip to content

Commit fdd0816

Browse files
committed
Better joined table alias tracking
1 parent ee08e77 commit fdd0816

File tree

1 file changed

+90
-48
lines changed

1 file changed

+90
-48
lines changed

src/Repositories/AbstractRepository.php

Lines changed: 90 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public function orderBy($column, $direction)
319319
*/
320320
public function getSearchableKeys()
321321
{
322-
return array_values(array_map(function($value, $key) {
322+
return array_values(array_map(function ($value, $key) {
323323
return (is_array($value) || is_numeric($key) === false) ? $key : $value;
324324
}, $this->searchable, array_keys($this->searchable)));
325325
}
@@ -341,7 +341,8 @@ public function search($queries)
341341
}
342342

343343
return $this->addScopeQuery(function ($query) use ($queries) {
344-
$alias_suffix = 1;
344+
// Keep track of what tables have been joined and their aliases
345+
$joined = [];
345346

346347
foreach ($this->searchable as $param => $columns) {
347348
// It doesn't always have to map to something
@@ -357,62 +358,31 @@ public function search($queries)
357358
$columns = (array)$columns;
358359

359360
// Loop though the columns and look for relationships
360-
foreach ($columns as $key=>$column) {
361+
foreach ($columns as $key => $column) {
361362
@list($joining_table, $options) = explode(':', $column);
362363

363364
if ($options !== null) {
364-
@list($column, $foreign_key, $related_key) = explode(',', $options);
365-
366-
// Allow for overrides
367-
$related_key = $related_key ?: $param;
368-
369-
// We need to join to the intermediate table
370-
$local_table = $this->getModel()->getTable();
371-
372-
// Create an alias for the join
373-
$alias = "join_{$joining_table}_{$alias_suffix}";
374-
375-
// Create the join
376-
$query->join(
377-
"{$joining_table} as {$alias}",
378-
"{$alias}.{$foreign_key}",
379-
"{$local_table}.{$related_key}"
380-
);
365+
@list($column, $foreign_key, $related_key, $alias) = explode(',', $options);
366+
367+
// Join the table if it hasn't already been joined
368+
if (isset($joined[$joining_table]) == false) {
369+
$joined[$joining_table] = $this->addSearchJoin(
370+
$query,
371+
$joining_table,
372+
$foreign_key,
373+
$related_key ?: $param, // Allow for related key overriding
374+
$alias
375+
);
376+
}
381377

382378
// Set a new column search
383-
$columns[$key] = "{$alias}.{$column}";
384-
385-
$alias_suffix++;
379+
$columns[$key] = "{$joined[$joining_table]}.{$column}";
386380
}
387381
}
388382

389-
// Get the range type
390-
$range_type = strtolower(substr($value, 0, 2));
391-
392383
// Perform a range based query if the range is valid
393384
// and the separator matches.
394-
if (substr($value, 2, 1) === ':' && in_array($range_type, $this->range_keys)) {
395-
// Get the true value
396-
$value = substr($value, 3);
397-
398-
switch ($range_type) {
399-
case 'gt':
400-
$query->where($this->appendTableName($columns[0]), '>', $value, 'and');
401-
break;
402-
case 'lt':
403-
$query->where($this->appendTableName($columns[0]), '<', $value, 'and');
404-
break;
405-
case 'ne':
406-
$query->where($this->appendTableName($columns[0]), '<>', $value, 'and');
407-
break;
408-
case 'bt':
409-
// Because this can only have two values
410-
if (count($values = explode(',', $value)) === 2) {
411-
$query->whereBetween($this->appendTableName($columns[0]), $values);
412-
}
413-
break;
414-
}
415-
385+
if ($this->createSearchRangeClause($query, $value, $columns)) {
416386
continue;
417387
}
418388

@@ -747,6 +717,78 @@ protected function createSearchClause(Builder $query, $param, $column, $value, $
747717
}
748718
}
749719

720+
/**
721+
* Add a search join to the query.
722+
*
723+
* @param Builder $query
724+
* @param string $joining_table
725+
* @param string $foreign_key
726+
* @param string $related_key
727+
* @param string $alias
728+
*
729+
* @return string
730+
*/
731+
protected function addSearchJoin(Builder $query, $joining_table, $foreign_key, $related_key, $alias)
732+
{
733+
// We need to join to the intermediate table
734+
$local_table = $this->getModel()->getTable();
735+
736+
// Set the way the table will be join, with an alias or without
737+
$table = $alias ? "{$joining_table} as {$alias}" : $joining_table;
738+
739+
// Create an alias for the join
740+
$alias = $alias ?: $joining_table;
741+
742+
// Create the join
743+
$query->join($table, "{$alias}.{$foreign_key}", "{$local_table}.{$related_key}");
744+
745+
return $alias;
746+
}
747+
748+
/**
749+
* Add a range clause to the query.
750+
*
751+
* @param Builder $query
752+
* @param string $value
753+
* @param array $columns
754+
*
755+
* @return bool
756+
*/
757+
protected function createSearchRangeClause(Builder $query, $value, array $columns)
758+
{
759+
// Get the range type
760+
$range_type = strtolower(substr($value, 0, 2));
761+
762+
// Perform a range based query if the range is valid
763+
// and the separator matches.
764+
if (substr($value, 2, 1) === ':' && in_array($range_type, $this->range_keys)) {
765+
// Get the true value
766+
$value = substr($value, 3);
767+
768+
switch ($range_type) {
769+
case 'gt':
770+
$query->where($this->appendTableName($columns[0]), '>', $value, 'and');
771+
break;
772+
case 'lt':
773+
$query->where($this->appendTableName($columns[0]), '<', $value, 'and');
774+
break;
775+
case 'ne':
776+
$query->where($this->appendTableName($columns[0]), '<>', $value, 'and');
777+
break;
778+
case 'bt':
779+
// Because this can only have two values
780+
if (count($values = explode(',', $value)) === 2) {
781+
$query->whereBetween($this->appendTableName($columns[0]), $values);
782+
}
783+
break;
784+
}
785+
786+
return true;
787+
}
788+
789+
return false;
790+
}
791+
750792
/**
751793
* Handle dynamic static method calls into the method.
752794
*

0 commit comments

Comments
 (0)