From c8609475178d0e9747daf574b1969065f51a5285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alfaiate?= Date: Mon, 28 Apr 2025 17:25:59 +0700 Subject: [PATCH 1/2] fix: prevent ambiguous column names --- src/EloquentDataTable.php | 12 ++++++------ src/QueryDataTable.php | 33 +++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/EloquentDataTable.php b/src/EloquentDataTable.php index edcb9294..bb16943b 100644 --- a/src/EloquentDataTable.php +++ b/src/EloquentDataTable.php @@ -167,7 +167,7 @@ protected function resolveRelationColumn(string $column): string $relation = str_replace('[]', '', implode('.', $parts)); if ($this->isNotEagerLoaded($relation)) { - return $column; + return parent::resolveRelationColumn($column); } return $this->joinEagerLoadedColumn($relation, $columnName); @@ -188,14 +188,14 @@ protected function joinEagerLoadedColumn($relation, $relationColumn) $lastQuery = $this->query; foreach (explode('.', $relation) as $eachRelation) { $model = $lastQuery->getRelation($eachRelation); - $lastAlias = $tableAlias ?: $lastQuery->getModel()->getTable(); + $lastAlias = $tableAlias ?: $this->getTablePrefix($lastQuery); $tableAlias = $tableAlias.'_'.$eachRelation; $pivotAlias = $tableAlias.'_pivot'; switch (true) { case $model instanceof BelongsToMany: $pivot = $model->getTable().' as '.$pivotAlias; $pivotPK = $pivotAlias.'.'.$model->getForeignPivotKeyName(); - $pivotFK = $lastAlias.'.'.$model->getParentKeyName(); + $pivotFK = ltrim($lastAlias.'.'.$model->getParentKeyName(), '.'); $this->performJoin($pivot, $pivotPK, $pivotFK); $related = $model->getRelated(); @@ -211,7 +211,7 @@ protected function joinEagerLoadedColumn($relation, $relationColumn) case $model instanceof HasOneThrough: $pivot = explode('.', $model->getQualifiedParentKeyName())[0].' as '.$pivotAlias; // extract pivot table from key $pivotPK = $pivotAlias.'.'.$model->getFirstKeyName(); - $pivotFK = $lastAlias.'.'.$model->getLocalKeyName(); + $pivotFK = ltrim($lastAlias.'.'.$model->getLocalKeyName(), '.'); $this->performJoin($pivot, $pivotPK, $pivotFK); $related = $model->getRelated(); @@ -227,12 +227,12 @@ protected function joinEagerLoadedColumn($relation, $relationColumn) case $model instanceof HasOneOrMany: $table = $model->getRelated()->getTable().' as '.$tableAlias; $foreign = $tableAlias.'.'.$model->getForeignKeyName(); - $other = $lastAlias.'.'.$model->getLocalKeyName(); + $other = ltrim($lastAlias.'.'.$model->getLocalKeyName(), '.'); break; case $model instanceof BelongsTo: $table = $model->getRelated()->getTable().' as '.$tableAlias; - $foreign = $lastAlias.'.'.$model->getForeignKeyName(); + $foreign = ltrim($lastAlias.'.'.$model->getForeignKeyName(), '.'); $other = $tableAlias.'.'.$model->getOwnerKeyName(); break; diff --git a/src/QueryDataTable.php b/src/QueryDataTable.php index 09d4fa46..b1d0d681 100644 --- a/src/QueryDataTable.php +++ b/src/QueryDataTable.php @@ -388,7 +388,7 @@ public function getQuery(): QueryBuilder */ protected function resolveRelationColumn(string $column): string { - return $column; + return $this->addTablePrefix($this->query, $column); } /** @@ -451,7 +451,7 @@ protected function castColumn(string $column): string */ protected function compileQuerySearch($query, string $column, string $keyword, string $boolean = 'or'): void { - $column = $this->addTablePrefix($query, $column); + $column = $this->wrap($this->addTablePrefix($query, $column)); $column = $this->castColumn($column); $sql = $column.' LIKE ?'; @@ -471,19 +471,32 @@ protected function compileQuerySearch($query, string $column, string $keyword, s protected function addTablePrefix($query, string $column): string { if (! str_contains($column, '.')) { - $q = $this->getBaseQueryBuilder($query); - $from = $q->from ?? ''; + return ltrim($this->getTablePrefix($query).'.'.$column, '.'); + } - if (! $from instanceof Expression) { - if (str_contains((string) $from, ' as ')) { - $from = explode(' as ', (string) $from)[1]; - } + return $column; + } + + /** + * Try to get the base table prefix. + * To be used to prevent ambiguous field name. + * + * @param QueryBuilder|EloquentBuilder $query + */ + protected function getTablePrefix($query): ?string + { + $q = $this->getBaseQueryBuilder($query); + $from = $q->from ?? ''; - $column = $from.'.'.$column; + if (! $from instanceof Expression) { + if (str_contains((string) $from, ' as ')) { + $from = explode(' as ', (string) $from)[1]; } + + return $from; } - return $this->wrap($column); + return null; } /** From 562552b06c3e0af2594adb1300985aea867c7d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Alfaiate?= Date: Tue, 29 Apr 2025 09:24:49 +0700 Subject: [PATCH 2/2] fix: skip prefix on alias columns --- src/QueryDataTable.php | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/QueryDataTable.php b/src/QueryDataTable.php index b1d0d681..f70125b8 100644 --- a/src/QueryDataTable.php +++ b/src/QueryDataTable.php @@ -470,11 +470,23 @@ protected function compileQuerySearch($query, string $column, string $keyword, s */ protected function addTablePrefix($query, string $column): string { - if (! str_contains($column, '.')) { - return ltrim($this->getTablePrefix($query).'.'.$column, '.'); + // Column is already prefixed + if (str_contains($column, '.')) { + return $column; } - return $column; + $q = $this->getBaseQueryBuilder($query); + + // Column is an alias, no prefix required + foreach ($q->columns ?? [] as $select) { + $sql = trim($select instanceof Expression ? $select->getValue($this->getConnection()->getQueryGrammar()) : $select); + if (str_ends_with($sql, ' as '.$column) || str_ends_with($sql, ' as '.$this->wrap($column))) { + return $column; + } + } + + // Add table prefix to column + return $this->getTablePrefix($query).'.'.$column; } /**