diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 6b91a673676a..6dbca8dde7fa 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Concerns; use Illuminate\Container\Container; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\MultipleRecordsFoundException; use Illuminate\Database\RecordsNotFoundException; use Illuminate\Pagination\CursorPaginator; @@ -305,7 +306,11 @@ protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = $builder->where(function (self $builder) use ($addCursorConditions, $cursor, $orders, $i) { ['column' => $column, 'direction' => $direction] = $orders[$i]; - $builder->where($column, $direction === 'asc' ? '>' : '<', $cursor->parameter($column)); + $builder->where( + $this->getOriginalColumnNameForCursorPagination($this, $column), + $direction === 'asc' ? '>' : '<', + $cursor->parameter($column) + ); if ($i < $orders->count() - 1) { $builder->orWhere(function (self $builder) use ($addCursorConditions, $column, $i) { @@ -327,6 +332,32 @@ protected function paginateUsingCursor($perPage, $columns = ['*'], $cursorName = ]); } + /** + * Get the original column name of the given column, without any aliasing. + * + * @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder $builder + * @param string $parameter + * @return string + */ + protected function getOriginalColumnNameForCursorPagination($builder, string $parameter) + { + $columns = $builder instanceof Builder ? $builder->getQuery()->columns : $builder->columns; + + if (! is_null($columns)) { + foreach ($columns as $column) { + if (stripos($column, ' as ') !== false) { + [$original, $alias] = explode(' as ', $column); + + if ($parameter === $alias) { + return $original; + } + } + } + } + + return $parameter; + } + /** * Create a new length-aware paginator instance. * diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php index 741f296632f6..32bdf8843a0d 100755 --- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php +++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php @@ -862,6 +862,24 @@ public function simplePaginate($perPage = null, $columns = ['*'], $pageName = 'p }); } + /** + * Paginate the given query into a cursor paginator. + * + * @param int|null $perPage + * @param array $columns + * @param string $cursorName + * @param string|null $cursor + * @return \Illuminate\Contracts\Pagination\CursorPaginator + */ + public function cursorPaginate($perPage = null, $columns = ['*'], $cursorName = 'cursor', $cursor = null) + { + $this->query->addSelect($this->shouldSelect($columns)); + + return tap($this->query->cursorPaginate($perPage, $columns, $cursorName, $cursor), function ($paginator) { + $this->hydratePivotRelation($paginator->items()); + }); + } + /** * Chunk the results of the query. * diff --git a/src/Illuminate/Pagination/AbstractCursorPaginator.php b/src/Illuminate/Pagination/AbstractCursorPaginator.php index 72698705205e..e65c0cb12e14 100644 --- a/src/Illuminate/Pagination/AbstractCursorPaginator.php +++ b/src/Illuminate/Pagination/AbstractCursorPaginator.php @@ -6,6 +6,8 @@ use Closure; use Exception; use Illuminate\Contracts\Support\Htmlable; +use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\Pivot; use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; @@ -195,7 +197,10 @@ public function getParametersForItem($item) return collect($this->parameters) ->flip() ->map(function ($_, $parameterName) use ($item) { - if ($item instanceof ArrayAccess || is_array($item)) { + if ($item instanceof Model && + ! is_null($parameter = $this->getPivotParameterForItem($item, $parameterName))) { + return $parameter; + } elseif ($item instanceof ArrayAccess || is_array($item)) { return $this->ensureParameterIsPrimitive( $item[$parameterName] ?? $item[Str::afterLast($parameterName, '.')] ); @@ -209,6 +214,26 @@ public function getParametersForItem($item) })->toArray(); } + /** + * Get the cursor parameter value from a pivot model if applicable. + * + * @param \ArrayAccess|\stdClass $item + * @param string $parameterName + * @return string|null + */ + protected function getPivotParameterForItem($item, $parameterName) + { + $table = Str::beforeLast($parameterName, '.'); + + foreach ($item->getRelations() as $relation) { + if ($relation instanceof Pivot && $relation->getTable() === $table) { + return $this->ensureParameterIsPrimitive( + $relation->getAttribute(Str::afterLast($parameterName, '.')) + ); + } + } + } + /** * Ensure the parameter is a primitive type. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index 6a511b9232e1..8f07c34c9ffb 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -4271,7 +4271,7 @@ protected function getMySqlBuilderWithProcessor() } /** - * @return m\MockInterface|Builder + * @return \Mockery\MockInterface|\Illuminate\Database\Query\Builder */ protected function getMockQueryBuilder() {