Skip to content

Commit

Permalink
Fixed 2 level nested sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
wasxxm committed Dec 14, 2021
1 parent 44f9da9 commit 87032d7
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 39 deletions.
122 changes: 85 additions & 37 deletions src/ColumnSortable/Sortable.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ trait Sortable

/**
* @param \Illuminate\Database\Query\Builder $query
* @param array|null $defaultParameters
* @param array|null $defaultParameters
*
* @return \Illuminate\Database\Query\Builder
* @throws \Kyslik\ColumnSortable\Exceptions\ColumnSortableException
Expand All @@ -33,9 +33,9 @@ public function scopeSortable($query, $defaultParameters = null)
$defaultParameters = $this->getDefaultSortable();
}

if ( ! is_null($defaultParameters)) {
if (!is_null($defaultParameters)) {
$defaultSortArray = $this->formatToParameters($defaultParameters);
if (config('columnsortable.allow_request_modification', true) && ! empty($defaultSortArray)) {
if (config('columnsortable.allow_request_modification', true) && !empty($defaultSortArray)) {
request()->merge($defaultSortArray);
}

Expand All @@ -55,7 +55,7 @@ private function getDefaultSortable()
{
if (config('columnsortable.default_first_column', false)) {
$sortBy = Arr::first($this->sortable);
if ( ! is_null($sortBy)) {
if (!is_null($sortBy)) {
return [$sortBy => config('columnsortable.default_direction', 'asc')];
}
}
Expand All @@ -66,7 +66,7 @@ private function getDefaultSortable()

/**
* @param \Illuminate\Database\Query\Builder $query
* @param array $sortParameters
* @param array $sortParameters
*
* @return \Illuminate\Database\Query\Builder
*
Expand All @@ -75,6 +75,7 @@ private function getDefaultSortable()
private function queryOrderBuilder($query, array $sortParameters)
{
$model = $this;
$subModel = false;

list($column, $direction) = $this->parseParameters($sortParameters);

Expand All @@ -83,31 +84,50 @@ private function queryOrderBuilder($query, array $sortParameters)
}

$explodeResult = SortableLink::explodeSortParameter($column);
if ( ! empty($explodeResult)) {
$relationName = $explodeResult[0];
$column = $explodeResult[1];

try {
$relation = $query->getRelation($relationName);
$query = $this->queryJoinBuilder($query, $relation);
} catch (BadMethodCallException $e) {
throw new ColumnSortableException($relationName, 1, $e);
} catch (\Exception $e) {
throw new ColumnSortableException($relationName, 2, $e);
if (!empty($explodeResult)) {
if (count($explodeResult) == 3) {
$relationName = $explodeResult[0];
$subRelationName = $explodeResult[1];
$column = $explodeResult[2];
try {
$relation = $query->getRelation($relationName);
$subRelation = $query->getRelation($relationName)->getRelation($subRelationName);
$query = $this->queryJoinBuilder($query, $relation, $subRelation);
} catch (BadMethodCallException $e) {
throw new ColumnSortableException($relationName, 1, $e);
} catch (\Exception $e) {
throw new ColumnSortableException($relationName, 2, $e);
}
$subModel = $subRelation->getRelated();
$model = $relation->getRelated();
} else {
$relationName = $explodeResult[0];
$column = $explodeResult[1];
try {
$relation = $query->getRelation($relationName);
$query = $this->queryJoinBuilder($query, $relation, false);
} catch (BadMethodCallException $e) {
throw new ColumnSortableException($relationName, 1, $e);
} catch (\Exception $e) {
throw new ColumnSortableException($relationName, 2, $e);
}
$model = $relation->getRelated();
}

$model = $relation->getRelated();
}

if (method_exists($model, Str::camel($column).'Sortable')) {
return call_user_func_array([$model, Str::camel($column).'Sortable'], [$query, $direction]);
if (method_exists($model, Str::camel($column) . 'Sortable')) {
return call_user_func_array([$model, Str::camel($column) . 'Sortable'], [$query, $direction]);
}

if (isset($model->sortableAs) && in_array($column, $model->sortableAs)) {
$query = $query->orderBy($column, $direction);
} elseif ($this->columnExists($model, $column)) {
$column = $model->getTable().'.'.$column;
$query = $query->orderBy($column, $direction);
} elseif ($this->columnExists($model, $subModel, $column)) {
if ($subModel) {
$column = $subModel->getTable() . '.' . $column;
} else {
$column = $model->getTable() . '.' . $column;
}
$query = $query->orderBy($column, $direction);
}

return $query;
Expand All @@ -127,7 +147,7 @@ private function parseParameters(array $parameters)
}

$direction = Arr::get($parameters, 'direction', []);
if ( ! in_array(strtolower($direction), ['asc', 'desc'])) {
if (!in_array(strtolower($direction), ['asc', 'desc'])) {
$direction = config('columnsortable.default_direction', 'asc');
}

Expand All @@ -143,28 +163,44 @@ private function parseParameters(array $parameters)
*
* @throws \Exception
*/
private function queryJoinBuilder($query, $relation)
private function queryJoinBuilder($query, $relation, $subRelation)
{
$subRelatedTable = ($subRelation) ? $subRelation->getRelated()->getTable() : false;
$relatedTable = $relation->getRelated()->getTable();
$parentTable = $relation->getParent()->getTable();
$parentTable = $relation->getParent()->getTable();

if ($parentTable === $relatedTable) {
$query = $query->from($parentTable.' as parent_'.$parentTable);
$parentTable = 'parent_'.$parentTable;
$query = $query->from($parentTable . ' as parent_' . $parentTable);
$parentTable = 'parent_' . $parentTable;
$relation->getParent()->setTable($parentTable);
}

if ($relation instanceof HasOne) {
$relatedPrimaryKey = $relation->getQualifiedForeignKeyName();
$parentPrimaryKey = $relation->getQualifiedParentKeyName();
$parentPrimaryKey = $relation->getQualifiedParentKeyName();
} elseif ($relation instanceof BelongsTo) {
$relatedPrimaryKey = $relation->getQualifiedOwnerKeyName();
$parentPrimaryKey = $relation->getQualifiedForeignKeyName();
$parentPrimaryKey = $relation->getQualifiedForeignKeyName();
} else {
throw new \Exception();
}

return $this->formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey);
$subRelatedParentKey = false;
$subRelatedPrimaryKey = false;

