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

Manager Laravel Package

graham-campbell/manager

Adds a reusable “manager” layer for Laravel packages and apps, helping you build driver-based services (create, cache, and resolve drivers) with a consistent API. Supports Laravel 8–13 and PHP 7.4–8.5.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require graham-campbell/manager:^5.3
    

    No service provider registration is required—just include the package in your project.

  2. First use case: Create a basic manager Extend AbstractManager to implement your connection logic. Example for a LoggerManager:

    use GrahamCampbell\Manager\AbstractManager;
    
    class LoggerManager extends AbstractManager
    {
        protected function createConnection(array $config)
        {
            return new CustomLogger($config);
        }
    
        protected function getConfigName()
        {
            return 'logging';
        }
    }
    
  3. Register the manager in config/logging.php:

    'drivers' => [
        'loggly' => [
            'token' => env('LOGGLY_TOKEN'),
        ],
        'sentry' => [
            'dsn' => env('SENTRY_DSN'),
        ],
    ],
    
  4. Use the manager in a controller/service:

    $logger = app(LoggerManager::class);
    $logger->connection('loggly')->log('Test message');
    // Or dynamically (thanks to __call):
    $logger->loggly()->log('Test message');
    

Implementation Patterns

Core Workflows

  1. Connection Lifecycle Management

    • Pooling: Connections are cached and reused. Call connection('name') to get an instance.
    • Forced Reconnect: Use reconnect('name') to bypass the cache (e.g., after config changes).
    • Cleanup: Call disconnect('name') to remove a connection from the pool (e.g., for security-sensitive operations).
  2. Dynamic Method Dispatch Leverage __call to avoid repetitive connection()->method() calls:

    // Instead of:
    $manager->connection('s3')->upload('file.jpg');
    
    // Use:
    $manager->s3()->upload('file.jpg');
    
  3. Runtime Extensibility Add custom drivers at runtime without code changes:

    $manager->extend('datadog', function () {
        return new DatadogLogger(config('logging.datadog'));
    });
    

    Now app(LoggerManager::class)->datadog()->log(...) works.

  4. Config Resolution

    • Use getConnectionConfig('name') to fetch config for a specific connection.
    • Use getDefaultConnection()/setDefaultConnection('name') to manage defaults.

Integration Tips

  • Laravel Facades: Bind the manager to a facade for cleaner syntax:
    Facades\Manager::connection('s3')->putObject(...);
    
  • Service Providers: Register the manager as a singleton:
    $this->app->singleton(LoggerManager::class, function ($app) {
        return new LoggerManager($app['config']);
    });
    
  • Testing: Mock connections by extending AbstractManager and overriding createConnection():
    $manager = new TestLoggerManager();
    $manager->extend('mock', fn() => new MockLogger());
    

Gotchas and Tips

Pitfalls

  1. Connection Leaks

    • Issue: Forgetting to call disconnect() can lead to memory leaks if connections hold resources (e.g., database connections, HTTP clients).
    • Fix: Implement a finally block or use Laravel’s withConnection() for scoped connections:
      $manager->connection('mysql')->query(...);
      // Connection is automatically disconnected when out of scope.
      
  2. Config Name Mismatches

    • Issue: getConfigName() must return the exact config key (e.g., 'logging'). Typos here will cause ConfigException.
    • Fix: Validate the config key exists in boot():
      if (!config()->has($this->getConfigName())) {
          throw new \RuntimeException("Config [{$this->getConfigName()}] not found.");
      }
      
  3. Dynamic Method Ambiguity

    • Issue: __call can conflict with existing methods. For example, if your manager has a log() method, $manager->log() will call it instead of dispatching to a connection.
    • Fix: Prefix dynamic methods or use connection()->method() explicitly.
  4. Thread Safety

    • Issue: The connection pool is not thread-safe by default. Concurrent requests may overwrite connections.
    • Fix: Use Laravel’s sync flag or implement a lock mechanism:
      \Illuminate\Support\Facades\Cache::lock('manager-'.$name, 5, function () use ($manager) {
          $manager->reconnect($name);
      });
      

Debugging Tips

  • Inspect Connections: Dump the pool to debug active connections:
    dd(app(LoggerManager::class)->getConnections());
    
  • Check Config: Verify config resolution with:
    dd(app(LoggerManager::class)->getConnectionConfig('s3'));
    
  • Enable Logging: Add debug logs in createConnection() to trace initialization:
    protected function createConnection(array $config)
    {
        \Log::debug('Creating connection with config:', $config);
        return new S3Client($config);
    }
    

Extension Points

  1. Custom Connection Factories Override createConnection() to support complex initialization:

    protected function createConnection(array $config)
    {
        return tap(new S3Client($config), function ($client) {
            $client->configure(['region' => $config['region']]);
        });
    }
    
  2. Connection Events Extend the manager to dispatch events on connect/disconnect:

    use Illuminate\Support\Facades\Event;
    
    protected function createConnection(array $config)
    {
        $connection = new S3Client($config);
        Event::dispatch('manager.connected', [$this, $connection]);
        return $connection;
    }
    
  3. Fluent Interface Add chainable methods to connections:

    $manager->extend('s3', function () {
        return new S3Manager(config('filesystems.disks.s3'));
    });
    
    // Usage:
    $manager->s3()->disk()->put('file.jpg', $content);
    
  4. Config Validation Validate connection configs in createConnection():

    if (empty($config['token'])) {
        throw new \InvalidArgumentException('Token is required.');
    }
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle