complex-heart/contracts
A lightweight Laravel/PHP contracts package from the Complex Heart ecosystem, offering shared interfaces and abstractions. It helps keep packages decoupled, consistent, and interoperable, so you can build and extend components without tight coupling.
complex-heart/contracts is a pure interface/contract package — you install it, but there is almost nothing to "run." Think of it as the shared vocabulary for the Complex Heart SDK ecosystem rather than a feature you wire into a controller.
Minimal setup:
composer require complex-heart/contracts
ComplexHeart\Contracts\ namespace. Confirm the exact PHP constraint in composer.json before installing alongside an older Laravel version.src/ and enumerate the interfaces. There is no facade, no service provider, no config file, and no migrations — the entire package surface is the interface list. The README on GitHub is the fastest inventory; if it's thin, vendor/complex-heart/contracts/src is the source of truth.AppServiceProvider:// AppServiceProvider::register()
$this->app->bind(
\ComplexHeart\Contracts\SomeClientContract::class,
\App\Services\ComplexHeartClient::class
);
Then type-hint the interface in a constructor and let Laravel's container resolve it.
1. Container bindings in a service provider. This is the primary integration point. Register a ComplexHeartServiceProvider that binds every contract you consume to a concrete implementation. Keep the binding map in one place so you can swap SDK versions without touching call sites.
2. Depend on the narrowest interface. If the package exposes several small interfaces (which interface packages usually do), inject only the one you need rather than a mega-interface. This keeps unit tests trivial and mocks minimal.
3. Decorate for cross-cutting concerns. Because implementations are injected by contract, you can wrap them:
class CachingClient implements ClientContract
{
public function __construct(
private ClientContract $inner,
private Cache $cache,
) {}
public function fetch(string $id): Payload
{
return $this->cache->remember("ch:$id", 300, fn () => $this->inner->fetch($id));
}
}
Bind the inner implementation first, then rebind the contract to the decorator — a clean way to add logging, retries, or telemetry without forking the SDK.
4. Mock the contract, not the implementation. In tests, bind a fake implementation of the interface in setUp() (or use $this->instance() / $this->mock()). This is exactly why a contracts package exists.
5. Adapter pattern for SDK boundaries. If the SDK interfaces are awkward for your domain, write a thin adapter in your app that implements the contract and translates to your own models. Your application code stays SDK-agnostic.
6. Contract tests. If you implement these interfaces yourself, write a shared PHPUnit test case (abstract class ClientContractTestCase) asserting the interface's behavioral contract, and extend it for every implementation. This is the pattern PSR-style packages expect.
composer.json and review the source before upgrading. There's no community to catch a broken interface.^1.0) and read the changelog before bumping minor versions — SemVer for pure-interface packages is stricter than for libraries.BindingResolutionException or a "cannot instantiate interface" error appears, the problem is always a missing container binding, not the package. Use app()->make(SomeContract::class)->get_class() to verify what's actually being resolved.config/app.php when it isn't needed will cause confusing "class not found" errors during php artisan package:discover.composer.json. Interface packages often use PHP 8.1+ features (enums, readonly, never return types). If one Laravel app in a monorepo is still on 8.0, the composer resolution will silently keep the whole repo pinned.app/Contracts/ and adapt — don't fork the package for a two-line change.complex-heart/contracts only exposes one or two interfaces you actually use, it may be cheaper to declare them in your app and drop the dependency entirely. Contracts packages only pay off when multiple packages or services share the same vocabulary.composer dump-autoload — not the interface definitions themselves.How can I help you explore Laravel packages today?