if ($subRelation) {
if ($subRelation instanceof HasOne) {
$subRelatedPrimaryKey = $subRelation->getQualifiedForeignKeyName();
$subRelatedParentKey = $subRelation->getQualifiedParentKeyName();
} elseif ($subRelation instanceof BelongsTo) {
$subRelatedPrimaryKey = $subRelation->getQualifiedOwnerKeyName();
$subRelatedParentKey = $subRelation->getQualifiedForeignKeyName();
} else {
throw new \Exception();
}
}

return $this->formJoin($query, $parentTable, $relatedTable, $subRelatedTable, $parentPrimaryKey, $relatedPrimaryKey, $subRelatedParentKey, $subRelatedPrimaryKey);
}


Expand All @@ -174,10 +210,15 @@ private function queryJoinBuilder($query, $relation)
*
* @return bool
*/
private function columnExists($model, $column)
private function columnExists($model, $subModel, $column)
{
return (isset($model->sortable)) ? in_array($column, $model->sortable) :
Schema::connection($model->getConnectionName())->hasColumn($model->getTable(), $column);
if (!$subModel) {
return (isset($model->sortable)) ? in_array($column, $model->sortable) :
Schema::connection($model->getConnectionName())->hasColumn($model->getTable(), $column);
}

return (isset($subModel->sortable)) ? in_array($column, $subModel->sortable) :
Schema::connection($subModel->getConnectionName())->hasColumn($subModel->getTable(), $column);
}


Expand All @@ -199,7 +240,7 @@ private function formatToParameters($array)
}

return (key($array) === 0) ? ['sort' => $array[0], 'direction' => $defaultDirection] : [
'sort' => key($array),
'sort' => key($array),
'direction' => reset($array),
];
}
Expand All @@ -214,10 +255,17 @@ private function formatToParameters($array)
*
* @return mixed
*/
private function formJoin($query, $parentTable, $relatedTable, $parentPrimaryKey, $relatedPrimaryKey)
private function formJoin($query, $parentTable, $relatedTable, $subRelatedTable, $parentPrimaryKey, $relatedPrimaryKey, $subRelatedParentKey, $subRelatedPrimaryKey)
{
$joinType = config('columnsortable.join_type', 'leftJoin');

return $query->select($parentTable.'.*')->{$joinType}($relatedTable, $parentPrimaryKey, '=', $relatedPrimaryKey);
$query->select($parentTable . '.*')
->{$joinType}($relatedTable, $parentPrimaryKey, '=', $relatedPrimaryKey);

if ($subRelatedTable) {
$query->{$joinType}($subRelatedTable, $subRelatedParentKey, '=', $subRelatedPrimaryKey);
}

return $query;
}
}
4 changes: 2 additions & 2 deletions src/ColumnSortable/SortableLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static function explodeSortParameter($parameter)

if (Str::contains($parameter, $separator)) {
$oneToOneSort = explode($separator, $parameter);
if (count($oneToOneSort) !== 2) {
if (count($oneToOneSort) > 3) {
throw new ColumnSortableException();
}

Expand Down Expand Up @@ -268,7 +268,7 @@ private static function buildAnchorAttributesString($anchorAttributes)
}

unset($anchorAttributes['href']);

$attributes = [];
foreach ($anchorAttributes as $k => $v) {
$attributes[] = $k.('' != $v ? '="'.$v.'"' : '');
Expand Down

0 comments on commit 87032d7

Please sign in to comment.