rikudou/qr-payment-qr-code-provider
Provider for rikudou/qr-payment that connects payment data to QR code generation libraries, letting PHP and Laravel applications render scannable payment QR codes from a simple, consistent interface. Lightweight and easy to wire in, it supports fast, error-free mobile payments.
This package is a companion to the base rikudou/qr-payment library. The base library builds the Czech "QR Platba" (SPAYD) payment string from IBAN, amount, variable symbol, etc. This package does exactly one job: take that string and hand back a rendered QR code image. Install both — the provider is useless without the base library:
composer require rikudou/qr-payment rikudou/qr-payment-qr-code-provider
Look at vendor/rikudou/qr-payment-qr-code-provider/src/ first. There will be a single concrete provider class implementing an interface declared in the base package. Read its constructor — it tells you which underlying QR library it wraps (endroid/qr-code, bacon/bacon-qr-code, or similar) and what knobs (size, margin, error correction level) the provider exposes. Everything else in the package is boilerplate around that one method.
The first use case almost every Czech/Slovak Laravel app hits is an invoice PDF with a payment QR:
use Rikudou\QrPayment\QrPayment;
$payment = QrPayment::create()
->setIban('CZ6508000000192000145399')
->setAmount(1234.56)
->setCurrency('CZK')
->setVariableSymbol('2024001')
->setMessage('Faktura 2024-001');
// The provider class from this package is passed in (or resolved) here:
$png = $payment->getQrCode(/* provider */);
file_put_contents(storage_path('app/invoices/2024-001.png'), $png);
If the provider is auto-wired or accepts no constructor args, new QrPaymentQrCodeProvider() is enough. Confirm the exact class name and method signature against src/ — the surface area is tiny, so a two-minute read beats guessing.
Bind the provider interface once. The base library depends on an abstraction, not the concrete class. Bind it in AppServiceProvider so any code (including anything the base library instantiates internally) gets the same implementation:
use Rikudou\QrPayment\...\QrCodeProvider as QrCodeProviderInterface;
use Rikudou\QrPaymentQrCodeProvider\QrCodeProvider;
public function register(): void
{
$this->app->bind(QrCodeProviderInterface::class, QrCodeProvider::class);
}
Return it from a controller as an image response. Cache the bytes, don't regenerate per request:
public function qr(Invoice $invoice)
{
$png = Cache::rememberForever("invoice-qr-{$invoice->id}", fn () => $invoice->qrPayment()->getQrCode());
return response($png, 200, [
'Content-Type' => 'image/png',
'Cache-Control' => 'public, max-age=31536000, immutable',
]);
}
Inline it in Blade via a data URI — avoids an extra HTTP round-trip for a small image, and sidesteps auth issues on the download route:
$dataUri = 'data:image/png;base64,' . base64_encode($png);
Embed inside PDFs (Dompdf, Snappy, mPDF). Dompdf will load a data: URI but is picky about whitespace; base64_encode output is safe. For Snappy/wkhtmltopdf, use the data URI too — pointing at a local file path fails in the container. If PDF rendering is slow, write the PNG to a temp file once per request and reuse it across all invoices.
Decorator for logging/metrics. Wrap the provider to time QR generation and log the payment string (careful: it contains IBAN and amounts — log only to a private channel).
Testing pattern. Don't snapshot the image — assert magic bytes and decode the string back:
$png = $payment->getQrCode();
$this->assertStringStartsWith("\x89PNG", $png);
For a stronger check, run it through a QR decoder in a test and assert the decoded SPAYD string matches what the base library produced.
Version drift is the main risk here. This package is a thin shim; its constraints on the underlying QR library and on rikudou/qr-payment need to line up. If Composer resolves the base library to a newer minor that changed the provider interface, you get a hard TypeError at runtime, not install time. Pin both in composer.json and bump them together. With 0 dependents and 2 stars, expect to read the changelog yourself.
No Laravel integration. There's no service provider, no config file, no facade. All wiring is manual. That's fine — it also means no auto-discovery surprises when upgrading Laravel.
Extension requirements. The underlying QR library needs either ext-gd or ext-imagick. Local dev may have GD while production containers don't; run php -m | grep -i gd in your Dockerfile build step and fail fast, otherwise you get an obscure error deep in image rendering.
Czech QR Platba is not a generic QR code. It's a specific SPAYD string format. Don't try to hand-roll the payload — always go through the base library, and validate output against the Czech Banking Association spec. Error correction level and module size matter for scannability at small print sizes; if the provider exposes them, prefer the defaults from the spec over "smallest possible."
Amounts, currency, and IBAN formatting are the base library's job, not this package's — but they're where 90% of bugs appear. 1234.56 vs 123456 (haléře vs koruny), CZ65 0800 ... with spaces, variable symbol leading zeros. Write a test that decodes the final QR back to a string and asserts the exact SPAYD output; that catches errors from both layers.
Validate with real banking apps. The official scanners (CSOB, Fio, Air Bank, Revolut for SPAYD-adjacent formats) are the only ground truth. Test on the smallest size you print and on a phone camera — a technically-valid QR that renders at 60px is often unscannable.
Error handling is thin. The provider will likely throw a generic exception if the QR library fails (GD not compiled, invalid size). Wrap getQrCode() at the call site and surface a meaningful message ("QR generation unavailable — check ext-gd"); don't let an invoice render silently without a payment code.
How can I help you explore Laravel packages today?