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

Graphqlite Symfony Validator Bridge Laravel Package

besmartand-pro/graphqlite-symfony-validator-bridge

Bridge package connecting Symfony Validator with GraphQLite, enabling automatic validation of GraphQL input/arguments using Symfony constraints and returning structured validation errors in GraphQL responses. Suitable for Symfony apps using GraphQLite.

View on GitHub
Deep Wiki
Context7

Implementation Patterns

1. Schema-Level Validation with Annotations

Leverage Symfony’s annotations for type-hinted validation in GraphQLite schemas. Example:

use GraphQL\Type\Definition\Type;
use Besmartand\GraphQLite\SymfonyValidatorBridge\Annotation\ValidatedInputType;
use Doctrine\Common\Annotations\Annotation\Target;

/**
 * @ValidatedInputType(
 *     constraints={
 *         @Assert\Email(),
 *         @Assert\NotBlank()
 *     }
 * )
 */
class UserInputType extends InputType {
    public function __construct() {
        parent::__construct([
            'name' => 'UserInput',
            'fields' => [
                'email' => Type::string(),
                'password' => Type::string(),
            ],
        ]);
    }
}

Workflow:

  • Annotate input types with @ValidatedInputType.
  • Use ValidatorBridge in resolvers to auto-validate:
    $validator = app(ValidatorBridge::class);
    $validator->validate($args); // Automatically checks annotations
    

2. Dynamic Validation Rules via YAML/XML

For non-annotated projects, define constraints externally: config/validation/user.yaml:

UserInput:
  email: { required: true, type: email }
  password: { required: true, min: 8 }

Resolver Integration:

$validator = app(ValidatorBridge::class);
$errors = $validator->validate($args, 'UserInput'); // Loads from YAML

3. Nested Object Validation

Validate complex types recursively: Schema:

$addressType = new InputType([
    'name' => 'AddressInput',
    'fields' => [
        'street' => Type::string(),
        'city' => Type::string(),
    ],
    'validator' => function (ValidatorBridge $validator, array $input) {
        return $validator->validate($input, [
            'street' => 'required|string',
            'city' => 'required|string',
        ]);
    },
]);

$userType = new InputType([
    'name' => 'UserInput',
    'fields' => [
        'name' => Type::string(),
        'address' => $addressType,
    ],
]);

Resolver:

$validator = app(ValidatorBridge::class);
$validator->validate($args['user'], [
    'name' => 'required',
    'address' => new CallbackConstraint(function ($address) {
        return $validator->validate($address, [
            'street' => 'required',
            'city' => 'required',
        ]);
    }),
]);

4. Custom Constraint Integration

Extend Symfony’s constraints for domain-specific rules: Custom Constraint:

use Symfony\Component\Validator\Constraint;

/**
 * @Annotation
 */
class ValidLaravelUser extends Constraint {
    public $message = 'This user is not active.';
    public function validatedBy() { return 'valid_laravel_user'; }
}

Validator Service:

use Symfony\Component\Validator\Constraints\Callback;

$validator->validate($user, [
    'id' => new ValidLaravelUser(),
    'email' => new Callback(function ($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL);
    }),
]);

5. Error Mapping to GraphQL Errors

Convert Symfony validation errors to GraphQL-compatible format:

use Besmartand\GraphQLite\SymfonyValidatorBridge\Exception\ValidationException;

try {
    $validator->validate($args);
} catch (ValidationException $e) {
    throw new GraphQLValidationError([
        'errors' => array_map(function ($error) {
            return [
                'field' => $error->getPropertyPath(),
                'message' => $error->getMessage(),
            ];
        }, $e->getErrors()),
    ]);
}

6. Performance Optimization

  • Cache Constraints: Use Symfony’s constraint caching:
    $validator->setConstraintCache(new FileCache('/path/to/cache'));
    
  • Lazy Validation: Defer validation for non-critical fields:
    $validator->validate($args, [
        'name' => 'required',
        'optionalField' => new LazyConstraint(function () {
            return new Assert\NotBlank();
        }),
    ]);
    

