apie/service-provider-generator
Generate Laravel ServiceProvider classes from Symfony YAML service definitions. Keep framework-agnostic libraries in sync by maintaining a single service container registry, then output PHP source code you can write to a file (or eval if you must).
Installation
composer require apie/service-provider-generator
Require the package in your project via Composer.
Basic Usage
Generate a Laravel service provider from a services.yaml file:
php artisan apie:service-provider-generator path/to/services.yaml
This creates a new service provider class in app/Providers/ with bindings and singleton configurations.
First Use Case
services.yaml (e.g., from a legacy app or microservice) into a Laravel-compatible provider.services.yaml):
services:
App\Services\MyService:
arguments:
- '@App\Repositories\DataRepository'
tags: ['app.service']
MyServiceProvider with bindings like:
$this->app->singleton(MyService::class, function ($app) {
return new MyService($app->make(DataRepository::class));
});
Incremental Adoption
# Generate for a subset of services
php artisan apie:service-provider-generator services.yaml --services="App\Services\*"
Integration with Laravel’s DI Container
singleton(), bind(), tag()) for consistency.when() for conditional bindings:
$this->app->when(MyService::class)
->needs(DataRepository::class)
->give(function ($app) { ... });
Tagging and Aliasing
app.service) to Laravel’s tag() method for service discovery:
$this->app->tag([MyService::class], 'app.service');
--tags flag to auto-generate tagged bindings:
php artisan apie:service-provider-generator services.yaml --tags
Environment-Specific Configurations
config/services.php) to override generated bindings:
'bindings' => [
MyService::class => \App\Services\MyService::class,
],
--env flag to generate environment-aware providers:
php artisan apie:service-provider-generator services.yaml --env=production
CI/CD Pipeline Integration
# .github/workflows/deploy.yml
- run: php artisan apie:service-provider-generator config/services.yaml
Testing Generated Providers
bind():
$this->app->bind(MyService::class, function () {
return Mockery::mock(MyService::class);
});
Customizing Output
ServiceProviderGenerator class to add pre/post-processing logic:
// app/Console/Commands/CustomServiceProviderGenerator.php
class CustomServiceProviderGenerator extends ServiceProviderGenerator {
protected function customizeBinding(string $service, array $config): string {
// Add custom logic (e.g., inject config)
return parent::customizeBinding($service, $config);
}
}
Circular Dependencies
services.yaml may define circular dependencies (e.g., A depends on B, which depends on A). Laravel’s container will throw an exception.bindIf():
$this->app->bindIf(
CircularService::class,
function ($app) { return new CircularService($app->make(OtherService::class)); }
);
Type Safety
services.yaml lacks type info, bindings may fail.@var annotations or use instanceof checks:
$this->app->bind('app.service', function ($app) {
return $app->make(ServiceInterface::class);
});
Namespace Conflicts
App\Services\Logger), but Laravel expects fully qualified names.--namespace flag to auto-resolve or manually update the YAML:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Singleton vs. Non-Singleton
singleton() calls.--strict flag to enforce singleton bindings or add manual overrides.Dry Run Mode
php artisan apie:service-provider-generator services.yaml --dry-run
Verbose Output
php artisan apie:service-provider-generator services.yaml --verbose
Validation Errors
services: root) will fail silently. Validate first:
php artisan apie:validate-yaml services.yaml
Leverage Laravel’s Helpers
collect() for dynamic bindings:
collect($this->app['config']['services.bindings'])
->each(fn ($class, $alias) => $this->app->bind($alias, $class));
Partial Generation
--changed:
php artisan apie:service-provider-generator services.yaml --changed
IDE Integration
Ctrl+Shift+R) after generation to update autocompletion.Performance
services.yaml, use --batch-size=50 to process bindings in chunks and avoid memory issues.Extending the Generator
ServiceProviderGenerator::generateBindings() to add custom logic (e.g., logging, caching):
protected function generateBindings(array $services): string {
Log::info('Generating bindings for: ' . count($services) . ' services');
return parent::generateBindings($services);
}
How can I help you explore Laravel packages today?