tiloweb/matpe-bundle
A composer-installable PHP bundle from tiloweb that wraps MATPE services for quick integration. Offers simple configuration, service wiring, and a clean API so you can add its functionality without boilerplate. Lightweight and easy to drop into existing Laravel or Symfony projects.
First, calibrate expectations: despite the Laravel framing, tiloweb/matpe-bundle is a Symfony bundle, not a Laravel package. There is no MatpeServiceProvider, no facade, and no config/matpe.php publish tag. In a Laravel app you consume it as a plain Composer library and wire it yourself; in a Symfony app you register the bundle.
Minimal Symfony path:
composer require tiloweb/matpe-bundle (pin the version — see Gotchas).Tiloweb\MatpeBundle\MatpeBundle::class => ['all' => true] in config/bundles.php.config/packages/matpe.yaml and put credentials in .env.local (e.g. MATPE_API_KEY, MATPE_BASE_URI), referenced as %env(MATPE_API_KEY)%.php bin/console config:dump-reference matpe to see the real config tree before guessing key names.Where to look first, in order: DependencyInjection/Configuration.php (authoritative config keys and defaults), Resources/config/services.* (the service ID and whether it's public/autowired), then the client class itself for the methods you can actually call. Skip the README until you've confirmed the service ID — the docs are thin at 3 stars.
For Laravel specifically: skip bundle registration entirely. In a MatpeServiceProvider::register(), read credentials from config/services.php and bind the bundle's client class as a singleton, passing config into its constructor or a small factory. Then inject it by type-hint like any other class. Expect to write ~15 lines of glue.
A good first use case: one read-only call in an artisan/console command (matpe:ping), dumping the raw response. That proves credentials, base URI, and network path before you touch application logic.
Anti-corruption layer. Never let the bundle's client leak into controllers or models. Define App\Contracts\MatpeGateway with the 2–4 methods you actually use, implement it with a class that wraps the bundle client, and inject the interface. When you inevitably fork or replace the package, one file changes.
Constructor injection everywhere. The bundle's service is autowired in Symfony; in Laravel the singleton binding gives you the same ergonomics. Avoid $container->get() — it hides dependencies and makes the config-vs-service distinction murky.
Own the resilience. The package is a thin HTTP wrapper; assume no retries, no backoff, no circuit breaker, no caching. Put those in your adapter:
return $this->cache->remember("matpe:{$id}", 3600, fn () =>
retry(3, fn () => $this->client->fetch($id), 200)
);
Push calls off the request path. Any write or bulk read belongs in a queued job (dispatch(new SyncMatpeRecord($id)) in Laravel, Messenger in Symfony). MaTPE calls are external I/O; a slow or failing upstream should not be able to time out a user's page load.
Test against your interface, not the package. Bind a fake MatpeGateway in tests. If you must test the real client, inject a Guzzle MockHandler / Symfony MockHttpClient — do not hit the live API in CI, and do not assert on response shapes you haven't recorded as fixtures.
Config through env, promoted once. Symfony resolves %env()% at container compile/runtime depending on where it's referenced; Laravel resolves at config-cache time. Either way, read the value once in the factory/binding rather than sprinkling env() calls through business logic.
app/Services/ and own outright. That is often the better call than a dependency here."tiloweb/matpe-bundle": "1.0.3"), not ^1.0. An abandoned-but-unpinned dependency is the worst of both worlds.Target [X] is not instantiable or a BindingResolutionException, not a helpful config error.api_ke falls back to a default and you get a 401 with no hint. Verify with config:dump-reference, and dump the resolved container (debug:container matpe) to see the actual constructor arguments.ConnectException) from HTTP failures (RequestException, with getResponse()->getStatusCode()) — the first is retryable, a 401 is not, and a 422 needs the body surfaced to the caller.RateLimiter::for('matpe', ...)) if you're doing bulk work.Middleware::log() or HttpClient's profiler in dev) rather than dd()-ing inside vendor code. You'll see the exact URL, headers, and payload — which is usually where the bug is.decorates: tiloweb.matpe.client); in Laravel, bind your own implementation to the interface the bundle service is aliased to. Either way, keep the vendor directory pristine so composer update is survivable.How can I help you explore Laravel packages today?