Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Api Paginator Laravel Package

aelfannir/doctrine-api-paginator

Symfony bundle for paginating Doctrine ORM queries with API-friendly filters. Supports property and nested compound filters (AND/OR) and operator-based comparisons to build query conditions cleanly for result lists.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require aelfannir/doctrine-query-paginator
    

    For non-Symfony Flex projects, ensure the bundle is enabled in config/bundles.php:

    AElfannir\DoctrineQueryPaginator\DoctrineQueryPaginatorBundle::class => ['all' => true],
    
  2. First Use Case: Inject the paginator service into your controller/service:

    use AElfannir\DoctrineQueryPaginator\Paginator;
    
    public function __construct(private Paginator $paginator) {}
    

    Use it to paginate a Doctrine query:

    $query = $entityManager->createQueryBuilder()
        ->select('u')
        ->from(User::class, 'u');
    
    $paginatedResults = $this->paginator->paginate($query, $request->query->getInt('page', 1), 10);
    
  3. Key Files to Review:

    • src/Paginator.php (core logic)
    • src/Filter/FilterBuilder.php (filter construction)
    • tests/ (usage examples)

Implementation Patterns

Core Workflow: Paginating Queries

  1. Basic Pagination:

    $query = $em->createQueryBuilder()->select('e')->from(Entity::class, 'e');
    $results = $paginator->paginate($query, $page, $limit);
    

    Returns an array with:

    • data: paginated entities
    • total: total count
    • page: current page
    • limit: items per page
  2. Filter Integration:

    $filter = (new FilterBuilder())
        ->add('name', '=', 'John')
        ->add('age', '>', 18)
        ->build();
    
    $query = $em->createQueryBuilder()->select('e')->from(Entity::class, 'e');
    $paginator->applyFilters($query, $filter);
    
  3. API Response Helper:

    $response = [
        'data' => $results['data'],
        'meta' => [
            'total' => $results['total'],
            'pages' => ceil($results['total'] / $results['limit']),
        ],
    ];
    

Common Patterns

  • Dynamic Filtering:

    $filter = (new FilterBuilder());
    foreach ($request->query->all() as $key => $value) {
        $filter->add($key, 'LIKE', "%{$value}%");
    }
    
  • Nested Compound Filters:

    $filter = (new FilterBuilder())
        ->add('status', '=', 'active')
        ->or()
        ->add('createdAt', '>', new \DateTime('-30 days'))
        ->build();
    
  • Integration with Symfony Serializer:

    use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
    
    $normalized = $serializer->normalize($results['data'], null, [
        AbstractNormalizer::IGNORED_ATTRIBUTES => ['id', 'createdAt'],
    ]);
    

Gotchas and Tips

Pitfalls

  1. QueryBuilder Compatibility:

    • The package assumes standard Doctrine QueryBuilder methods. Avoid custom DQL or native queries.
    • Fix: Use ->expr()-> for complex conditions if needed.
  2. Filter Operator Mismatch:

    • Operators like IN require arrays:
      $filter->add('id', 'IN', [1, 2, 3]); // Correct
      $filter->add('id', 'IN', '1,2,3');   // Fails
      
  3. Case Sensitivity:

    • Property names in filters are case-sensitive. Use getClassMetadata()->getFieldNames() to verify.
  4. Performance:

    • Filters applied via applyFilters() are not counted in COUNT(*). Use getTotal() separately if needed:
      $total = $paginator->getTotal($query, $filter);
      

Debugging Tips

  • Log Filters:

    $filter = (new FilterBuilder())->add('name', '=', 'John')->build();
    \Log::debug($filter->toArray()); // Inspect structure
    
  • Query Dump:

    $query = $em->createQueryBuilder()->select('e')->from(Entity::class, 'e');
    $paginator->applyFilters($query, $filter);
    \Log::debug($query->getQuery()->getSQL()); // Raw SQL
    

Extension Points

  1. Custom Operators: Extend Filter/OperatorInterface and register via service:

    # config/services.yaml
    AElfannir\DoctrineQueryPaginator\Filter\Operator\CustomOperator:
        tags: { name: doctrine_query_paginator.operator }
    
  2. Response Transformers: Override the default response structure by binding a custom service:

    $paginator->setResponseTransformer($customTransformer);
    
  3. Filter Validation: Use Symfony Validator for dynamic filters:

    use Symfony\Component\Validator\Constraints as Assert;
    
    $filter->add('price', new Assert\GreaterThan(0));
    

Configuration Quirks

  • Default Page/Limit: Override via DI:

    $paginator->setDefaultPage(1);
    $paginator->setDefaultLimit(20);
    
  • Bundle Auto-Configuration: If using Symfony Flex, the bundle auto-registers services. For manual setups, ensure services.yaml includes:

    AElfannir\DoctrineQueryPaginator\:
        resource: '../vendor/aelfannir/doctrine-query-paginator/src/'
        exclude: '../vendor/aelfannir/doctrine-query-paginator/src/{Entity,Migrations,Tests,Kernel.php}'
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor