Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ripcord Laravel Package

darkaonline/ripcord

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up

composer require darkaonline/ripcord

On Laravel 5.5+ the service provider and Xmlrpc facade are auto-discovered. If you've disabled discovery (or you're on an older skeleton), add them manually:

// config/app.php
'providers' => [
    DarkaOnLine\Ripcord\RipcordServiceProvider::class,
],
'aliases' => [
    'Xmlrpc' => DarkaOnLine\Ripcord\Facades\Xmlrpc::class,
],

Publish the package config and read it first — it's the shortest way to understand how the package instantiates clients:

php artisan vendor:publish --provider="DarkaOnLine\Ripcord\RipcordServiceProvider"

Where to look first

  1. config/ripcord.php — the client prefix/class defaults the wrapper uses.
  2. vendor/darkaonline/ripcord/src/ — the Laravel layer is tiny (a provider, a facade, and a small registry class). Read it in five minutes.
  3. Ripcord_Client from the underlying library — this is where all the real behavior lives: call(), magic method proxies, transports, exceptions.

First use case: talk to a legacy XML-RPC endpoint

Register a client and make a call from Tinker:

use DarkaOnLine\Ripcord\Facades\Xmlrpc;

Xmlrpc::addClient('erp', \Ripcord_Client::class, 'https://erp.example.com/xmlrpc');

$client = Xmlrpc::getClient('erp');

// Magic proxy style
$methods = $client->system->listMethods();

// Explicit style (easier to grep, easier to mock)
$methods = $client->call('system.listMethods', []);

// Or through the facade registry
$methods = Xmlrpc::call('erp', 'system.listMethods', []);

Start with system.listMethods / system.methodHelp against the target server — it tells you what the remote actually exposes before you write any domain code.

Implementation Patterns

Register clients once, in a provider

Don't call addClient() from controllers. Register in a dedicated (optionally deferred) provider so the client registry is populated once per request and is trivial to fake in tests:

namespace App\Providers;

use DarkaOnLine\Ripcord\Facades\Xmlrpc;
use Illuminate\Support\ServiceProvider;

class XmlRpcServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Xmlrpc::addClient('erp', \Ripcord_Client::class, config('services.erp.xmlrpc_url'));
        Xmlrpc::addClient('crm', \Ripcord_Client::class, config('services.crm.xmlrpc_url'));
    }
}

Keep the URLs in config/services.php (env-driven), never inline in addClient() calls.

Wrap the client in a typed service

The facade returns a raw Ripcord_Client. Don't let that leak into your application layer — bind it to a small class with named methods:

namespace App\Services;

class ErpGateway
{
    public function __construct(private \Ripcord_Client $client) {}

    public function customer(int $id): array
    {
        return $this->client->call('customer.get', [$id]);
    }

    public function createInvoice(array $payload): int
    {
        return (int) $this->client->call('invoice.create', [$payload]);
    }
}
// AppServiceProvider::register()
$this->app->bind(ErpGateway::class, fn () => new ErpGateway(
    \DarkaOnLine\Ripcord\Facades\Xmlrpc::getClient('erp')
));

This is the single most valuable pattern with this package: it isolates the old Ripcord API (and any future replacement) behind something your app owns.

Batch independent lookups with async calls

XML-RPC is chatty and synchronous by default. If you need several unrelated results, use Ripcord's async call objects so requests pipeline instead of serializing:

$a = $client->callAsync('customer.get', [1]);
$b = $client->callAsync('customer.get', [2]);
$c = $client->callAsync('invoice.list', [1]);

$customerA = $a->send();
$customerB = $b->send();
$invoices  = $c->send();

Reach for this when a page needs more than two or three round trips — it's usually the difference between a 300 ms and a 1.2 s response.

Server side: expose a Laravel service over XML-RPC

The package doesn't add much here; use Ripcord_Server directly inside a route or controller and let it write the response:

// routes/web.php (or api.php, but CSRF matters — see below)
Route::post('/xmlrpc', function () {
    $server = new \Ripcord_Server(new \App\XmlRpc\ReportsService());
    $server->service();
});

