- How do I integrate Symfony OptionsResolver into Laravel’s service container for reusable configuration validation?
- Bind the resolver as a singleton in `AppServiceProvider` using `app()->singleton(OptionsResolver::class, fn() => new OptionsResolver())`, then inject it into services via constructor or resolve via `app()->make(OptionsResolver::class)`. For shared schemas, define defaults in `setDefaults()` with closures (e.g., `fn() => config('services.stripe')`) to merge Laravel config dynamically.
- Can OptionsResolver replace Laravel’s manual `array_replace_recursive` for nested service configurations?
- Yes. Use `setDefaults()` for static values and `setNormalizers()` for transformations (e.g., converting strings to arrays). For example, replace `array_replace_recursive($config, $defaults)` with `$resolver->resolve($config)`, which enforces types, validates values, and handles nested structures automatically. This eliminates runtime errors from misconfigured arrays.
- What Laravel versions and PHP versions does symfony/options-resolver v7.4/v8.0 support?
- The package works with Laravel 9+ (PHP 8.1+) and Laravel 10+ (PHP 8.2+). For v7.4, use PHP 8.2+; for v8.0, PHP 8.4+. Lock your `composer.json` to `^7.4` or `^8.0` to avoid compatibility issues. Laravel’s service container and config system integrate seamlessly with both versions, but test edge cases like null values or circular references in nested resolvers.
- How do I handle dynamic defaults (e.g., environment-specific values) in Laravel with OptionsResolver?
- Use closures in `setDefaults()` to fetch dynamic values, such as `fn() => config('services.'.env('APP_ENV').'.defaults')`. For environment-aware defaults, combine with Laravel’s `config()` helper or `env()` calls. This avoids hardcoding values and lets you override configurations per environment without modifying the resolver schema.
- Should I use OptionsResolver for form validation in Laravel, or is it better for service configurations?
- OptionsResolver excels at service/config validation (e.g., API clients, queue workers) where you need strict schemas, but for forms, Laravel’s built-in validation (Form Requests) is often simpler. Use OptionsResolver when you need pre-validation for complex nested structures, like `config('services.stripe.webhook_signing_secret')`, or when third-party packages require enforced schemas.
- How do I test OptionsResolver in Laravel to ensure it catches misconfigurations early?
- Write unit tests for resolver schemas using PHPUnit or Pest, mocking inputs to verify validation (e.g., `assertThrowsExceptionIf($resolver->resolve(['invalid_key' => 'value']))`). For integration tests, use Laravel’s `MockFacade` to simulate service container bindings. Test edge cases like null values, circular references, and deprecated options with `setDeprecated()` and custom assertions.
- What’s the performance impact of using OptionsResolver in high-traffic Laravel APIs?
- OptionsResolver adds minimal overhead—benchmark resolution time for critical services (e.g., API gateways) by comparing `microtime(true)` before/after `$resolver->resolve()`. For most use cases, the cost is negligible (~1–5ms per resolution). Cache resolvers as singletons in the container to avoid reinstantiation. If performance is critical, profile with Laravel Forge or Blackfire.
- Can I migrate from manual `array_replace_recursive` or custom validation logic to OptionsResolver without breaking changes?
- Yes. Start by auditing `array_replace_recursive` usages with `grep -r` and replace them incrementally. For custom validation, refactor logic into `setAllowedValues()`, `setAllowedTypes()`, or `setNormalizers()`. Use `setDeprecated()` to log warnings for legacy configs during migration. Test thoroughly with existing configs to ensure backward compatibility.
- How do I log deprecation warnings for legacy configurations when using OptionsResolver in Laravel?
- Use `setDeprecated()` to mark options as deprecated, then log warnings via Laravel’s `Log` facade or Symfony’s `ErrorHandler`. For example: `$resolver->setDeprecated('old_key', '2024-01-01', 'Use new_key instead');`. Trigger warnings in a `ResolvedEvent` listener or `boot()` method of a service provider to centralize logging.
- Are there Laravel-specific alternatives to OptionsResolver for configuration validation?
- Laravel’s native `config()` system and validation rules (e.g., `ValidatedData`) handle basic cases, but OptionsResolver provides advanced features like nested structure validation, normalizers, and pre-validation for services. Alternatives like `spatie/laravel-config-array` are simpler but lack type safety. For domain-specific rules, OptionsResolver’s extensibility (custom validators, normalizers) makes it the best fit for complex configurations.