Service container
VelvetCMS\Core\Application doubles as the framework bootstrap and dependency injection container. Everything—services, facades, middleware, commands—flows through it.
Registering services #
Application::__construct() calls registerCoreServices() which binds:
- The container itself under
Application::classandVelvetCMS\Core\Application. config→ singletonConfigRepository.events→EventDispatcher.logger→Services\FileLogger(PSR-3) with level fromconfig('app.log_level').exceptions.handler→VelvetCMS\Exceptions\Handlerwith renderers/reporters fromconfig/exceptions.php.router→VelvetCMS\Core\Routerwith middleware aliases/global stack fromconfig/http.php.db→VelvetCMS\Database\Connectionusingconfig('db')(supports sqlite/mysql/pgsql).cache→Drivers\Cache\FileCacheorRedisCachedepending onconfig('cache.default').cache.tags→Support\Cache\CacheTagManagerfor granular invalidation.migrations.runner→Database\Migrations\DefaultMigrationRunner.session→Services\SessionManager.markdown,content.driver,pages,theme,modules(see dedicated docs).
You can register your own bindings inside modules:
$app->singleton(AnalyticsService::class, function() use ($app) {
return new AnalyticsService($app->make('events'));
});
$app->alias(AnalyticsService::class, 'analytics');
Autowiring #
If make(Foo::class) is called and the service is not explicitly bound, the container attempts to instantiate it by reflecting on the constructor, caching dependencies per class in $reflectionCache. Only class-hinted parameters are allowed; untyped parameters throw informative exceptions.
Aliases & facades #
- Aliases let you resolve a binding using a human-readable key. Example:
$app->alias('cache', CacheDriver::class);soapp(CacheDriver::class)andapp('cache')both return the same instance. - Facades (
VelvetCMS\Facades\App,DB,Session) are ultra-thin: they store the container (App::setInstance($app)) and forward static calls to real services. No magic global state.
Helper functions #
src/Support/helpers.php exposes utility functions that always pull from the container:
app($abstract = null)– resolves services.config('key')– fetches values viaConfigRepositorywith dot notation.base_path(),storage_path(),content_path()– consistent path helpers.view('template', $vars)– shorthand forThemeService::view().csrf_token(),csrf_field(),method_field()– session + security helpers.route('name', $params)– proxies toRouter::url().
Adding your own services #
- Create a service class anywhere under
src/or a module. - Bind it in a service provider/module
register()method viasingleton()orbind(). - (Optional) add aliases or facades for ease-of-use.
- Resolve it through dependency injection,
app(Service::class), or helper functions.
Because everything funnels through the same container, CLI commands, HTTP controllers, and modules all get the exact same instances, simplifying caching, logging, and DB access.