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

Options Resolver Laravel Package

symfony/options-resolver

Symfony OptionsResolver enhances array_replace with a robust options system: define required options, set defaults, validate types and values, and normalize inputs. Ideal for building configurable APIs, form components, and reusable libraries with strict option handling.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • High Fit for Laravel Ecosystem: The package is designed to complement Laravel’s existing validation and configuration systems (e.g., Form Requests, config() helpers) while addressing gaps in nested/conditional validation and normalization. It integrates seamlessly with Laravel’s Service Container and Dependency Injection, enabling resolved options to be injected directly into services.
  • Modular and Lightweight: As a standalone component (not a full framework), it avoids bloat and can be adopted incrementally. Its declarative API (setDefaults(), setRequired(), setNormalizer()) aligns with Laravel’s philosophy of explicit, readable configuration.
  • Symfony Ecosystem Synergy: If the team already uses other Symfony components (e.g., HttpClient, Process), this provides consistency in configuration patterns.

Integration Feasibility

  • Laravel-Specific Advantages:
    • Service Container Integration: Resolved options can be registered as bindings or resolved via closures, replacing manual array_merge logic in service constructors.
    • Form Requests: Can pre-process and validate incoming request data before Laravel’s validation pipeline runs (e.g., normalize enum strings to constants).
    • Config Files: Replace ad-hoc config() array merging with structured, validated configurations (e.g., config('services.stripe') resolved via OptionsResolver).
  • PHP Version Compatibility:
    • PHP 8.2+: Required for v7.4.x (supports union/intersection types).
    • PHP 8.4+: Required for v8.0.x (future-proofing for newer PHP features).
    • Backward Compatibility: v6.4.x supports older PHP versions but lacks modern type features.

Technical Risk

  • Low Risk for Greenfield Projects: The component is battle-tested (used by Symfony, Drupal, and 3,000+ other projects) with a stable API. Breaking changes are rare and well-documented (e.g., deprecation of setDefault() for nested options in v8.0).
  • Migration Risk for Legacy Code:
    • Manual array_replace Logic: Replacing ad-hoc array merging with OptionsResolver requires refactoring, but the payoff (validation, normalization) is significant.
    • Nested Configurations: If existing code relies on deeply nested array_replace_recursive, the resolver’s explicit setOptions() method for nested structures may require adjustments.
  • Dependency Overhead:
    • Adds ~1MB to vendor size (negligible for most Laravel apps).
    • No runtime performance penalty—resolution is fast and cached-friendly.

Key Questions

  1. Scope of Adoption:
    • Should we start with high-risk areas (e.g., payment gateways, third-party APIs) or adopt globally for all configurations?
    • Which existing configurations are most error-prone and would benefit most from validation?
  2. PHP Version Constraints:
    • Can we upgrade to PHP 8.2+ to leverage v7.4.x’s union types and deprecation features?
    • If not, will v6.4.x’s limitations (e.g., no union types) block critical use cases?
  3. Team Familiarity:
    • Does the team have experience with Symfony components? If not, will the learning curve slow adoption?
    • Should we wrap the resolver in a custom facade (e.g., ConfigResolver) to simplify Laravel integration?
  4. Testing Impact:
    • How will this affect existing unit tests that mock or assert on raw config arrays?
    • Should we introduce factory methods (e.g., resolveStripeConfig()) to encapsulate resolver logic?
  5. Deprecation Strategy:
    • How will we handle legacy configurations that need to be deprecated? Will we use the resolver’s built-in deprecation warnings or implement a custom solution?
  6. Performance:
    • For high-throughput services (e.g., queue workers), is the resolver’s overhead negligible, or should we optimize further (e.g., cache resolved options)?

Integration Approach

