如何删除 Laravel 分页响应元对象中的链接?

问题描述 投票:0回答:6

Laravel 默认分页为我提供了默认分页格式的响应,但我想删除页面响应中元对象中的链接

我使用下面的代码来获取页面数据:

public function index()
{
  return response()->json(
     new EntityCollection(Entity::paginate($pageSize))
  );
}

它返回我在代码中称为 EntityCollection 的资源集合中的响应。但我想删除响应中元数据中的链接。

EntityCollection 看起来像这样:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\ResourceCollection;

class EntityCollection extends ResourceCollection
 {

 /**
  * Transform the resource collection into an array.
  *
  * @param  \Illuminate\Http\Request  $request
  * @return array
  */
  public function toArray($request)
  {
     return [
        'data' => $this->collection,
     ];

  }
}

当我使用 EntityCollection 获取列表时,它返回以下格式响应:

{
"data": [
    // data
],
"links": {
    "first": "*url?page_size=1&page=1",
    "last": "*url?page_size=1&page=15",
    "prev": null,
    "next": "*url?page_size=1&page=2"
},
"meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 15,
    "links": [
        {
            "url": null,
            "label": "pagination.previous",
            "active": false
        },
        {
            "url": "*url?page_size=1&page=6",
            "label": 6,
            "active": false
        }
   ],
    "path": "*url",
    "per_page": "1",
    "to": 1,
    "total": 15
 }
}

请给我删除元中链接的方法或在 Laravel 中自定义分页响应的最佳实践。

php laravel pagination lumen
6个回答
3
投票

我的解决方案:


<?php

namespace App\Core\Resources;

use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class AppAnonymousResourceCollection extends AnonymousResourceCollection
{
    public function paginationInformation($request, $paginated, $default): array
    {
        return [
            'pagination' => [
                'currentPage' => $paginated['current_page'],
                'from' => $paginated['from'],
                'lastPage' => $paginated['last_page'],
                'perPage' => $paginated['per_page'],
                'to' => $paginated['to'],
                'total' => $paginated['total'],
            ]
        ];
    }
}

<?php

namespace App\Core\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class AppJsonResource extends JsonResource
{
    public static function collection($resource)
    {
        return tap(new AppAnonymousResourceCollection($resource, static::class), function ($collection) {
            if (property_exists(static::class, 'preserveKeys')) {
                $collection->preserveKeys = (new static([]))->preserveKeys === true;
            }
        });
    }
}

class AcmeResource extends AppJsonResource
{
    /**
     * Transform the resource into an array.
     *
     * @param  Request| null  $request
     * @return array
     */
    public function toArray($request = null): array
    {
        return [
            ...
        ];
    }
}

在控制器上..

return AcmeResource::collection($collection->paginate($limit))
            ->response();

结果:

{
    "data": [
        ...
    ],
    "pagination": {
        "currentPage": 2,
        "from": 4,
        "lastPage": 7,
        "perPage": 3,
        "to": 6,
        "total": 21
    }
}

1
投票

通过从您自己的集合 EntityCollection 创建此方法很简单:

public function paginationInformation($request, $paginated, $default)
{
    unset($default['links']);
    return $default;
}

1
投票

这对我来说始终是一个 PIA。

您将找到的建议/答案将涉及创建多个集合,如果您使用错误的

paginate
方法,可能会出现未定义的键等。

我喜欢做的很简单,我向 Eloquent Builder 添加了一个功能,这样你就可以做

jsonPaginate()

app/Providers/AppServiceProvider.php

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;

public function boot()
{
    Builder::macro('jsonPaginate', function (int $perPage = 15) {
        /** @var Collection $this */
        $json = $this->paginate($perPage)->toArray();
        $json['meta'] = [
            'from'      => $json['from'],
            'to'        => $json['to'],
            'last_page' => $json['last_page'],
            'per_page'  => $json['per_page'],
            'total'     => $json['total'],
        ];
        unset(
            $json['links'],
            $json['path'],
            $json['prev_page_url'],
            $json['first_page_url'],
            $json['last_page_url'],
            $json['next_page_url'],
            $json['current_page'],
            $json['from'],
            $json['to'],
            $json['last_page'],
            $json['per_page'],
            $json['total'],
        );
        return $json;
    });
}

现在你可以像这样使用它:

Route::get('/', function () {
    return App\Models\User::jsonPaginate();
});

PS:

  • DocBlock 是为了绕过从匿名函数/回调中获取
    $this
    时出现的 Intelephense 错误。
  • 我在示例中使用了两种自定义,一种是将某些键“移动”到
    meta
    键中,另一种是删除不需要的键,您可以按照自己想要的方式对其进行自定义。

0
投票

这里的问题是

ResourceCollection
覆盖了您的自定义响应结构并添加了一些额外的属性here。您可以通过重写
toResponse()
方法来修复此(损坏的 IMO)行为,如下所示:

/**
 * {@inheritdoc}
 */
public function toResponse($request)
{
    return JsonResource::toResponse($request);
}

0
投票

我在尝试做同样的事情时遇到了这个问题。使用 Laravel 8,似乎可以做到这一点,但不能使用资源集合。您只需使用您创建的资源类即可。因此,在您的情况下,您不使用

EntityCollection
,而是使用
EntityResource

示例如下:

$results = EntityResource::collection(Entity::paginate($pageSize));

return response()->json([
    'data' => $results,
    'lastPage' => $results->lastPage()
]);

通过这种方法,您基本上可以自己构建元数据。您可以参考 Laravel 的分页文档,了解还有哪些其他方法可用于构建您自己的元数据。

https://laravel.com/docs/8.x/pagination


0
投票
该解决方案对我有用

我在查询表单

paginate()
类中调用了
repository
。我收到了分页回复。因此,我需要在
query level
上处理分页,而不是在
resource response
层中处理分页。即

User::where('user_type', 'attendee')->paginate()
资源调用示例:
$attendees = $this->userRepository->getAttendees($filters);
$attendees = (AttendeeResource::collection($attendees))->response()->getData(true);

当我们使用上述语法调用资源时,它会在幕后调用

AnonymousResourceCollection
类。因此,要全局覆盖分页数据,而不是在多个
Resources
或覆盖
Resource
类中重复相同的内容。我创建了一个
macro
并介绍了我的分页格式。

宏片段:
AnonymousResourceCollection::macro('paginationInformation', function ($request, $paginated, $default) {
    unset($default['links'], $default['meta']['links']);
    return $default;
});
资源类示例:
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class AttendeeResource extends JsonResource
{
    public function __construct($resource)
    {
        parent::__construct($resource);
        self::wrap("users");
    }

    public function toArray(Request $request): array
    {
        return parent::toArray($request);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.