symfony-notes/object-transformer-bundle
Symfony bundle that integrates the ObjectTransformer library, providing service configuration and dependency injection for transforming objects, DTOs, and arrays with reusable, configurable transformers in Symfony applications.
Install the bundle with Composer and let Symfony Flex do the wiring:
composer require symfony-notes/object-transformer-bundle
If Flex doesn't auto-register it (common for low-adoption packages with no recipe), add the bundle manually to config/bundles.php:
return [
// ...
SymfonyNotes\ObjectTransformerBundle\ObjectTransformerBundle::class => ['all' => true],
];
Where to look first:
vendor/symfony-notes/object-transformer-bundle/README.md — for a package with 0 stars and 0 dependents, the README is your primary (often only) source of truth for the public API surface.vendor/symfony-notes/object-transformer-bundle/DependencyInjection/ — the Configuration.php and *Extension.php reveal every config key and service alias the bundle exposes. Read these before guessing at YAML config.vendor/symfony-notes/object-transformer-bundle/Resources/config/services.xml (or .yaml) — shows the service IDs you can autowire against.First use case: transform a request/input DTO or array payload into a domain entity (or entity → output DTO) inside a controller or application service, instead of hand-writing new Entity($dto->getFoo(), ...). This is the canonical "object transformer" flow and the fastest way to validate whether the package fits your needs.
A minimal smoke test:
// src/Controller/ExampleController.php
public function __invoke(SomeTransformer $transformer, Request $request): Response
{
$source = new SourceDto(/* ...hydrated from $request... */);
$target = $transformer->transform($source); // or whatever the
// bundle's public entry point is — check README for the exact method name
return $this->json($target);
}
If you can dispatch a transform end-to-end on the first try, the bundle is doing its job. If you find yourself reading three vendor files just to construct the transformer, treat that as a signal to compare against symfony/serializer's normalizer or a hand-rolled mapper.
Autowire the transformer as a service. Symfony bundles of this shape usually register their core service under a stable ID. Constructor-inject it into controllers, message handlers, and application services rather than instantiating it yourself — that way the bundle's config (and any compiler-pass-registered transformers) actually applies.
Wrap transforms behind an application-layer port. Don't leak the transformer into your domain. Define a small interface in src/Application/ (e.g. OrderMapperInterface) and implement it with an adapter that delegates to the bundle's transformer. This costs ~20 lines and gives you a one-file escape hatch if the package goes unmaintained (it will — 0 stars, 0 dependents).
Register one transformer per direction, not per entity. Typically these libraries expect a source→target pair (e.g. CreateOrderRequest → Order, Order → OrderResponse). Keep them granular and named accordingly. Resist a single mega-transformer that switches on class — it defeats the type-system benefits and makes nested handling brittle.
Use it at the edges of your app, not inside domain logic. Good boundaries:
RequestDto → CommandMessagePayload → DomainInputAggregate → ResponseDtoBad boundary: transforming inside an aggregate or a domain service. That forces the domain to depend on this bundle, which is the opposite of what you want from a third-party utility.
Compose with Symfony Form / Serializer. A common pattern is: deserialize/validate the request with Serializer + symfony/validator, then hand the resulting DTO to the object transformer for the DTO→domain mapping. This keeps validation concerns (which the transformer almost certainly doesn't handle) out of the transformer and avoids overloading it.
Collections. If the transformer supports mapping arrays or iterable, prefer array_map over the transformer's bulk API when you need error context per item — you'll get a stack trace pointing at the offending element instead of a generic "transformation failed" from the collection wrapper.
Testing pattern. Because these transformers are usually pure, unit-test them directly without booting the kernel:
$transformer = new OrderTransformer(/* collaborators */);
$result = $transformer->transform(new Order($id, $amount));
self::assertSame($expectedDto, $result);
Only reach for a kernel/bundle test if the bundle does container-dependent resolution (e.g. picks a transformer by target type). Check DependencyInjection/ to see if that's the case.
Very low adoption = read the source before you commit. 0 stars and 0 dependents means: no community answers on Stack Overflow, no blog posts, no third-party tutorials, and no guarantee the README is current with the tag you installed. Pin the exact version in composer.json and budget an afternoon to read DependencyInjection/, the transformer service, and the tests. If it's under 500 lines total, that's a fine trade; if it's 5,000 lines with no tests, look at symfony/serializer object normalizers or a simple Mapper class instead.
Bundle registration order matters. If you also use bundles that decorate services (e.g. MakerBundle, custom CompilerPasses), register this bundle before any bundle that iterates over tagged services your transformer relies on. When in doubt, put it low in config/bundles.php and use debug:container --tag=<whatever-tags-the-bundle-uses> to verify wiring.
Autowiring aliases may be missing. Small bundles frequently forget ->public() or the alias in services.xml. If Transformer $transformer fails to autowire, check bin/console debug:container | grep -i transform. You may need to add an explicit alias in config/services.yaml:
services:
SymfonyNotes\ObjectTransformerBundle\Transformer\Transformer:
alias: 'symfony_notes.object_transformer'
Config key naming is inconsistent across these bundles. Don't assume the root key is object_transformer — it might be object_transformer_bundle, symfony_notes_object_transformer, or something else. Verify with:
bin/console config:dump-reference object_transformer
If that errors, try the other candidate keys before editing files (the exception message usually names the correct one).
Circular references on bidirectional mappings. If you register A → B and B → A, and either transformer recursively transforms nested properties, you can easily deadlock or stack-overflow. Guard by keeping the graph acyclic (map only in one direction per flow) or by excluding the back-reference property from the mapping.
Performance in loops. Object transformers often use reflection and/or deep recursion. If you're transforming 10k+ items in a batch job (imports, exports), benchmark before shipping. Typical fixes: cache reflection metadata per class (many bundles do this automatically — check), or batch at the DB layer and transform only the final page.
Error messages are generic. Most implementations throw a TransformationException with the source/target class but not the failing property. If debugging is slow, wrap the call in a try/catch that logs get_class($source) and a serialize()-able subset of the input before rethrowing:
try {
$dto = $transformer->transform($entity);
} catch (\Throwable $e) {
$this->logger->error('transform failed', [
'source' => get_class($entity),
'id' => $entity->getId(),
'error' => $e->getMessage(),
]);
throw $e;
}
Extension points. Two things are worth checking in DependencyInjection/:
object_transformer.transformer) you can use to register your own transformers with a CompilerPass. If so, that's the clean way to extend without forking.EventDispatcher subscriber hook (e.g. PreTransformEvent / PostTransformEvent). If it does, use it for cross-cutting concerns (audit logging, normalization) rather than subclassing base transformers.Upgrade path and abandonment risk. With 0 dependents, assume no one else is running this in production. Keep the adapter interface described in Implementation Patterns so replacing the bundle with a hand-written mapper is a one-afternoon job. Update by bumping the constraint, running your unit tests for the transformers, and diffing Resources/config/ between versions — that's where most breaking changes hide.
How can I help you explore Laravel packages today?