Contracts
Introduction
Framework’s “contracts” are a set of interfaces that define the core services provided by the framework. For example, an MacropaySolutions\Kernel\Contracts\Queue\Queue contract defines the methods needed for queueing jobs, while the MacropaySolutions\Kernel\Contracts\Mail\Mailer contract defines the methods needed for sending e-mail.
Each contract has a corresponding implementation provided by the framework. For example, Framework provides a queue implementation with a variety of drivers, and a mailer implementation that is powered by Symfony Mailer.
All the Framework contracts live in their own GitHub repository. This provides a quick reference point for all available contracts, as well as a single, decoupled package that may be utilized when building packages that interact with Framework services.
Contracts vs. Container Helpers
Framework’s helper functions provide a simple way of utilizing Framework’s services without needing to type-hint and resolve contracts out of the service container.
Unlike helpers, which do not require you to inject them in your class’ constructor, contracts allow you to define explicit dependencies for your classes. Some developers prefer to explicitly define their dependencies in this way and therefore prefer to use contracts, while other developers enjoy the convenience of global helpers.
When to Use Contracts
The decision to use contracts or global helpers will come down to personal taste and the tastes of your development team. Both contracts and global functions can be used to create robust, well-tested Framework applications.
If you are building a package that integrates with multiple PHP frameworks you may wish to use the kernel/contracts package to define your integration with Framework’s services.
How to Use Contracts
So, how do you get an implementation of a contract? It’s actually quite simple.
Many types of classes in Framework are resolved through the service container, including controllers, event listeners, middleware, queued jobs. So, to get an implementation of a contract, you can just “type-hint” the interface in the constructor of the class being resolved.
For example, take a look at this event listener:
<?php
namespace App\Listeners;
use App\Events\OrderWasPlaced;
use App\Models\User;
use MacropaySolutions\Kernel\Contracts\Redis\Factory;
class CacheOrderInformation
{
/**
* Create a new event handler instance.
*/
public function __construct(
protected Factory $redis,
) {}
/**
* Handle the event.
*/
public function handle(OrderWasPlaced $event): void
{
// ...
}
}
When the event listener is resolved, the service container will read the type-hints on the constructor of the class, and inject the appropriate value. To learn more about registering things in the service container, check out its documentation.
Contract Reference
This table provides a quick reference to all the Framework contracts and their equivalent container bindings: