weblabel/data-transformer
weblabel/data-transformer is a Laravel/PHP package for transforming arrays, objects, and application data into clean, consistent output using reusable rules. It helps keep APIs, resources, and presentation logic organized and maintainable.
Install it and immediately open vendor/weblabel/data-transformer/src/ — with 0 stars and a single 2021 release, the README is thin and the source is the documentation.
composer require weblabel/data-transformer
First, identify the contract. The package's whole value proposition is an interface (something like a TransformerInterface / DecoderInterface with a transform() or decode() method returning array) plus one or more concrete implementations (e.g. a JSON decoder). Confirm the exact FQCNs before writing code — there is no stable public API contract beyond that 2021 tag.
First use case: stop sprinkling json_decode($body, true) through controllers and jobs. Instead, resolve the decoder from the container, inject it, and let callers depend on the interface:
use Weblabel\DataTransformer\...; // verify class name in src/
public function __construct(private TransformerInterface $transformer) {}
public function handle(string $payload): array
{
return $this->transformer->transform($payload);
}
That is the day-to-day leverage: a testable seam around string→array decoding, not new decoding behaviour (it almost certainly delegates to native json_decode).
Bind the interface once. If the package ships a Laravel service provider, it will (maybe) auto-register via discovery. If it doesn't, add the binding in your own AppServiceProvider:
$this->app->bind(TransformerInterface::class, JsonTransformer::class);
Or register a singleton if the implementation is stateless — which a decoder should be.
Strategy per format. The "object-oriented interface" phrase suggests the intended pattern is one implementation per format (JSON now, XML/CSV/YAML by you later). Choose the implementation at the edge of your app (a factory keyed on Content-Type or a route parameter) and keep the interface downstream. That way a new format never touches business logic.
Decorate for validation and logging. Because it's an interface, wrap it:
final class ValidatingTransformer implements TransformerInterface
{
public function __construct(private TransformerInterface $inner) {}
public function transform(string $input): array
{
if (trim($input) === '') {
throw new InvalidArgumentException('Empty payload');
}
return $this->inner->transform($input);
}
}
Bind the decorator around the concrete class and get logging/guarding for free.
Testing. The main payoff is that you can swap in a fake:
$fake = new class implements TransformerInterface {
public function transform(string $input): array { return ['id' => 1]; }
};
$this->app->instance(TransformerInterface::class, $fake);
Existing tests that call real JSON strings keep working; the fake is for tests where the decoded result is the only thing that matters.
Integration with HTTP clients. Decode once at the boundary — say in a Saloon/Http response hook or a small ApiClient class — and pass arrays inward. Do not let the transformer leak into domain services other than as the injected interface.
composer.json require block: php and illuminate/* constraints from 2021 may refuse to install on PHP 8.3+/Laravel 11. If it blocks, either pin the package (bad) or copy the one interface and one class into app/Support/ (~40 lines) — you lose nothing but a composer update.php artisan vendor:publish finds nothing, that's expected. Bind manually (see above).[]/null? Native json_decode returns null and sets json_last_error(). If the wrapper swallows that, a broken API response silently becomes an empty array and you debug the wrong layer. Read the concrete class's body before trusting it; wrap it with an explicit json_last_error() check or a validating decorator if needed.assoc flag / depth. Whether objects come back as arrays or stdClass depends entirely on the implementation's internal json_decode($s, true). If nested objects matter, verify with a quick dd($transformer->transform('{"a":{"b":1}}')).\Throwable at the boundary unless you've confirmed a package-specific exception class exists; catching a class that was never thrown will mislead future maintainers.match on format to pick the implementation.json_decode($s, true, 512, JSON_THROW_ON_ERROR) first. If raw PHP is wrong too, the payload is the problem, not the package; if they differ, the package is doing something on top (trimming, BOM handling, default flags) that the README doesn't mention.DecoderInterface in the app and, if you want the package, have one adapter class implement your interface by delegating. Then removing the package later is a one-file change rather than a refactor.How can I help you explore Laravel packages today?