7. Integration with Laravel’s Form Requests

Reuse existing Laravel validation logic:

use App\Http\Requests\StoreUserRequest;

$validator = app(ValidatorBridge::class);
$errors = $validator->validate($args, StoreUserRequest::rules());

8. Testing Validation Logic

Unit-test constraints independently:

public function testEmailValidation()
{
    $validator = $this->app->make(ValidatorBridge::class);
    $errors = $validator->validate(['email' => 'invalid'], [
        'email' => 'email',
    ]);
    $this->assertCount(1, $errors);
}

Gotchas and Tips

Pitfalls

  1. Annotation Parsing Failures

    • Issue: Annotations may not load if autoloading is misconfigured.
    • Fix: Ensure composer dump-autoload is run and doctrine/annotations is installed:
      composer require doctrine/annotations
      composer dump-autoload
      
  2. Circular Dependencies in Validation

    • Issue: Nested validation can cause infinite loops if not careful.
    • Fix: Use CallbackConstraint with depth limits or break cycles manually.
  3. Symfony Validator Initialization

    • Issue: Validator may not be bootstrapped if Symfony’s DI isn’t fully loaded.
    • Fix: Explicitly bind the validator in Laravel’s container:
      $this->app->bind('validator', function () {
          return Validation::makeContainerValidator();
      });
      
  4. Error Message Localization

    • Issue: Default error messages may not match your app’s language.
    • Fix: Configure Symfony’s translator:
      $validator = app(ValidatorBridge::class);
      $validator->setTranslator($this->app->make('translator'));
      
  5. GraphQLite Schema Caching

    • Issue: Schema changes may not reflect if cached.
    • Fix: Clear GraphQLite’s cache after adding/removing constraints:
      php artisan graphqlite:clear-cache
      
  6. Constraint Overrides

    • Issue: Rules in YAML/XML may override annotations silently.
    • Fix: Explicitly set priority in ValidatorBridge:
      $validator->setConstraintSourcePriority('annotation'); // or 'yaml'
      

Debugging Tips

  1. Enable Symfony Validator Debug Mode

    $validator->setDebug(true);
    
    • Logs constraint validation steps to storage/logs/validator.log.
  2. Inspect Validation Groups Use named groups to isolate validation:

    $validator->validate($args, 'UserInput', ['group' => 'create']);
    
  3. Validate Constraints Independently Test constraints in isolation:

    $constraint = new Assert\Email();
    $validator->validate('test@example.com', $constraint);
    
  4. GraphQL Error Tracing Enable GraphQLite’s error tracing:

    $schema->setErrorFormatter(function ($error) {
        return [
            'message' => $error->getMessage(),
            'path' => $error->getPath(),
            'extensions' => [
                'validator' => $error->getValidatorErrors(),
            ],
        ];
    });
    

Extension Points

  1. Custom Error Formats Extend GraphQLValidationError to format errors for your API:

    class CustomValidationError extends GraphQLValidationError {
        public function __construct(array $errors) {
            parent::__construct([
                'errors' => array_map(function ($error) {
                    return [
                        'field' => $error->getPropertyPath(),
                        'message' => __($error->getMessage()),
                        'code' => $error->getCode(),
                    ];
                }, $errors),
            ]);
        }
    }
    
  2. Dynamic Constraint Loading Load constraints from a database or API:

    $validator->setConstraintLoader(function ($type) {
        return DB::table('validation_rules')->where('type', $type)->get();
    });
    
  3. Integration with Laravel Policies Validate against Laravel’s authorization:

    $validator->validate($user, [
        'id' => new Callback(function ($id) {
            return auth()->user()->can('update', User::find($id));
        }),
    ]);
    
  4. Validation Middleware Create a GraphQL middleware for global validation:

    $schema->addMiddleware(function ($root, $args, $context, $info) {
        $validator = app(ValidatorBridge::class);
        $validator->validate($args, 'GlobalRules');
    });
    

Configuration Quirks

  1. Validator Service Binding Ensure the validator is bound after Symfony’s DI is initialized:
    $this->app->afterResolving('validator',
    
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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime