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

Discovery Laravel Package

psr-discovery/discovery

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install via Composer:

    composer require psr-discovery/discovery
    

    For a specific PSR implementation (e.g., PSR-18 HTTP Client):

    composer require psr-discovery/http-client-implementations
    
  2. First Use Case: Discover a PSR-18 HTTP Client in a Laravel service:

    use Psr\Discovery\DiscoveryInterface;
    use Psr\Discovery\DiscoveryExceptionInterface;
    use Psr\Http\Client\ClientInterface;
    
    // In a service provider or constructor
    $discovery = new \Psr\Discovery\Discovery();
    $client = $discovery->discover(ClientInterface::class);
    
  3. Where to Look First:


Implementation Patterns

Core Workflow

  1. Discovery in Service Providers: Bind discovered interfaces to Laravel’s container in register():

    $this->app->singleton(ClientInterface::class, function ($app) {
        return resolve(DiscoveryInterface::class)->discover(ClientInterface::class);
    });
    
  2. Lazy-Loading Dependencies: Use discovery in constructors to defer resolution until needed:

    public function __construct(private ClientInterface $client) {}
    
  3. Integration with Laravel’s HTTP Client: Prefer Laravel’s native Http facade for simplicity, but use discovery for third-party SDKs:

    // Instead of:
    $client = new \GuzzleHttp\Client();
    
    // Use:
    $client = resolve(ClientInterface::class);
    

Advanced Patterns

  • Fallback Chains: Combine discovery with manual fallbacks for critical paths:

    try {
        $client = resolve(DiscoveryInterface::class)->discover(ClientInterface::class);
    } catch (DiscoveryExceptionInterface) {
        $client = new \GuzzleHttp\Client(); // Fallback
    }
    
  • Testing with Mocks: Override discovery in tests to inject mocks:

    $this->app->instance(DiscoveryInterface::class, new MockDiscovery());
    
  • Dynamic PSR Selection: Use discovery to switch implementations based on environment (e.g., stub in tests, guzzle in production):

    $discovery = new \Psr\Discovery\Discovery();
    $discovery->addPsr18ClientImplementation(\GuzzleHttp\Client::class);
    

Gotchas and Tips

Pitfalls

  1. Missing Implementations:

    • Error: DiscoveryException if no implementations are found.
    • Fix: Ensure required PSR meta-packages are installed (e.g., psr-discovery/http-client-implementations).
    • Debug: Run composer why-not psr-discovery/http-client-implementations to check dependencies.
  2. Priority Conflicts:

    • Discovery returns the first matching class in autoload order. Explicitly order implementations:
      $discovery = new \Psr\Discovery\Discovery();
      $discovery->addPsr18ClientImplementation(\Laravel\Http\Client\PendingRequest::class, 10); // Higher priority
      
  3. Singleton Caching:

    • Discovery caches results by default. Clear cache if implementations change:
      $discovery->clearCache();
      
  4. Laravel-Specific Quirks:

    • Avoid mixing discovery with Laravel’s built-in bindings (e.g., HttpClient facade). Use one or the other for consistency.
    • Example Conflict:
      // ❌ Avoid: Mixing discovery with Laravel's HttpClient
      $this->app->bind(ClientInterface::class, fn() => resolve(DiscoveryInterface::class)->discover(ClientInterface::class));
      $this->app->bind(ClientInterface::class, \Laravel\Http\Client\Factory::class); // Overrides!
      

Debugging Tips

  1. List Available Implementations:

    $discovery = new \Psr\Discovery\Discovery();
    $implementations = $discovery->getPsr18ClientImplementations();
    dd($implementations); // Debug available classes
    
  2. Check Autoload Order: Use composer dump-autoload to refresh classmap if discovery behaves unexpectedly.

  3. Environment-Specific Config: Override discovery in config/app.php for environment-specific implementations:

    'discovery' => [
        'psr18_clients' => [
            env('APP_ENV') === 'testing' ? \Nyholm\Psr7\MockClient::class : \GuzzleHttp\Client::class,
        ],
    ],
    

Extension Points

  1. Custom Discovery Logic: Extend \Psr\Discovery\Discovery to add custom resolution rules:

    class CustomDiscovery extends \Psr\Discovery\Discovery {
        public function discoverWithFallback(string $interface, callable $fallback): object {
            try {
                return $this->discover($interface);
            } catch (DiscoveryExceptionInterface) {
                return $fallback();
            }
        }
    }
    
  2. PSR-15 Middleware Integration: Use discovery to dynamically load middleware for HTTP clients:

    $client = resolve(ClientInterface::class);
    $client->withMiddleware(new \Psr\Http\Message\Middleware\MiddlewareStack());
    
  3. Testing Utilities: Create a test helper to reset discovery state:

    function resetDiscovery(): void {
        $discovery = resolve(DiscoveryInterface::class);
        $discovery->clearCache();
        $discovery->clearImplementations();
    }
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
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
christhompsontldr/laravel-inky