hboie/data-io-bundle
hboie/data-io-bundle provides reusable import and export tooling for PHP applications, with configurable readers, writers, and format adapters to simplify moving structured data between files, streams, and external systems. Designed for flexible data exchange workflows.
This assessment is based on the v0.8 release note, which only states “added loader interface.” Treat the loader contract as the package’s primary extension point until the README and source confirm otherwise.
Loader interface. Note:
void, mixed, typed DTOs, iterables).bind, singleton, or a manager-style resolver that maps the interface to a concrete loader. That tells you what you get by default and how to swap it.php artisan vendor:publish discovery step and inspect config/ for loader selection, source paths, or driver names.$loader = app(\Vendor\Package\Contracts\Loader::class);
$loader->load(/* minimal argument */);
First realistic use case: resolve the default loader, load one resource through it, then implement the interface for your own source (database, API, filesystem, etc.). Because v0.8 is pre-1.0, verify the contract before committing production code to it.
Type-hint the interface, never the concrete class. This is the whole point of the new contract and keeps you insulated from internal implementation changes:
public function __construct(private \Vendor\Package\Contracts\Loader $loader) {}
Bind custom loaders in your own service provider. Keep package code untouched:
$this->app->bind(
\Vendor\Package\Contracts\Loader::class,
\App\Support\ApiLoader::class
);
Use singleton if the loader is stateless and safe to reuse; use bind if it carries per-resolution state.
Use contextual binding when multiple loaders are needed. If the package resolves the interface from the container in several places, bind different implementations per consumer rather than introducing global switches.
Decorate rather than fork. Wrap the default or your own loader to add caching, logging, retries, or metrics:
final class CachingLoader implements Loader
{
public function __construct(
private Loader $inner,
private CacheRepository $cache,
) {}
public function load(mixed $input): mixed
{
return $this->cache->remember(
'loader:'.md5(serialize($input)),
now()->addMinutes(10),
fn () => $this->inner->load($input)
);
}
}
Test against the contract. Fake or stub the interface in unit tests, and keep one integration test that exercises the real default loader. If the package ships a fake, prefer it; otherwise a simple anonymous class is enough.
Config-driven selection. If the package exposes a config key for the loader or driver, keep environment-specific choices in config and resolve the implementation through the container rather than branching on env() inside application code.
composer.json and read the changelog before upgrading.extra.laravel.providers) or must be registered manually in bootstrap/providers.php.array where the contract expects iterable or a specific DTO, PHP will fail at runtime, not at bind time. Run a real load in a test early.app()->make(Loader::class) and get_class(...) confirms which implementation is actually active. This is the fastest way to debug “my custom loader isn’t being used.”How can I help you explore Laravel packages today?