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

Registry Laravel Package

sylius/registry

Sylius Registry component provides a simple service registry to store, retrieve, and manage services by type and name. Useful for decoupling implementations, selecting handlers at runtime, and organizing extensible systems in Symfony/Laravel-style PHP apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package:

    composer require sylius/registry
    

    Ensure autoloading is configured (Laravel handles this automatically).

  2. Define an Interface: Create a shared interface for services you want to register (e.g., PaymentGatewayInterface):

    namespace App\Contracts;
    
    interface PaymentGatewayInterface
    {
        public function processPayment(float $amount): bool;
    }
    
  3. Instantiate the Registry:

    use Sylius\Component\Registry\ServiceRegistry;
    
    $registry = new ServiceRegistry(PaymentGatewayInterface::class);
    
  4. Register a Service:

    $registry->register('stripe', new StripePaymentGateway());
    
  5. Retrieve a Service:

    $stripeGateway = $registry->get('stripe');
    $stripeGateway->processPayment(100.00);
    
  6. Check Existence (Optional):

    if ($registry->has('stripe')) {
        // Service exists
    }
    
  7. Leverage in Laravel (Optional): Bind the registry to Laravel’s container in a service provider:

    use Illuminate\Support\ServiceProvider;
    use Sylius\Component\Registry\ServiceRegistry;
    
    class RegistryServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->singleton('payment.gateway.registry', function () {
                return new ServiceRegistry(PaymentGatewayInterface::class);
            });
        }
    }
    

    Then access it via:

    $registry = app('payment.gateway.registry');
    

Implementation Patterns

Core Workflows

  1. Dynamic Service Loading:

    • Useful for plugins or modular systems where services are loaded at runtime (e.g., from a database or third-party packages).
    • Example: Load payment gateways from a config file:
      $configGateways = config('payment.gateways');
      foreach ($configGateways as $name => $class) {
          $registry->register($name, new $class());
      }
      
  2. Dependency Injection Alternative:

    • Replace manual instantiation with registry lookups in constructors:
      class OrderService
      {
          public function __construct(
              private ServiceRegistry $paymentGatewayRegistry
          ) {}
      
          public function createOrder()
          {
              $gateway = $this->paymentGatewayRegistry->get('stripe');
              // ...
          }
      }
      
  3. Prioritized Registries:

    • Use Sylius\Component\Registry\PrioritizedServiceRegistry for ordered resolution (e.g., fallback payment methods):
      $prioritizedRegistry = new PrioritizedServiceRegistry(PaymentGatewayInterface::class);
      $prioritizedRegistry->register('stripe', new StripeGateway(), 10);
      $prioritizedRegistry->register('paypal', new PaypalGateway(), 5);
      $gateway = $prioritizedRegistry->get(); // Returns StripeGateway (highest priority)
      
  4. Lazy Registration:

    • Register services dynamically based on conditions (e.g., user roles, feature flags):
      if (featureEnabled('new_shipping')) {
          $registry->register('new_shipping', new NewShippingCalculator());
      }
      
  5. Integration with Laravel Events:

    • Register services during event listeners (e.g., after plugin installation):
      use Illuminate\Support\Facades\Event;
      
      Event::listen('plugin.installed', function ($plugin) {
          $registry = app('shipping.calculator.registry');
          $registry->register($plugin->name, $plugin->getCalculator());
      });
      

