| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- <?php
- namespace Webkul\BagistoApi\State;
- use ApiPlatform\Laravel\Eloquent\Paginator;
- use ApiPlatform\Metadata\Operation;
- use ApiPlatform\State\Pagination\Pagination;
- use ApiPlatform\State\ProviderInterface;
- use Illuminate\Pagination\LengthAwarePaginator;
- use Webkul\BagistoApi\Models\ProductReview;
- /**
- * Provider for ProductReview queries
- * Handles filtering by product_id, status, and rating
- */
- class ProductReviewProvider implements ProviderInterface
- {
- public function __construct(
- private readonly Pagination $pagination
- ) {}
- public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
- {
- // GraphQL 走 $context['args'];REST 走 request()->query()。
- // 两者合并,REST 查询参数优先,保证 REST 与 GraphQL 行为一致。
- $args = array_merge($context['args'] ?? [], request()->query());
- $query = ProductReview::query();
- // 优先读取商品子资源路由的路径参数(/products/{productId}/reviews),
- // 其次读取查询参数 product_id / productId。
- $productId = $uriVariables['productId']
- ?? $uriVariables['product_id']
- ?? $args['product_id']
- ?? $args['productId']
- ?? null;
- // Apply filters
- if (! empty($productId)) {
- $query->where('product_id', (int) $productId);
- }
- /** Default to approved reviews for storefront API */
- $query->where('status', isset($args['status']) ? (string) $args['status'] : 'approved');
- if (! empty($args['rating'])) {
- $query->where('rating', (int) $args['rating']);
- }
- // 仅返回带图片附件的评论(前端 Photos 筛选)
- if (! empty($args['has_images'])) {
- $hasImages = filter_var($args['has_images'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
- if ($hasImages === true) {
- $query->has('images');
- } elseif ($hasImages === false) {
- $query->doesntHave('images');
- }
- }
- // 按附件类型过滤:image / video
- if (! empty($args['attachment_type'])) {
- $type = (string) $args['attachment_type'];
- $query->whereHas('images', function ($q) use ($type) {
- $q->where('type', $type);
- });
- }
- // Eager load relationships
- $query->with(['product', 'customer']);
- // 分页参数:REST 用 page / per_page(别名 limit),GraphQL 用 first / last / after / before
- $restPage = isset($args['page']) ? max(1, (int) $args['page']) : null;
- $restPerPage = isset($args['per_page'])
- ? (int) $args['per_page']
- : (isset($args['limit']) ? (int) $args['limit'] : null);
- $first = isset($args['first']) ? (int) $args['first'] : null;
- $last = isset($args['last']) ? (int) $args['last'] : null;
- $after = $args['after'] ?? null;
- $before = $args['before'] ?? null;
- if ($restPage !== null || $restPerPage !== null) {
- // REST 分页
- $perPage = $restPerPage !== null ? min(max(1, $restPerPage), 50) : 30;
- $page = $restPage ?? 1;
- $offset = ($page - 1) * $perPage;
- } else {
- // GraphQL 游标分页
- $perPage = $first ?? $last ?? 30;
- $offset = 0;
- if ($after) {
- $decoded = base64_decode($after, true);
- $offset = ctype_digit((string) $decoded) ? ((int) $decoded + 1) : 0;
- }
- if ($before) {
- $decoded = base64_decode($before, true);
- $cursor = ctype_digit((string) $decoded) ? (int) $decoded : 0;
- $offset = max(0, $cursor - $perPage);
- }
- }
- // 排序:sort=newest(按创建时间倒序)或 sort=oldest(默认,按 id 升序)
- $sort = $args['sort'] ?? null;
- /*if ($sort !== null && strtolower((string) $sort) === 'newest') {
- $query->orderBy('created_at', 'desc')->orderBy('id', 'desc');
- } else {
- $query->orderBy('id', 'asc');
- }*/
- $query->orderBy('created_at', 'desc')->orderBy('id', 'desc');
- $total = (clone $query)->count();
- if ($offset > $total) {
- $offset = max(0, $total - $perPage);
- }
- $items = $query
- ->offset($offset)
- ->limit($perPage)
- ->get();
- $currentPage = $total > 0 ? (int) floor($offset / $perPage) + 1 : 1;
- return new Paginator(
- new LengthAwarePaginator(
- $items,
- $total,
- $perPage,
- $currentPage,
- ['path' => request()->url()]
- )
- );
- }
- }
|