Put the exposed logic in a plain PHP class with public methods and no Laravel dependencies; Ripcord_Server introspects public methods. Treat the endpoint as untrusted input — validate argument types inside the service methods, because XML-RPC's type system is loose.

Error handling: convert faults into domain exceptions

Ripcord surfaces transport and protocol faults as Ripcord_Exception (HTTP errors, malformed responses, server faults). Wrap once, at the gateway boundary:

try {
    return $client->call('invoice.create', [$payload]);
} catch (\Ripcord_Exception $e) {
    report($e);
    throw new \App\Exceptions\ErpUnavailable($e->getMessage(), previous: $e);
}

Callers then deal with one exception type instead of a library class.

Testing

Because the facade is backed by a normal container binding, you can mock it:

Xmlrpc::shouldReceive('getClient')->with('erp')->andReturn($mock);

That's brittle for anything beyond a smoke test. The durable approach is the gateway class above: bind a fake ErpGateway implementation (or a Ripcord_Client subclass whose call() returns fixtures) in the test container. Ripcord performs real network I/O, so never let tests hit a live endpoint.

Gotchas and Tips

  • This is a thin wrapper, not a framework. The Laravel package only adds a provider, a facade, and a client registry. Every behavioral quirk you hit (call semantics, faults, transports, encoding) is Ripcord's, and Ripcord's core dates from the PHP 5 era. Read the source when in doubt — it's small.
  • PHP 8 compatibility. Old XML-RPC libraries are prone to dynamic-property deprecations and other PHP 8 warnings. Pin the package version, run your test suite on your exact PHP minor version, and don't be surprised by notices from vendor/.
  • addClient() expects a constructible class, not an instance. The third argument is the URL, and the wrapper does new $client($url). So any subclass you register must accept the same constructor signature — that's your extension point for logging, retries, or header injection.
  • Extension point: subclass Ripcord_Client. Add request/response logging, retry logic, or auth headers by overriding call()/transport, then register your class with addClient(). This is cleaner than wrapping every call site.
  • No timeout or retry config in the facade. Configure timeouts at the transport level (cURL options / default_socket_timeout in php.ini) or via your Ripcord_Client subclass. A hung XML-RPC endpoint will otherwise hold a PHP worker until the default socket timeout.
  • Empty arrays are ambiguous. XML-RPC distinguishes <array> from <struct>; PHP's empty array doesn't. If a remote rejects a payload, capture the raw request (log from your transport subclass) and check what was actually encoded.
  • Dates and binary need explicit encoding. Don't assume DateTime is auto-converted — send ISO 8601 strings in the format the remote documents. Base64 payloads bloat fast; watch post_max_size/memory_limit on both ends when moving files.
  • CSRF on the server endpoint. A POST route accepting XML-RPC needs to be excluded from VerifyCsrfToken (or validateCsrfTokens() in Laravel 11's bootstrap/app.php). Also consider a shared-secret middleware — XML-RPC has no built-in auth.
  • The server bypasses Laravel's response pipeline. Ripcord_Server::service() writes output directly. Don't expect Response objects, middleware-applied headers, or exception rendering to behave normally; wrap it deliberately.
  • config:cache and env(). Resolve endpoint URLs in config files, not inside addClient() calls; otherwise you'll break under config:cache.
  • Facade aliasing on Laravel 11. The default skeleton no longer ships an aliases array; rely on package discovery or register the alias explicitly in bootstrap/app.php. If Xmlrpc:: throws "class not found", that's the cause.
  • Small ecosystem, zero dependents. Thirty-six stars and no downstream dependents means you're largely on your own for issues. Pin the version in composer.json, and keep the gateway abstraction so you can replace the implementation with a hand-rolled Guzzle/Saloon XML-RPC client if the package stalls. For greenfield integrations, check whether the remote offers JSON-RPC or REST first — XML-RPC is usually the legacy option, not the best one.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin