symfony/contracts
Symfony Contracts provides small, stable PHP interfaces and traits extracted from Symfony components. Use them as type hints for loose coupling and interoperability, with proven implementations and backward compatibility across the Symfony ecosystem.
Architecture fit
Symfony Contracts excels in Laravel applications targeting decoupled infrastructure layers (caching, events, messaging, etc.). The package’s domain-specific interfaces (e.g., CacheInterface, EventDispatcherInterface) align with Laravel’s service container and dependency injection patterns, enabling loose coupling between business logic and framework-specific implementations. For example, replacing Illuminate\Cache\Repository with Symfony\Contracts\Cache\CacheInterface in a service layer allows seamless swapping of cache backends (e.g., Redis, Memcached) without modifying domain logic. However, core Laravel abstractions (e.g., Eloquent, Blade) lack direct contract support, limiting applicability to infrastructure-heavy components.
Integration feasibility Moderate-to-high for new projects or greenfield services, but challenging for legacy Laravel codebases. Key hurdles:
CacheManager) do not implement Symfony Contracts, requiring explicit bindings or adapter classes.symfony/cache-contracts:^2.5 for older PHP).AppServiceProvider) are mandatory for seamless adoption.Technical risk
symfony/cache) may deviate from Laravel’s behavior (e.g., cache tagging, event propagation). Validate via reference tests in the symfony/contracts suite.symfony/contracts pulls in all domain contracts, even if only 1–2 are needed (e.g., cache-contracts). Use granular packages (e.g., symfony/event-dispatcher-contracts) to minimize footprint.Target class does not exist errors. Mitigate with comprehensive alias() mappings in AppServiceProvider.Key questions
CacheInterface, MailerInterface) where Laravel’s native implementations are suboptimal or non-standard.symfony/mailer vs. spatie/laravel-mail—each may have partial contract compliance.CacheManager in a CacheInterface adapter).MessengerInterface—will we build one or avoid queueing abstractions?Stack fit Ideal for:
Poor fit for:
Symfony\Contracts\Messenger), or Laravel’s auth system.Migration path
CacheManager → CacheInterface).composer require symfony/contracts symfony/cache-contracts symfony/event-dispatcher-contracts
symfony/cache-contracts) to avoid bloat.// app/Providers/AppServiceProvider.php
public function register(): void
{
$this->app->bind(
Symfony\Contracts\Cache\CacheInterface::class,
fn($app) => $app->make(Illuminate\Cache\Repository::class)
);
$this->app->bind(
Symfony\Contracts\EventDispatcher\EventDispatcherInterface::class,
Illuminate\Events\Dispatcher::class
);
}
// Before
public function __construct(CacheManager $cache) {}
// After
public function __construct(Symfony\Contracts\Cache\CacheInterface $cache) {}
Cache::store()) to preserve decoupling.MessengerInterface), build adapter wrappers around Laravel’s queue system.Compatibility
composer.json (e.g., "provide": { "symfony/cache-implementation": "1.0" }).Sequencing
Critical dependencies:
symfony/cache) are version-locked to avoid contract-breaking updates.Maintenance
CacheInterface methods).symfony/cache) require active version management to avoid compatibility issues.
symfony/cache from v6.x to v7.x may require contract adapter updates.composer why symfony/* to audit dependencies and roave/security-advisories to monitor vulnerabilities.Support
php artisan container:inspect to verify bindings and dd($cache instanceof Symfony\Contracts\Cache\CacheInterface) to validate runtime compliance.Scaling
symfony/cache with Redis vs. file-based cache will have dramatically different latency.Illuminate\Cache to Predis for Redis) without code changes.Failure modes
Target class [Symfony\Contracts\Cache\CacheInterface] does not exist.alias() or bind() in AppServiceProvider.php artisan container:inspect.Class not found or Method not found after dependency updates.How can I help you explore Laravel packages today?