Advanced

Service Providers

The provider model and lifecycle, plus the framework's built-in providers.

Service providers are the central place to configure and bootstrap your application services.

Quick Start

Create a Service Provider

An app provider is a class with a static services() method returning the array DSL (see DI → Service Registration). This is what the api-skeleton's AppServiceProvider looks like:

app/Providers/AppServiceProvider.php:

<?php

namespace App\Providers;

use App\Contracts\PaymentGatewayInterface;
use App\Payments\PaymentGatewayFactory;
use App\Services\OrderService;

final class AppServiceProvider
{
    public static function services(): array
    {
        return [
            // Autowired singleton
            OrderService::class => ['autowire' => true],

            // Class/method factory, also resolvable by the interface
            'payment.gateway' => [
                'factory' => [PaymentGatewayFactory::class, 'create'],
                'alias' => PaymentGatewayInterface::class,
            ],
        ];
    }
}

The container calls services() statically, so it can't use $this. A factory that needs config resolves ApplicationContext from the container it receives:

use Glueful\Bootstrap\ApplicationContext;
use Psr\Container\ContainerInterface;

final class PaymentGatewayFactory
{
    public static function create(ContainerInterface $c): StripePaymentGateway
    {
        $context = $c->get(ApplicationContext::class);
        return new StripePaymentGateway((array) config($context, 'payments.stripe', []));
    }
}

Register Provider

Register providers in config/serviceproviders.php. Entries load in the order listed, before extension providers:

return [
    'enabled' => [
        App\Providers\AppServiceProvider::class,
    ],
];

Provider Model

  • Definitions: a static services() (array DSL) or a static defs() (typed definitions). If both exist, defs() wins. Definitions are compiled into the container before anything runs, so keep them free of side effects.
  • Lifecycle (optional): extend Glueful\Extensions\ServiceProvider to get register(ApplicationContext $context) and boot(ApplicationContext $context). register() runs for every provider first, then boot() runs after all providers are registered. Both must keep the ApplicationContext $context parameter, or PHP raises a fatal signature error.
  • In register() / boot() you can call the base class helpers: loadRoutesFrom(), loadMigrationsFrom(), mergeConfig(), loadMessageCatalogs(), serveFrontend(), commands(), discoverCommands(), registerNotificationChannel(). Providers can also declare permissions(), roles(), voters() and policies() for the permission catalog.
  • In production, a provider whose definitions fail to load is skipped and reported by extensions:diagnose; outside production the error is thrown.
use App\Listeners\OrderListener;
use Glueful\Bootstrap\ApplicationContext;
use Glueful\Events\EventService;
use Glueful\Extensions\ServiceProvider;

final class EventServiceProvider extends ServiceProvider
{
    public static function services(): array
    {
        return [];
    }

    public function boot(ApplicationContext $context): void
    {
        // Wire listeners, register channels, etc. subscribe() autowires a listener class
        // that isn't a container service; one that can't be built throws here, at boot.
        app($context, EventService::class)->subscribe(OrderListener::class);
    }
}

Packaged extensions use the same Glueful\Extensions\ServiceProvider base, but are enabled in config/extensions.php (via php glueful extensions:enable) rather than serviceproviders.php. See Building Extensions.

Built-in Providers

The framework builds its container from these providers, in this order (ContainerFactory). They extend the internal Glueful\Container\Providers\BaseServiceProvider and are not user-configurable, but they're the definitive reference for core service ids:

ProviderRegisters (highlights)
CoreProvider'database' / Connection, 'cache.store' / CacheStore, 'logger', 'request', Router, PermissionManager (alias 'permission.manager'), most middleware aliases
ORMProviderORM model support
ConsoleProviderConsole application and commands
StorageProviderStorage manager, disks, FileUploader
ExceptionProviderException Handler, ExceptionHandlerInterface, 'exception' middleware
RequestProviderSymfony Request, PSR-7 ServerRequestInterface, RequestContext
ValidationProviderValidator
SerializerProviderSerializer / normalizers
HttpClientProviderHttpClientInterface, PSR-18 client, Glueful\Http\Client
RepositoryProviderRepositoryFactory, 'repository'
AuthProviderAuthentication manager, guards, token services, API keys
NotificationsProviderNotification channels
EventProviderEventService, PSR-14 dispatcher
ExtensionProviderExtensionManager, 'extensions'
QueueProviderQueueManager, FailedJobProvider, JobScheduler
LockProviderLock manager, 'lock'
FileProviderFileFinder ('file.finder')
HttpPsr15ProviderPSR-15 bridge
VarDumperProviderVar dumper
ControllerProviderFramework controllers (AuthController, ...)
LazyProviderLazy warmup groups
SecurityProviderSecurity services
PermissionsProvider / GateProviderPermission catalog, Gate
TasksProviderBuilt-in scheduled tasks
ApiVersioningProviderVersion negotiation, 'api_version' middleware

Most live in src/Container/Providers/; the rest are under their subsystem's ServiceProvider/ directory (for example src/Queue/ServiceProvider/QueueProvider.php). Run php glueful di:container:debug --services to list what's actually registered.

Next Steps