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

Query Parameter Bundle Laravel Package

ekreative/query-parameter-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require ekreative/query-parameter-bundle
    
  2. Register Bundle: Add new Ekreative\QueryParameterBundle\EkreativeQueryParameterBundle() to AppKernel.php (or config/bundles.php for Symfony 4+).
  3. Ensure Dependencies: Verify sensio/framework-extra-bundle and Symfony’s OptionResolver/PropertyAccess are installed.

First Use Case

Validate a boolean query parameter in a controller:

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Ekreative\QueryParameterBundle\Annotation\QueryParameter;

/**
 * @Route("/search")
 * @QueryParameter("active", type="boolean", options={"required" = false, "default" = false})
 */
public function searchAction(bool $active) {
    // $active is now a validated boolean (true/false)
}

Implementation Patterns

1. Basic Query Parameter Validation

Use @QueryParameter for simple, single-field validation:

/**
 * @QueryParameter("page", type="integer", options={"required" = true, "min" = 1})
 */
public function listAction(int $page) {
    // $page is guaranteed to be an integer ≥ 1
}

2. Complex Filter Objects (@QueryModel)

For multi-field validation, create a DTO (e.g., Filter class) and annotate:

// src/Filter/TestFilter.php
class TestFilter {
    /** @QueryParameter("min_age", type="integer", options={"default" = 18}) */
    public $minAge;

    /** @QueryParameter("is_active", type="boolean") */
    public $isActive;
}

Controller:

/**
 * @QueryModel("filter", class="AppBundle\Filter\TestFilter")
 */
public function advancedSearch(TestFilter $filter) {
    // $filter->minAge and $filter->isActive are validated
}

3. Integration with Symfony Forms

Reuse validation logic in forms:

use Symfony\Component\Form\Extension\Core\Type\IntegerType;

// In a form builder:
$builder->add('page', IntegerType::class, [
    'constraints' => [
        new Assert\Type(['type' => 'integer']),
        new Assert\GreaterThan(['value' => 0]),
    ],
]);

Tip: Mirror @QueryParameter constraints in forms for consistency.

4. Dynamic Route Parameters

Combine with Sensio’s @ParamConverter for hybrid validation:

/**
 * @Route("/user/{id}")
 * @QueryParameter("sort", type="string", options={"allowed_values" = {"name", "email"}})
 * @ParamConverter("user", converter="doctrine")
 */
public function userAction(User $user, string $sort) {
    // $sort is validated against ["name", "email"]
}

5. API Resource Filtering

Validate nested query parameters for API pagination/sorting:

/**
 * @QueryModel("pagination", class="AppBundle\Filter\PaginationFilter")
 */
public function apiListAction(PaginationFilter $pagination) {
    // $pagination->page, $pagination->limit, $pagination->sort are validated
}

Gotchas and Tips

Pitfalls

  1. Missing Dependencies:

    • If sensio/framework-extra-bundle is missing, annotations won’t work. Install via:
      composer require sensio/framework-extra-bundle
      
    • For Symfony 4+, use symfony/flex or manually add to config/bundles.php.
  2. Type Mismatches:

    • The bundle uses Symfony’s OptionResolver, so types must match PHP’s strict typing (e.g., integerint in older PHP versions).
    • Fix: Use type="integer" (string) or type="bool" (boolean) explicitly.
  3. Annotation Override:

    • @QueryParameter overrides route parameters. If you have:
      @Route("/user/{id}")
      @QueryParameter("id", type="integer")
      
      The route {id} will be ignored in favor of the query string.
  4. Default Values:

    • default values are not merged with route defaults. Specify one or the other:
      // Bad: May conflict
      @Route("/user/{id}", defaults={"id" = 1})
      @QueryParameter("id", type="integer", options={"default" = 2})
      
      // Good: Explicit choice
      @QueryParameter("id", type="integer", options={"default" = 1})
      
  5. Circular References:

    • Avoid circular dependencies in QueryModel classes (e.g., FilterA referencing FilterB which references FilterA).

Debugging Tips

  1. Enable Annotation Debugging: Add to config/packages/framework.yaml:

    framework:
        annotations:
            cache: null  # Disable cache to see raw annotations
    

    Then check var/log/dev.log for parsed annotations.

  2. Validation Errors:

    • Invalid parameters throw InvalidArgumentException. Catch globally in a listener:
      // src/EventListener/QueryValidationListener.php
      public function onKernelException(GetResponseForExceptionEvent $event) {
          $exception = $event->getException();
          if ($exception instanceof \InvalidArgumentException &&
              strpos($exception->getMessage(), 'QueryParameter') !== false) {
              $event->setResponse(new JsonResponse(['error' => $exception->getMessage()], 400));
          }
      }
      
      Register in services.yaml:
      services:
          App\EventListener\QueryValidationListener:
              tags:
                  - { name: kernel.event_listener, event: kernel.exception }
      
  3. Type-Specific Quirks:

    • datetime: Expects YYYY-MM-DD or ISO 8601 strings. Use options={"format" = "Y-m-d H:i:s"} for custom formats.
    • double: May parse 1.23 as 1 in some PHP versions. Use options={"scale" = 2} to enforce precision.

Extension Points

  1. Custom Validators: Extend the bundle’s QueryParameterValidator (located in Ekreative\QueryParameterBundle\Validator\QueryParameterValidator) to add custom rules:

    // src/Validator/CustomQueryValidator.php
    use Ekreative\QueryParameterBundle\Validator\QueryParameterValidatorInterface;
    
    class CustomQueryValidator implements QueryParameterValidatorInterface {
        public function validate($value, array $options) {
            if ($options['type'] === 'custom' && $value !== 'allowed') {
                throw new \InvalidArgumentException('Custom validation failed');
            }
            return $value;
        }
    }
    

    Register as a service:

    services:
        App\Validator\CustomQueryValidator:
            tags:
                - { name: ekreative.query_parameter.validator, type: custom }
    
  2. Override Default Types: Replace the default validator for a type (e.g., integer) by implementing QueryParameterValidatorInterface and tagging it with the desired type:

    services:
        App\Validator\CustomIntegerValidator:
            tags:
                - { name: ekreative.query_parameter.validator, type: integer }
    
  3. Event Dispatching: Listen for ekreative.query_parameter.validated events to log or modify validated values:

    use Ekreative\QueryParameterBundle\Event\QueryParameterValidatedEvent;
    
    public function onQueryParameterValidated(QueryParameterValidatedEvent $event) {
        $event->setValue(strtoupper($event->getValue())); // Example: Force uppercase
    }
    

    Register:

    services:
        App\EventListener\QueryParameterListener:
            tags:
                - { name: kernel.event_listener, event: ekreative.query_parameter.validated }
    
  4. Configuration Overrides: Override bundle defaults in config/packages/ekreative_query_parameter.yaml:

    ekreative_query_parameter:
        strict_types: true  # Enable strict type checking
        default_locale: en_US  # For datetime parsing
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
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