Download the PHP package zjkiza/response-processor without Composer
On this page you can find all versions of the php package zjkiza/response-processor. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download zjkiza/response-processor
More information about zjkiza/response-processor
Files in zjkiza/response-processor
Package response-processor
Short Description Symfony bundle for automatically enrich DTO response objects with relational data using PHP 8 attributes
License MIT
Informations about the package response-processor
ResponseProcessor Bundle
A Symfony bundle that fetches and injects related data into DTOs after a controller returns, using PHP 8 attributes.
How it works
- Controller returns DTOs with
#[ProcessorIdentifier]on the ID property - DTO properties are annotated with
#[InjectData(SomeFetcher::class)]or a custom attribute ProcessorListenerinterceptskernel.view, reads#[Processor('handler_key')]from the controller method- Each registered handler delegates to
ProcessorEngine, which batches fetches perDataFetcherclass (onefetch()call per class per request) and injects results directly into DTO properties
When to use it
The problem
After a controller returns DTOs (or any response objects), you often need to enrich them with related data — tags, authors, categories, metadata, or data from external sources. Common approaches all have drawbacks:
- Fetching manually in the controller → bloated logic, repeated across endpoints
- Doctrine lazy loading / serialization → N+1 queries or oversized JOINs
- Event subscribers / post-controller hooks → ad-hoc, no reuse between handlers
Use cases
1. API responses with relational data
A controller returns PostDto[], each with author, tags, attachments. Instead of manually populating fields, annotate DTO properties with #[InjectData(TagFetcher::class)]. The bundle populates them before serialization — zero controller code.
2. CQRS read models
A query handler returns a read model that combines data from PostgreSQL, Redis, and an HTTP API. Each source gets its own DataFetcher, each property its own #[InjectData(...)]. Batching is automatic — one fetch() call per source per request.
3. Multi-source user profiles
User details from the database, notifications from Redis, permissions from a remote API. One controller, one #[Processor], multiple DTO properties with different fetchers — all resolved in the same kernel.view pass.
4. Aggregate views with expensive fields
Some DTO fields are costly to load (e.g. full-text search data, analytics). Instead of always joining or always lazy-loading, mark them with #[InjectData]. The bundle resolves them only when needed — no premature optimization, no waste.
What you gain
- Batch fetch — each
DataFetcher::fetch()is called once per request with all identifiers at once. No N+1, no redundant calls. - Handler key system — the same PHP handler class can be registered under multiple keys (e.g.
api.tagvsweb.tag) with different behavior, tag resolution, or configuration. - Zero config for fetchers — every
DataFetcherInterfaceimplementation is auto-tagged. Just create the class. - Clean controllers — controllers only assemble and return DTOs. They know nothing about fetching or injection.
- Predictable performance —
O(1)batch calls perDataFetcherclass, property resolution cached per call sequence. - Extensible — create a custom
#[Attribute], implementProcessorAttributeInterface, register anAttributeHandlerwith your key, and it works. - Battle-tested — 96.97% code coverage, 37 tests, 0 PHPStan errors at level max.
Installation
Configuration
Usage
1. Define your DTO
Mark the ID property with #[ProcessorIdentifier] and properties to be injected with #[InjectData]:
#[InjectData] points to a DataFetcherInterface implementation that provides the data.
2. Create a DataFetcher
All DataFetcherInterface implementations are auto-tagged with zjkiza_response_processor.fetcher.
3. Register handlers
The key tag matches the value in #[Processor('key')]. Different keys can use the same attributeClass or different ones.
4. Use on controller
Multiple handlers can be stacked on one method:
Custom attributes
Extend InjectDataAbstract for a minimal custom attribute:
The $fetcher property and ProcessorAttributeInterface implementation are inherited — you only need to add the #[\Attribute] declaration and extend the abstract class.
Register it with AttributeHandler:
Architecture
ProcessorEnginebatches fetches perDataFetcherclass — onefetch()call per class perprocess()call$callSequenceprevents redundant reflection lookups within a singleprocess()call- Handler tag keys allow the same PHP class registered under multiple keys
Service Tags
| Tag | Purpose |
|---|---|
zjkiza_response_processor.handler |
Registers a handler with a key attribute |
zjkiza_response_processor.fetcher |
Auto-tagged on all DataFetcherInterface implementations |
Contracts
| Interface | Purpose |
|---|---|
ProcessorAttributeInterface |
Marker interface for custom processor attributes |
DataFetcherInterface |
Fetches data by array of identifiers |
ProcessorHandlerInterface |
Handles processed data in kernel.view |
IdentifierExtractorInterface |
Extracts identifier from an object |
PropertyResolverInterface |
Resolves a DataFetcherInterface for a property |
All versions of response-processor with dependencies
symfony/http-kernel Version ^5.4|^6.0|^7.0|^8.0
symfony/dependency-injection Version ^5.4|^6.0|^7.0|^8.0
symfony/config Version ^5.4|^6.0|^7.0|^8.0