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

Soap Laravel Package

ricorocks-digital-agency/soap

A Laravel SOAP client with an expressive, HTTP-client-like API. Build SOAP clients, send requests, inspect responses, and fake SOAP calls in tests for fast, reliable integration testing.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer and note the new major version constraint:

composer require ricorocks-digital-agency/soap:^4.0

The 4.0.0 release is a framework-support release: it adds Laravel 13 support and drops Laravel 11. That means:

  • Laravel 12 and 13 applications can move to ^4.0.
  • Laravel 11 applications must either stay on ^3.0 or upgrade the framework first. Check your composer.json platform requirements (PHP version) alongside the Laravel bump before running composer update.

Publish the package config if you want to tune defaults:

php artisan vendor:publish --tag=soap

Where to look first:

  1. The package README / config/soap.php for the facade entry point and available options.
  2. The facade RicorocksDigitalAgency\Soap\Facades\Soap and the underlying RicorocksDigitalAgency\Soap\Soap class — that is where to(), call(), hooks and faking live.
  3. Your existing SOAP endpoints' WSDL URLs, so you can confirm the package can parse them before writing any application code.

First use case — a smoke test against a real WSDL:

use RicorocksDigitalAgency\Soap\Facades\Soap;

$response = Soap::to('https://example.com/service?wsdl')
    ->call('GetCustomer', ['id' => 123]);

dump($response->response); // raw decoded payload

Once that returns, wrap it in a small service class (see below) rather than scattering facade calls through controllers.

Requires the PHP ext-soap extension. Confirm with php -m | grep soap on every environment, including CI and production containers.

Implementation Patterns

Wrap each remote service in a dedicated class. Keep the facade out of controllers, jobs and models. Inject it or resolve it inside a thin client:

namespace App\Services\Billing;

use RicorocksDigitalAgency\Soap\Facades\Soap;

class BillingSoapClient
{
    public function __construct(private string $wsdl) {}

    public function getInvoice(int $id): array
    {
        return Soap::to($this->wsdl)
            ->withOptions(['connection_timeout' => 10, 'cache_wsdl' => WSDL_CACHE_BOTH])
            ->call('GetInvoice', ['invoiceId' => $id])
            ->response;
    }
}

Bind the class in a service provider so the WSDL URL and options come from config, not hardcoded strings.

Use hooks for cross-cutting concerns instead of repeating them. The package exposes request/response lifecycle hooks, which is the natural place for auth headers, correlation IDs, tracing and logging:

Soap::beforeRequest(function ($request) {
    $request->arguments['authToken'] = config('services.billing.token');
    return $request;
});

Register global hooks in a service provider (boot()), and request-scoped tweaks via withOptions() on the individual call.

Map SOAP faults to your own exception hierarchy. SOAP faults surface as PHP SoapFault exceptions; catch them at the client boundary and rethrow a domain exception so callers never depend on SOAP semantics:

try {
    return $client->getInvoice($id);
} catch (\SoapFault $e) {
    throw new BillingUnavailableException($e->getMessage(), previous: $e);
}

Decide per-endpoint whether you need WSDL mode. WSDL mode gives you functions() and argument validation but adds a fetch and parse cost on first call (mitigated by cache_wsdl). Non-WSDL mode (passing null plus location/uri options) is faster and more predictable when the remote WSDL is flaky or only reachable from inside a VPC.

Fake aggressively in tests. This is the biggest day-to-day win over raw SoapClient:

use RicorocksDigitalAgency\Soap\Facades\Soap;

Soap::fake(['*' => Soap::response(['status' => 'ok'])]);

// ... exercise the code under test ...

Soap::assertSent(fn ($request) => $request->method === 'GetInvoice');
Soap::assertNotSent(fn ($request) => $request->method === 'VoidInvoice');

Fake the client in feature tests, and reserve real calls for a small number of contract/integration tests tagged and excluded from the default suite. Assert on the service class behaviour in unit tests and on the outgoing request shape in feature tests — the assertions on method name and arguments are what catch regressions when the remote API changes.

Wrap write operations in jobs. SOAP calls are slow and synchronous. Push them onto the queue with retries and a backoff, then keep the HTTP request path read-only.

Expose typed return objects. The raw ->response is an anonymous object/array depending on the endpoint; normalise it into a DTO inside the client so the rest of the app is insulated from WSDL quirks.

Gotchas and Tips

  • Laravel 11 is no longer supported in 4.x. If you have multiple apps on different frameworks, pin per app (^3.0 vs ^4.0) rather than relying on a single monorepo constraint. Also re-check the PHP requirement that comes with the Laravel 13 bump; CI images pinned to older PHP will fail at composer install before any code runs.
  • No API changes are advertised in 4.0.0 — it is a support-matrix release. Treat the upgrade as low-risk for Laravel 12 apps, but read the full changelog between your installed version and 4.0.0 if you are jumping from 2.x.
  • ext-soap is a hard runtime dependency. It is easy to have it locally and miss it in a slim production image. Add ext-soap to composer.json require if the package doesn't already enforce it, so the failure happens at build time.
  • WSDL fetching is a real network call. Do not resolve WSDL-dependent code in a service provider's register() — it will break artisan commands, queue workers and deploy scripts whenever the remote host is unreachable. Lazy-resolve inside the client method.
  • Cache the WSDL. Set cache_wsdl in withOptions(); otherwise every PHP process pays the fetch/parse cost. Be aware that cached WSDL can go stale after a remote schema change — clear it (or set WSDL_CACHE_NONE in a debug path) when you see "method not found" style errors that don't match the remote docs.
  • Hooks registered on the facade are effectively global static state. They survive between tests in the same process. Reset them in tearDown() (or use the package's fake/reset helpers) or you will get order-dependent test failures that appear only when the full suite runs.
  • Timeouts are not Laravel's HTTP client timeouts. connection_timeout and the PHP default_socket_timeout ini value both matter. Set explicit timeouts in options; the default can hang a queue worker for a long time on a dead endpoint.
  • SSL verification in local/staging. Self-signed internal endpoints need verify_peer/allow_self_signed stream context options. Never disable verification in production code paths — gate it on app()->isLocal().
  • SOAP version mismatches produce confusing faults. If the remote expects SOAP 1.2, pass soap_version => SOAP_1_2; the default 1.1 envelope can be rejected with an unhelpful parse error.
  • Log the envelope when debugging, not the object. Enable tracing/request logging through the hooks and dump the raw XML request and response; var_dump of the response object hides the actual fault string. Redact credentials from the logged envelope.
  • Large payloads and memory. Request and response bodies are held in memory as strings plus the decoded object. For bulk operations, page the calls rather than requesting thousands of records in one envelope.
  • Extension point to prefer: if you need behaviour the hooks don't cover, extend the package's Soap class (or bind your own implementation into the container behind the facade) instead of forking. That keeps future major-version upgrades — like this one — to a single composer update.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource