symfony/contracts
Symfony Contracts provides small, domain-focused PHP interfaces, traits, and normative docblocks extracted from Symfony components. Use them as stable type hints for loose coupling, interoperability, and easy DI/autowiring with battle-tested implementations.
Install the package:
composer require symfony/contracts
(No configuration needed—just type-hint interfaces where required.)
First use case:
Replace Laravel’s Cache facade with CacheInterface in a service:
use Symfony\Contracts\Cache\CacheInterface;
class UserService
{
public function __construct(private CacheInterface $cache) {}
}
Bridge Laravel services:
In AppServiceProvider@boot():
$this->app->alias(
CacheInterface::class,
Illuminate\Cache\Repository::class
);
Autowire with Laravel:
Ensure config/app.php has "autowire": true and "autowire_cache": true.
Infrastructure Abstraction:
CacheInterface for storage-agnostic caching (e.g., Redis, file, database).
$item = $cache->get('key', fn() => $expensiveOperation());
Event facade with EventDispatcherInterface:
$dispatcher->dispatch(new UserRegisteredEvent($user));
Cross-Framework Libraries:
HttpClientInterface (Symfony) or GuzzleClient (Laravel) interchangeably.Service Layer Decoupling:
use Illuminate\Mail\Mailer;use Symfony\Contracts\Mailer\MailerInterface;AppServiceProvider:
$this->app->bind(MailerInterface::class, function ($app) {
return $app->make(Illuminate\Mail\Mailer::class);
});
Testing:
$cache = $this->createMock(CacheInterface::class);
$cache->method('get')->willReturn('mocked-value');
Laravel Facades → Contracts:
Replace Cache::store() with injected CacheInterface in new code. Use adapters for legacy facades:
class CacheFacadeAdapter implements CacheInterface {
public function get($key, Closure $default) {
return Cache::store('default')->get($key, $default());
}
// ... other methods
}
Autowiring:
Laravel’s autowiring ignores Symfony interfaces by default. Explicitly bind or use bind():
$this->app->bind(Symfony\Contracts\Cache\CacheInterface::class,
fn($app) => $app->make(Illuminate\Cache\Repository::class));
Traits for Partial Compliance:
Extend CacheItemInterface in custom cache items:
class LaravelCacheItem implements CacheItemInterface {
use Symfony\Contracts\Cache\CacheItemTrait;
// ...
}
Autowiring Failures:
Target class [Symfony\Contracts\Cache\CacheInterface] does not exist.alias() is configured.Semantic Mismatches:
Cache::remember() uses a callback, while CacheInterface::get() may expect a default value.Version Conflicts:
composer.json:
"require": {
"symfony/contracts": "^3.0"
}
Missing Implementations:
Queue).MessageBusInterface) for queues.Check Bindings:
php artisan container:inspect Symfony\Contracts\Cache\CacheInterface
(Ensures the interface is properly bound.)
Mocking Issues:
get() vs. remember()).Custom Implementations:
RedisCache class implementing CacheInterface for Redis support:
class RedisCache implements CacheInterface {
use CacheItemTrait;
// ...
}
Composite Contracts:
CacheInterface & TaggableInterface).Service Tags:
#[AsService] attribute (if using Symfony’s DI) or Laravel’s bindIf() for conditional binding.CacheInterface or EventDispatcherInterface—low-risk domains.@method annotations for unsupported methods in adapters.provide:
Declare implementations in composer.json for tooling compatibility:
"provide": {
"symfony/cache-implementation": "1.0"
}
How can I help you explore Laravel packages today?