CountryStateCollectionProvider.php 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. <?php
  2. namespace Webkul\BagistoApi\State;
  3. use ApiPlatform\Laravel\Eloquent\Paginator;
  4. use ApiPlatform\Metadata\Operation;
  5. use ApiPlatform\State\Pagination\Pagination;
  6. use ApiPlatform\State\ProviderInterface;
  7. use Illuminate\Pagination\LengthAwarePaginator;
  8. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  9. use Webkul\BagistoApi\Models\CountryState;
  10. /**
  11. * Collection provider for CountryState
  12. *
  13. * Provides cursor-based pagination for country states
  14. * - Subresource: /countries/{country_id}/states (country_id provided via URI)
  15. * - Direct query: countryStates(countryId: 244) (countryId REQUIRED in args for GraphQL and REST)
  16. */
  17. class CountryStateCollectionProvider implements ProviderInterface
  18. {
  19. public function __construct(
  20. private readonly Pagination $pagination,
  21. ) {}
  22. public function provide(Operation $operation, array $uriVariables = [], array $context = []): object|array|null
  23. {
  24. // Handle both 'country_id' (snake_case from URI) and 'countryId' (camelCase from args)
  25. $countryId = $uriVariables['country_id'] ?? $uriVariables['countryId'] ?? null;
  26. $args = $context['args'] ?? [];
  27. // Also check for countryId in GraphQL args (for direct countryStates query)
  28. if (! $countryId && isset($args['countryId'])) {
  29. $countryId = (int) $args['countryId'];
  30. }
  31. // Enforce: countryId is REQUIRED when querying country states directly
  32. if (! $countryId) {
  33. throw new BadRequestHttpException(
  34. __('bagistoapi::app.graphql.country-state.country-id-required')
  35. );
  36. }
  37. $first = isset($args['first']) ? (int) $args['first'] : null;
  38. $last = isset($args['last']) ? (int) $args['last'] : null;
  39. $after = $args['after'] ?? null;
  40. $before = $args['before'] ?? null;
  41. $defaultPerPage = 10;
  42. // Determine page size
  43. if ($first !== null) {
  44. $perPage = $first;
  45. } elseif ($last !== null) {
  46. $perPage = $last;
  47. } else {
  48. $perPage = $defaultPerPage;
  49. }
  50. $offset = 0;
  51. if ($after) {
  52. $decoded = base64_decode($after, true);
  53. $offset = ctype_digit((string) $decoded) ? ((int) $decoded + 1) : 0;
  54. }
  55. if ($before) {
  56. $decoded = base64_decode($before, true);
  57. $cursor = ctype_digit((string) $decoded) ? (int) $decoded : 0;
  58. $offset = max(0, $cursor - $perPage);
  59. }
  60. $query = CountryState::where('country_id', $countryId)
  61. ->with('translations')
  62. ->orderBy('id', 'asc');
  63. $total = (clone $query)->count();
  64. if ($offset > $total) {
  65. $offset = max(0, $total - $perPage);
  66. }
  67. $items = $query
  68. ->offset($offset)
  69. ->limit($perPage)
  70. ->get();
  71. $currentPage = $total > 0 ? (int) floor($offset / $perPage) + 1 : 1;
  72. return new Paginator(
  73. new LengthAwarePaginator(
  74. $items,
  75. $total,
  76. $perPage,
  77. $currentPage,
  78. ['path' => request()->url()]
  79. )
  80. );
  81. }
  82. }