Stack Fit

  • Laravel-Specific Integrations:
    • Service Container: Bind the resolver as a singleton or per-request service:
      $this->app->singleton(OptionsResolver::class, fn() => new OptionsResolver());
      
    • Form Requests: Use the resolver to pre-process and validate input before Laravel’s validation:
      public function rules()
      {
          $resolved = resolve(OptionsResolver::class)->resolve($this->all());
          return ['timeout' => 'required|integer', ...];
      }
      
    • Config Files: Replace config('services.stripe') with a resolved object:
      $stripeConfig = resolve(StripeConfigResolver::class)->resolve(config('services.stripe'));
      
    • Jobs/Commands: Validate job payloads or command options:
      public function handle()
      {
          $options = resolve(OptionsResolver::class)->resolve($this->options);
          // Use $options->timeout, etc.
      }
      
  • Symfony Compatibility:
    • If using Symfony’s HttpClient, the resolver’s validation aligns with Symfony’s configuration patterns.
    • For custom packages, the resolver provides a standardized way to define configuration contracts.

Migration Path

  1. Phase 1: Pilot in High-Risk Areas
    • Start with third-party API clients (e.g., Stripe, Twilio) where misconfigurations are costly.
    • Replace manual validation logic with OptionsResolver:
      // Before
      $config = array_replace([
          'timeout' => 30,
          'endpoint' => 'https://api.example.com',
      ], $userInput);
      
      // After
      $resolver = new OptionsResolver();
      $resolver->setDefaults(['timeout' => 30])
               ->setRequired(['endpoint'])
               ->setAllowedTypes('timeout', 'int');
      $config = $resolver->resolve($userInput);
      
  2. Phase 2: Standardize Configuration Contracts
    • Create resolver classes for reusable configurations (e.g., DatabaseConfigResolver, CacheConfigResolver).
    • Example:
      class DatabaseConfigResolver
      {
          public function __invoke(array $config): array
          {
              $resolver = new OptionsResolver();
              $resolver->setDefaults([
                  'driver' => 'mysql',
                  'host' => 'localhost',
                  'port' => 3306,
              ]);
              $resolver->setAllowedValues('driver', ['mysql', 'pgsql', 'sqlite']);
              return $resolver->resolve($config);
          }
      }
      
  3. Phase 3: Integrate with Laravel’s Ecosystem
    • Bind resolvers to the Service Container for dependency injection.
    • Extend Form Requests or Console Commands to use resolved options.
  4. Phase 4: Deprecate Legacy Configurations
    • Use the resolver’s deprecation features to warn when old config keys are used:
      $resolver->setDeprecated('old_key', 'new_key');
      

Compatibility

  • Laravel Versions:
    • Compatible with Laravel 9+ (PHP 8.0+) and Laravel 10+ (PHP 8.1+).
    • For Laravel 8, use v6.4.x (PHP 7.4+) but miss modern features.
  • PHP Extensions:
    • No additional extensions required beyond standard PHP libraries.
  • Existing Code:
    • Low Risk: The resolver can be used opt-in for specific configurations without affecting unrelated code.
    • High Risk: Deeply nested array_replace_recursive logic may need refactoring to use setOptions() for nested structures (v8.0+).

Sequencing

  1. Assess Current Configurations:
    • Identify pain points (e.g., runtime errors from invalid configs, manual validation logic).
    • Prioritize areas with highest failure rates (e.g., payment processing, database connections).
  2. Upgrade PHP (if needed):
    • Target PHP 8.2+ to use v7.4.x’s union types and deprecation features.
  3. Pilot with a Single Service:
    • Example: Replace manual Stripe config validation with OptionsResolver.
  4. Standardize Resolver Usage:
    • Create base resolver classes for common use cases (e.g., API clients, jobs).
  5. Integrate with Laravel’s DI:
    • Bind resolvers to the container and inject resolved options into services.
  6. Deprecate Legacy Configs:
    • Use resolver warnings to phase out old configuration keys.
  7. Document Patterns:
    • Publish internal guidelines for when/where to use OptionsResolver (e.g., "Always use for third-party API configs").

Operational Impact

Maintenance

  • Pros:
    • Reduced Boilerplate: Eliminates repetitive validation logic (e.g
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport