inscouts/rms-push-notifications-bundle
A Symfony bundle that integrates RMS push notifications into your PHP application, providing services and configuration to send notifications through the RMS platform with minimal setup in your Symfony project.
First, a framing correction: despite the "Laravel developer" framing, this is a Symfony bundle (a fork of richsage/RMSPushNotificationsBundle), not a Laravel package. There is no service provider, no config/push.php, no facade. It was built for Symfony 2.x and ships APNS (binary provider protocol) and GCM (HTTP legacy) transports — both of which Apple and Google have since shut down. Treat this as a legacy-maintenance / reference-read dependency, not something you install into a new Laravel app.
Minimal steps to get it running (in a Symfony 2/3-era app, or wired by hand in Laravel):
dev-master:
composer require inscouts/rms-push-notifications-bundle:dev-master
app/AppKernel.php (new RMS\PushNotificationsBundle\RMSPushNotificationsBundle()). Symfony 4+: append to config/bundles.php.rms_push_notifications root key:
# config/packages/rms_push_notifications.yaml
rms_push_notifications:
ios:
sandbox: true
certificate: "%kernel.project_dir%/certs/apns-dev.pem"
passphrase: "%env(APNS_PASSPHRASE)%"
android:
api_key: "%env(GCM_API_KEY)%"
rms_push_notifications:
use RMS\PushNotificationsBundle\Message\iOSMessage;
$message = new iOSMessage();
$message->setDeviceIdentifier($deviceToken);
$message->setMessage('Your order has shipped');
$message->setAPS(['badge' => 1, 'sound' => 'default']);
$results = $this->get('rms_push_notifications')->send($message);
Where to look first, in this order:
DependencyInjection/Configuration.php — the authoritative list of config keys; docs are sparse and may lag the code.Service/Notifications.php — the dispatcher; shows which message types map to which transport and whether errors are returned or swallowed.Message/iOSMessage.php and Message/AndroidMessage.php — the fluent API you'll actually touch.Resources/config/services.xml — service IDs, which you'll need for overrides and for manual wiring in Laravel.Resources/doc/ — usually the best surviving usage notes in these old bundles.For Laravel specifically: don't try to make the bundle work end-to-end. Either (a) lift the message/payload construction logic into your own classes and talk to APNS HTTP/2 and FCM v1 directly, or (b) skip it and use laravel-notification-channels/apn + laravel-notification-channels/fcm. If you must use it, bind the service manually in a provider:
$this->app->singleton('rms_push_notifications', function () {
return new \RMS\PushNotificationsBundle\Service\Notifications([
// transport objects constructed by hand from config()
]);
});
You'll be reconstructing the DI graph yourself, because the bundle's container config assumes Symfony's %parameter% resolution and its own services.xml.
Message-object-then-dispatch. The whole bundle is built around one pattern: construct a MessageInterface implementation, mutate it fluently, hand it to the central service. Everything else is configuration. Lean into this rather than reaching for the individual transport services.
$msg = new AndroidMessage();
$msg->setDeviceIdentifier($token);
$msg->setMessage('Fallback body for notification tray');
$msg->setData(['order_id' => 1234, 'deep_link' => '/orders/1234']);
$msg->setCollapseKey('order-updates'); // avoid a backlog of stale tray items
Fan-out with a single loop, not a single call. There is no multi-device send. For a user with N devices, loop and collect per-device results — then prune tokens that come back as permanently invalid:
$invalid = [];
foreach ($user->pushTokens as $token) {
$msg = (new iOSMessage())->setDeviceIdentifier($token->value)->setMessage($body);
$result = $push->send($msg);
if ($result->isFailed() && $result->isPermanentFailure()) {
$invalid[] = $token->id;
}
}
PushToken::whereIn('id', $invalid)->delete();
Verify the result-object method names against Service/Notifications.php in your pinned commit — this API varied between forks.
Push it behind a queue. Sending is synchronous and opens a socket per message; in a web request that means user-facing latency and no retry. In Laravel, wrap it in a job and never call it from a controller. In Symfony, a MessageHandler or a console command processing a table.
Keep a notification log. Because the transports fail silently in some code paths, persist a row per send attempt (token, platform, payload, response, timestamp). This is the only reliable debugging surface you'll have.
Abstract the sender behind your own interface. This is the highest-leverage thing you can do with an abandoned dependency:
interface PushSender {
public function send(PushTarget $target, PushPayload $payload): PushResult;
}
Implement it once with this bundle and once with FCM v1 / APNS HTTP/2. Then migrating off is a container binding change, not a rewrite of every call site. Given the transports are dead, plan for that swap from day one.
Testing. Never let tests reach the transport. Bind a fake PushSender (or a fake rms_push_notifications) that records messages, and assert on the constructed payloads — that's the part with real logic (badge counts, collapse keys, deep links) and the part most worth covering.
The transports themselves are the biggest gotcha. The APNS binary provider protocol this bundle implements was retired by Apple (fully shut down March 2021; HTTP/2 + JWT is the only supported path). GCM legacy HTTP was shut down in April 2019 in favour of FCM. Even a perfectly configured install will not deliver a notification today. If your goal is working push, this package cannot get you there.
Symfony 2-era code, modern PHP. Expect untyped properties, old Symfony\Component\HttpKernel APIs, possibly each()-adjacent idioms, and no PHP 8.x compatibility. Composer will fight you on Symfony version constraints. If you need it to parse at all, you may be looking at a fork-of-the-fork or a composer.json override with --ignore-platform-reqs — neither of which is a production strategy.
Certificate quirks. APNS expects a combined .pem (cert + key) with an optional passphrase; .p12 needs conversion first. Sandbox and production are separate endpoints and separate certificates — the single sandbox: true flag is a common source of "works in dev, silently nothing in prod" reports. Keep the cert path outside the repo and inject the passphrase via env.
Payload size. The original APNS limit was 256 bytes; modern APNS allows 4KB and FCM ~4KB. This bundle does not validate size. Large setData() arrays will be rejected at the transport level with an error that is easy to miss — clamp and validate on your side before calling send().
Silent failures. Several historical versions of send() returned a result object but did not throw on transport failure. Always inspect the return value; never assume a non-exception means delivery. Log the raw response.
No security process. Zero dependents, a fork with no upstream activity, blank star count: there will be no CVE response and no bug fixes. Pin to an exact commit hash (not dev-master), commit it to your lockfile, and set a calendar reminder to remove it. Vendoring the two or three classes you actually use is often safer than depending on the package.
Extension points, if you must keep it. Override the per-platform service definitions (see Resources/config/services.xml for IDs) to inject a custom transport, or implement MessageInterface for a payload shape the bundle doesn't cover. The Notifications service is the natural seam — decorate it rather than editing vendor code.
Where the real value is. Reading Message/iOSMessage.php and AndroidMessage.php is a fast way to learn the shape of an APNS/FCM payload (aps dictionary, data map, collapse keys, badge/sound semantics) without wading through Apple's and Google's docs. Mine it for that, then send with a maintained client.
How can I help you explore Laravel packages today?