Laravel-Specific Patterns

  1. Facade for Cleaner Access: Create a facade to simplify registry access:

    // app/Facades/PaymentGatewayRegistry.php
    namespace App\Facades;
    
    use Illuminate\Support\Facades\Facade;
    
    class PaymentGatewayRegistry extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'payment.gateway.registry';
        }
    }
    

    Usage:

    use App\Facades\PaymentGatewayRegistry;
    
    $gateway = PaymentGatewayRegistry::get('stripe');
    
  2. Macros for Extensibility: Extend the registry with custom methods:

    $registry->macro('getByConfig', function ($configKey) {
        $name = config($configKey);
        return $this->get($name);
    });
    

    Usage:

    $gateway = $registry->getByConfig('payment.default_gateway');
    
  3. Service Provider Bootstrapping: Initialize registries with default services in the boot() method:

    public function boot()
    {
        $registry = $this->app['payment.gateway.registry'];
        $registry->register('stripe', new StripeGateway());
        $registry->register('paypal', new PaypalGateway());
    }
    
  4. Testing with Mock Registries: Replace registries in tests using Laravel’s container mocking:

    $this->app->instance('payment.gateway.registry', $mockRegistry);
    

Gotchas and Tips

Pitfalls

  1. Interface Mismatches:

    • Registering a service with the wrong interface will cause a TypeError at runtime.
    • Fix: Validate types during registration or use PHP 8’s is operator:
      if ($service instanceof PaymentGatewayInterface) {
          $registry->register('stripe', $service);
      }
      
  2. Duplicate Keys:

    • Overwriting a key silently replaces the existing service.
    • Fix: Check for existence first or throw an exception:
      if ($registry->has('stripe')) {
          throw new \RuntimeException('Gateway already registered');
      }
      
  3. Prioritized Registry Order:

    • PrioritizedServiceRegistry uses FIFO order for services with the same priority.
    • Tip: Assign unique priorities to avoid unexpected behavior.
  4. Memory Leaks with all():

    • Calling all() returns a new array copy, which can be expensive for large registries.
    • Workaround: Cache the result if the registry is static:
      $services = $registry->all(); // Cache this if possible
      
  5. No Automatic Dependency Injection:

    • Unlike Laravel’s container, the registry does not resolve dependencies automatically.
    • Tip: Manually resolve dependencies or use Laravel’s container for complex cases.
  6. PHP 8+ Compatibility:

    • While the package supports PHP 8, named arguments or other PHP 8.1+ features may break if used in registered services.
    • Test thoroughly after upgrading PHP versions.
  7. Thread Safety Assumptions:

    • The registry is not designed for multi-process environments (e.g., queues, workers).
    • Avoid sharing the same registry instance across processes unless synchronized externally.

Debugging Tips

  1. Check Registered Services: Use all() to inspect the registry contents:

    dd($registry->all());
    
  2. Enable Strict Typing: Add strict_types=1 to your PHP files to catch type-related issues early.

  3. Log Registry Operations: Wrap registry methods in a decorator for debugging:

    $registry->macro('debugGet', function ($key) {
        \Log::debug("Getting service: {$key}");
        return $this->get($key);
    });
    
  4. Handle Missing Services Gracefully: Use has() to avoid exceptions:

    if ($registry->has('fallback_gateway')) {
        $gateway = $registry->get('fallback_gateway');
    } else {
        throw new \RuntimeException('No fallback gateway configured');
    }
    

Extension Points

  1. Custom Registry Classes: Extend ServiceRegistry to add domain-specific logic:

    class PaymentGatewayRegistry extends ServiceRegistry
    {
        public function getDefault(): PaymentGatewayInterface
        {
            $default = config('payment.default_gateway');
            return $this->get($default);
        }
    }
    
  2. Dynamic Registration from Config: Load services from a config file or database:

    $configServices = config('services');
    foreach ($configServices as $name => $serviceConfig) {
        $service = new $serviceConfig['class']($serviceConfig['params']);
        $registry->register($name, $service);
    }
    
  3. Integration with Laravel’s Container: Bind the registry to Laravel’s container for seamless DI:

    $this->app->bind(PaymentGatewayInterface::class, function ($app) {
        return $app['payment.gateway.registry']->get('stripe');
    });
    
  4. Event-Driven Registration: Trigger registration during Laravel events (e.g., Registered):

    Event::listen('user.registered', function ($user) {
        $registry = app('notification.channel.registry');
        $registry->register("user
    
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
codifyo/ts-generator-bundle
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
spatie/mailcoach-vapor