Skip to content

Portable integration · Framework-free

Framework-free

Construct portable services directly and add infrastructure adapters only at the application boundary.

Domain and Application code remain framework-free; only the outer composition root knows the provider.

The portable baseline

Framework-free integration is the reference composition, not a reduced support tier. Values, collections, specifications, messages, repositories, and neutral Application services require no framework adapter. Install only Fight Common to begin:

composer require johnnickell/fight-common

Use each component guide for its portable construction and behavior. Add an Adapter only when the application crosses a real infrastructure boundary such as a database, HTTP transport, filesystem, mailer, or process.

Compose one capability

Application services depend on Domain and Application contracts. The outer bootstrap constructs the chosen adapter and supplies it to the use case. Keep provider configuration beside that construction so replacing a transport does not change the use case.

For example, select GuzzleClient for outbound HTTP, a Flysystem adapter for file storage, SymfonyMailTransport for mail, or SymfonyProcessRunner for processes only when the application uses that capability. Each optional package is independently selectable; installing Fight Common does not install them.

Use the Fight container when useful

Fight\Common\Application\Service\Container is a small PSR-11 container for explicit composition. Register shared services with set() and transient factories with factory(). It does not scan application code or autowire dependencies.

Fight\Common\Adapter\ServiceContainer\Fight\ContainerCapabilityRegistrar provides bounded helpers for synchronous messaging, template helpers, and a configured Fight HTTP transport with its PSR-18 view. Invoke only the registrar for the selected capability. Direct constructor wiring remains valid.

Provider and operations boundaries

Shared adapters cover Doctrine/DBAL persistence, Guzzle and PSR-18 HTTP, Flysystem storage, Twig templating, Symfony Mailer/Filesystem/Process/Messenger, Twilio SMS, Mercure publication, and PSR-3 observability. The application chooses concrete packages, configuration, credentials, migrations, transaction boundaries, retry policy, worker supervision, and shutdown behavior.

Async delivery through Messenger remains at least once. The application owns brokers, topology, retries, failure storage, workers, idempotency, and any durable outbox. Portable scheduling likewise needs an application-owned invocation loop and lock backend.

Failure boundaries

Do not translate provider failures into success at the composition root. Preserve the component guide's failure contract, attach operational context at the Adapter edge, and let the Application use case decide whether a failure is retryable. A null or logging adapter is a deliberate operating mode, not proof that an external side effect occurred.

Continue with Dependency Injection, Messaging, or the complete framework support matrix.