• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

api-platform / core / 13724522058

07 Mar 2025 04:04PM UTC coverage: 8.175% (-0.3%) from 8.518%
13724522058

Pull #7005

github

web-flow
Merge 322407532 into 1e0bc9dc8
Pull Request #7005: fix(validation): deprecate string message for ValidationException con…

4 of 6 new or added lines in 1 file covered. (66.67%)

159 existing lines in 24 files now uncovered.

12839 of 157045 relevant lines covered (8.18%)

13.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/docs/guides/custom-pagination.php
1
<?php
2
// ---
3
// slug: custom-pagination
4
// name: Custom pagination
5
// executable: true
6
// position: 12
7
// tags: expert
8
// ---
9

10
// In case you're using a custom collection (through a Provider), make sure you return the `Paginator` object to get the full hydra response with `view` (which contains information about first, last, next and previous page).
11
//
12
// The following example shows how to handle it using a custom Provider. You will need to use the Doctrine Paginator and pass it to the API Platform Paginator.
13

14
namespace App\Entity {
15
    use ApiPlatform\Metadata\ApiResource;
16
    use ApiPlatform\Metadata\GetCollection;
17
    use App\Repository\BookRepository;
18
    use App\State\BooksListProvider;
19
    use Doctrine\ORM\Mapping as ORM;
20

21
    /* Use custom Provider on operation to retrieve the custom collection */
22
    #[ApiResource(
23
        operations: [
×
24
            new GetCollection(provider: BooksListProvider::class),
×
25
        ]
×
26
    )]
×
27
    #[ORM\Entity(repositoryClass: BookRepository::class)]
28
    class Book
29
    {
30
        #[ORM\Id, ORM\Column, ORM\GeneratedValue]
31
        public ?int $id = null;
32

33
        #[ORM\Column]
34
        public ?string $title = null;
35

36
        #[ORM\Column(name: 'is_published', type: 'boolean')]
37
        public ?bool $published = null;
38
    }
39
}
40

41
namespace App\Repository {
42
    use App\Entity\Book;
43
    use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
44
    use Doctrine\Common\Collections\Criteria;
45
    use Doctrine\ORM\Tools\Pagination\Paginator as DoctrinePaginator;
46
    use Doctrine\Persistence\ManagerRegistry;
47

48
    class BookRepository extends ServiceEntityRepository
49
    {
50
        public function __construct(ManagerRegistry $registry)
51
        {
52
            parent::__construct($registry, Book::class);
×
53
        }
54

55
        public function getPublishedBooks(int $page = 1, int $itemsPerPage = 30): DoctrinePaginator
56
        {
57
            /* Retrieve the custom collection and inject it into a Doctrine Paginator object */
58
            return new DoctrinePaginator(
×
59
                $this->createQueryBuilder('b')
×
60
                     ->where('b.published = :isPublished')
×
61
                     ->setParameter('isPublished', true)
×
62
                     ->addCriteria(
×
63
                         Criteria::create()
×
64
                             ->setFirstResult(($page - 1) * $itemsPerPage)
×
65
                             ->setMaxResults($itemsPerPage)
×
66
                     )
×
67
            );
×
68
        }
69
    }
70
}
71

72
namespace App\State {
73
    use ApiPlatform\Doctrine\Orm\Paginator;
74
    use ApiPlatform\Metadata\Operation;
75
    use ApiPlatform\State\Pagination\Pagination;
76
    use ApiPlatform\State\ProviderInterface;
77
    use App\Repository\BookRepository;
78

79
    class BooksListProvider implements ProviderInterface
80
    {
81
        public function __construct(private readonly BookRepository $bookRepository, private readonly Pagination $pagination)
82
        {
83
        }
×
84

85
        public function provide(Operation $operation, array $uriVariables = [], array $context = []): Paginator
86
        {
87
            /* Retrieve the pagination parameters from the context thanks to the Pagination object */
88
            [$page, , $limit] = $this->pagination->getPagination($operation, $context);
×
89

90
            /* Decorates the Doctrine Paginator object to the API Platform Paginator one */
91
            return new Paginator($this->bookRepository->getPublishedBooks($page, $limit));
×
92
        }
93
    }
94
}
95

96
namespace App\Playground {
97
    use Symfony\Component\HttpFoundation\Request;
98

99
    function request(): Request
100
    {
101
        return Request::create('/books.jsonld', 'GET');
×
102
    }
103
}
104

105
namespace DoctrineMigrations {
106
    use Doctrine\DBAL\Schema\Schema;
107
    use Doctrine\Migrations\AbstractMigration;
108

109
    final class Migration extends AbstractMigration
110
    {
111
        public function up(Schema $schema): void
112
        {
113
            $this->addSql('CREATE TABLE book (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, title VARCHAR(255) NOT NULL, is_published SMALLINT NOT NULL)');
×
114
        }
115
    }
116
}
117

118
namespace App\Fixtures {
119
    use App\Entity\Book;
120
    use Doctrine\Bundle\FixturesBundle\Fixture;
121
    use Doctrine\Persistence\ObjectManager;
122
    use Zenstruck\Foundry\AnonymousFactory;
123

124
    use function Zenstruck\Foundry\faker;
125

126
    final class BookFixtures extends Fixture
127
    {
128
        public function load(ObjectManager $manager): void
129
        {
130
            /* Create books published or not */
131
            $factory = AnonymousFactory::new(Book::class);
×
132
            $factory->many(5)->create(static function (int $i): array {
×
133
                return [
×
134
                    'title' => faker()->title(),
×
135
                    'published' => false,
×
136
                ];
×
137
            });
×
138
            $factory->many(35)->create(static function (int $i): array {
×
139
                return [
×
140
                    'title' => faker()->title(),
×
141
                    'published' => true,
×
142
                ];
×
143
            });
×
144
        }
145
    }
146
}
147

148
namespace App\Tests {
149
    use ApiPlatform\Playground\Test\TestGuideTrait;
150
    use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
151
    use App\Entity\Book;
152

153
    final class BookTest extends ApiTestCase
154
    {
155
        use TestGuideTrait;
156

157
        public function testTheCustomCollectionIsPaginated(): void
158
        {
159
            $response = static::createClient()->request('GET', '/books.jsonld');
×
160

161
            $this->assertResponseIsSuccessful();
×
162
            $this->assertMatchesResourceCollectionJsonSchema(Book::class, '_api_/books{._format}_get_collection', 'jsonld');
×
163
            $this->assertNotSame(0, $response->toArray(false)['totalItems'], 'The collection is empty.');
×
164
            $this->assertJsonContains([
×
165
                'totalItems' => 35,
×
166
                'view' => [
×
167
                    '@id' => '/books.jsonld?page=1',
×
168
                    '@type' => 'PartialCollectionView',
×
169
                    'first' => '/books.jsonld?page=1',
×
170
                    'last' => '/books.jsonld?page=2',
×
171
                    'next' => '/books.jsonld?page=2',
×
172
                ],
×
173
            ]);
×
174
        }
175
    }
176
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc