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

Apitk Url Bundle Laravel Package

check24/apitk-url-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require check24/apitk-url-bundle
    

    Ensure byWulf/ApiTKUrlBundle is registered in config/bundle.php.

  2. First Use Case: Annotate a controller action to enable filtering, sorting, and pagination:

    use Shopping\ApiTKUrlBundle\Annotation as ApiTK;
    
    /**
     * @Rest\Get("/v1/products")
     * @ApiTK\Filter(name="name")
     * @ApiTK\Sort(name="price", allowedDirections={"asc", "desc"})
     * @ApiTK\Pagination(maxPerPage=50)
     */
    public function getProducts() { ... }
    
  3. Trigger Processing: Add the ApiTKUrlListener to your services.yaml:

    services:
        Shopping\ApiTKUrlBundle\EventListener\ApiTKUrlListener:
            tags:
                - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
    
  4. Test the Endpoint: Call GET /v1/products?filter[name]=laptop&sort[price]=asc&page=1 to see filters/sorting/pagination in action.


Implementation Patterns

1. Filtering Workflows

  • Basic Filtering:

    @ApiTK\Filter(name="status") // Allows `filter[status][eq]=active`
    
    • Supports eq, ne, gt, lt, in, nin comparisons by default.
  • Complex Filtering:

    @ApiTK\Filter(name="created", allowedComparisons={"gt", "lt"})
    @ApiTK\Filter(name="category", enum={"electronics", "clothing"})
    
    • Use allowedComparisons to restrict operators.
    • Use enum for predefined values (validates client input).
  • Joined Table Fields:

    @ApiTK\Filter(name="user.country", queryBuilderName="u.country")
    
    • Map API filter names to query builder aliases (e.g., for Doctrine).
  • Route Parameter Filters: Define filters matching route placeholders (e.g., /users/{id}@ApiTK\Filter(name="id")).


2. Sorting Integration

  • Default Sorting:
    @ApiTK\Sort(name="name") // Allows `sort[name]=asc` or `sort[name]=desc`
    
  • Multi-Field Sorting: Clients can chain sorts: ?sort[name]=asc&sort[price]=desc.
  • Restrict Directions:
    @ApiTK\Sort(name="created", allowedDirections={"asc"})
    

3. Pagination Patterns

  • Basic Pagination:
    @ApiTK\Pagination(maxPerPage=20) // Limits `page[size]` to 20
    
  • Dynamic Limits: Use maxPerPage to enforce a max (e.g., maxPerPage=100).
  • Default Page Size: Set a default via config (apitk_url.default_page_size = 10).

4. Query Builder Integration

  • Doctrine Example:

    $qb = $this->createQueryBuilder('p');
    $applier = new \Shopping\ApiTKUrlBundle\QueryBuilder\FilterApplier($qb);
    $applier->applyFilters($this->get('apitk_url.filter_manager')->getFilters());
    $applier->applySorting($this->get('apitk_url.sort_manager')->getSorting());
    $applier->applyPagination($this->get('apitk_url.pagination_manager')->getPagination());
    
  • Custom Query Builders: Extend FilterApplier or implement FilterApplierInterface for non-Doctrine ORMs.


5. API Documentation

  • Swagger/OpenAPI: Use @ApiTK\Filter/@ApiTK\Sort annotations to auto-generate docs with supported parameters. Example:
    parameters:
      - in: query
        name: filter[name][eq]
        schema:
          type: string
        description: Filter by name (exact match)
    

Gotchas and Tips

Pitfalls

  1. Annotation Loading:

    • Ensure api_platform.meta.factory.doctrine.orm.proxy is not used if annotations aren’t loading.
    • Fix: Use api_platform.meta.factory.doctrine.orm or manually register annotations.
  2. Case Sensitivity:

    • Filter names in annotations are case-sensitive. Use snake_case or camelCase consistently.
  3. Query Builder Conflicts:

    • If queryBuilderName clashes with existing query aliases, rename the alias in your DQL.
    • Tip: Use unique prefixes (e.g., u_country instead of country).
  4. Pagination Edge Cases:

    • Empty Results: Handle page[size]=0 explicitly to avoid "page not found" errors.
    • Max Per Page: Clients may ignore maxPerPage; validate server-side:
      $size = min($request->query->getInt('page[size]', 10), $maxPerPage);
      
  5. Route Overrides:

    • Route parameters (e.g., /users/{id}) take precedence over query filters with the same name.
    • Workaround: Use distinct names (e.g., @ApiTK\Filter(name="user_id")).

Debugging Tips

  1. Enable Verbose Logging: Add to config/packages/dev/apitk_url.yaml:

    apitk_url:
        debug: true
    

    Logs filter/sort/pagination parsing to var/log/dev.log.

  2. Validate Filters:

    • Test with invalid inputs (e.g., filter[nonexistent]=value) to trigger 400 responses.
    • Check ApiTKUrlListener for parsed data:
      $this->get('apitk_url.filter_manager')->getFilters();
      
  3. Query Builder Debugging:

    • Use Doctrine’s getSQL() to inspect generated queries:
      $qb->getQuery()->getSQL();
      

Extension Points

  1. Custom Filter Operators: Extend FilterApplier to add operators like contains:

    public function applyFilter(Filter $filter, QueryBuilder $qb) {
        if ($filter->getComparison() === 'contains') {
            $qb->andWhere("LOWER($filter->getField()) LIKE LOWER(:val)");
            $qb->setParameter('val', "%{$filter->getValue()}%");
        }
    }
    
  2. Dynamic Filter Sources: Fetch filter options from a database:

    @ApiTK\Filter(name="category", dynamicSource="app.get_categories")
    

    Implement DynamicFilterSourceInterface to resolve app.get_categories.

  3. Override Default Behavior:

    • Replace FilterManager, SortManager, or PaginationManager via DI:
      services:
          App\Custom\FilterManager:
              decorates: 'apitk_url.filter_manager'
      
  4. Non-Doctrine ORMs: Create a custom FilterApplier for Eloquent, MongoDB, etc., by implementing FilterApplierInterface.


Performance Tips

  1. Cache Filter Enums: If enum values are static, cache them to avoid repeated DB lookups.

  2. Batch Filter Validation: Validate all filters at once in ApiTKUrlListener to reduce overhead:

    $this->get('apitk_url.filter_manager')->validateAll();
    
  3. Limit Sorting Fields: Restrict sorting to indexed columns to avoid ORDER BY performance hits.

  4. Pagination Offsets: For large datasets, use keyset pagination (e.g., ?after=last_id) instead of OFFSET.

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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware