spyrit/smoney-bundle
spyrit/smoney-bundle is a Symfony bundle for integrating SMoney payment services into PHP applications. It wraps the SMoney API with Symfony configuration and services, helping developers add payment workflows with less boilerplate. Best suited to projects already built on Symfony.
Reality check first: this is a Symfony bundle, not a Laravel package, and it has zero stars, zero dependents, and an essentially dead ecosystem footprint. It wraps the legacy S-money (French wallet/payment provider) PHP client. Treat it as a reference implementation to copy, not a maintained dependency.
Install and inspect before wiring anything:
composer require spyrit/smoney-bundle
Then open vendor/spyrit/smoney-bundle/ and read, in this order:
DependencyInjection/Configuration.php — the actual config keys (client ID, secret, sandbox flag, endpoint URLs).DependencyInjection/*Extension.php — how the services are constructed.Resources/config/services.yml — the service IDs you'll need to mimic.spyrit/smoney-api-client (or similarly named) package — this is where the real HTTP logic lives.Do not attempt to register the bundle via Laravel's package discovery. Laravel has no bundle concept. You have two realistic options:
First use case: initiating a payment. The typical flow is:
sandbox=true).Service provider binding (the pragmatic path). Rather than pulling in the Symfony bundle, bind the raw client in a dedicated S-moneyServiceProvider:
// app/Providers/SmoneyServiceProvider.php
public function register(): void
{
$this->app->singleton(SmoneyClient::class, function ($app) {
return new SmoneyClient(
clientId: config('services.smoney.client_id'),
clientSecret: config('services.smoney.client_secret'),
sandbox: app()->environment(['local', 'staging']),
);
});
}
Put the credentials in config/services.php under an smoney key and source them from .env — never hardcode. Follow the bundle's Configuration.php for the exact option names it expects; S-money used clientId/clientSecret/sandbox, but verify against the vendor source.
Payment initiation flow. Wrap the client behind an application-level service (e.g. App\Services\SmoneyGateway) that returns your own DTOs, not the vendor's objects. If S-money is ever replaced (Lydia, Mangopay, Stripe), only that adapter changes:
class SmoneyGateway
{
public function startPayment(Order $order): PaymentRedirect
{
$response = $this->client->createPayment([
'amount' => $order->total_cents, // check units — likely cents
'currency' => 'EUR',
'orderId' => $order->reference,
'returnUrl' => route('smoney.return', $order),
'callbackUrl' => route('smoney.callback'),
]);
return new PaymentRedirect($response->redirectUrl, $response->token);
}
}
Callback / webhook pattern. S-money callbacks are the authoritative source of payment state — do not trust the return URL redirect alone (a user can close the tab). Register a route, verify the payload, and update the order inside a transaction. Log the raw body before you parse it.
Facade for ergonomics (optional, if you're used to Laravel facades):
Smoney::startPayment($order);
backed by the singleton you registered above. Keep the facade thin — it's sugar over the gateway service.
Integration tip: if you're mixing Symfony components anyway, you're already using them — Laravel ships symfony/http-foundation and symfony/finder. But the bundle's own event dispatching (kernel.request, custom events) will not fire in Laravel. Any behavior relying on Symfony's event dispatcher must be reimplemented with Laravel events.
config/app.php providers array autoload, no ServiceProvider to rely on, no publishes() migrations. The bundle is effectively documentation for how to construct the client — plan on that.composer.json and audit the client source yourself before trusting it with money movement.Payment model. A silent ×100 error is catastrophic.uniqid()) so retries don't double-charge..env-aware. The bundle expects a config array; in Laravel you must translate your env() values into whatever argument names the client constructor takes. Read the constructor signature, not the YAML.@event_dispatcher, those hooks are inert in Laravel. Re-implement equivalent behavior with Event::dispatch() in your adapter.FakeSmoneyClient implementing the same interface and bind it in testing/local environments. You want to be able to run your checkout suite without hitting a possibly-dead sandbox.How can I help you explore Laravel packages today?