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

Besimple Soap Client Laravel Package

reprovinci/besimple-soap-client

A Laravel wrapper for the BeSimple SOAP client that simplifies configuring and using SOAP/WSDL web services in PHP applications. It provides service provider integration and convenient access for building and calling SOAP clients, useful for integrating legacy or third-party SOAP APIs.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and prerequisites

composer require reprovinci/besimple-soap-client

This package is a drop-in replacement/enhancement around PHP's native SoapClient. It is not a Laravel package: there is no service provider, no facade, no config file, and no auto-discovery. You wire it up yourself. Before anything else confirm the runtime has ext-soap enabled (php -m | grep soap) and that outbound SOAP/WSDL URLs are reachable — the library still depends on libxml/WSDL parsing under the hood.

First thing to check in the repo: the src/BeSimple/SoapClient/ tree. The entry points you will actually touch are:

  • SoapClientBuilder — fluent construction (WSDL, options, filters/plugins)
  • SoapClientOptions — the equivalent array/options object if you use the non-builder path
  • WsSecurity/WsSecurity.php — the reason most people adopt this over vanilla SoapClient
  • Mtom/ and SwA/ — attachment support

First use case — a WSSE-secured WSDL call

use BeSimple\SoapClient\SoapClientBuilder;
use BeSimple\SoapClient\WsSecurityFilter;

$client = SoapClientBuilder::create()
    ->withWsdl('https://partner.example.com/service?wsdl')
    ->withOptions([
        'trace'      => true,
        'exceptions' => true,
        'cache_wsdl' => WSDL_CACHE_NONE, // during development
    ])
    ->withWsSecurityFilter(
        WsSecurityFilter::create()
            ->withUsernameToken($username, $password)
            ->withPasswordDigest(true)   // adjust per partner spec
    )
    ->build();

$response = $client->SomeOperation(['id' => 42]);

If you only need vanilla SOAP, you do not need this package — use \SoapClient directly. Adopt it when you need WS-Security, MTOM/SwA attachments, or cookie/session-aware SOAP transports.

Implementation Patterns

Wrap the client in a dedicated service class and bind it in the container. Do not inject the SOAP client into controllers; it is stateful (__getLastRequest, cookies) and slow to rebuild.

// app/Services/Partner/PartnerSoapClient.php
namespace App\Services\Partner;

use BeSimple\SoapClient\SoapClientBuilder;
use BeSimple\SoapClient\WsSecurityFilter;

class PartnerSoapClient
{
    private \BeSimple\SoapClient\SoapClient $client;

    public function __construct(array $config)
    {
        $this->client = SoapClientBuilder::create()
            ->withWsdl($config['wsdl'])
            ->withOptions([
                'trace'            => app()->isLocal(),
                'exceptions'       => true,
                'connection_timeout' => $config['timeout'] ?? 10,
                'cache_wsdl'       => app()->isProduction()
                                        ? WSDL_CACHE_DISK
                                        : WSDL_CACHE_NONE,
            ])
            ->withWsSecurityFilter(
                WsSecurityFilter::create()
                    ->withUsernameToken($config['user'], $config['pass'])
                    ->withPasswordDigest($config['digest'])
            )
            ->build();
    }

    public function __call(string $method, array $args)
    {
        return $this->client->{$method}(...$args);
    }
}
// app/Providers/AppServiceProvider.php
$this->app->singleton(PartnerSoapClient::class, fn () =>
    new PartnerSoapClient(config('services.partner'))
);

Put credentials and WSDL URLs in config/services.php, not in code. Treat it like any other external service credential.

Push the call onto a queue job for anything user-facing. SOAP partners are routinely slow (2–30s), and a stuck synchronous call blocks a PHP worker. Combine with tries, backoff, and a failed() handler that logs __getLastRequest() / __getLastResponse().

Attachments (MTOM / SwA) pattern. For file-upload operations, build the client with the MTOM or SwA filter, hand it a file path or SplFileObject, and confirm the partner actually negotiates application/xop+xml — many do not, in which case fall back to base64 in the SOAP body.

Caching layer. The package ships cache decorators for WSDL/metadata. Use disk cache in production (WSDL files change rarely). If you have many partners/WSDLs, key the cache by WSDL URL — most shared hosting setups will silently share a single cache directory otherwise.

Testing. Do not hit live partners in tests. Two practical approaches:

  1. Point wsdl at a local static .wsdl fixture (committed under tests/fixtures/) and mock the HTTP transport, or
  2. Extract an interface around PartnerSoapClient, bind a fake that returns canned response objects in tests.

If you must assert the wire format, enable trace => true in a test-only config and inspect __getLastRequest().

Gotchas and Tips

  • No Laravel integration means no php artisan vendor:publish, no config merging. Everything is manual. Budget time for that.
  • Autoload namespace collisions. The package uses BeSimple\SoapClient\*. If you also have besimple/soap-client or besimple/soap-common installed transitively, you can get class-not-found errors or silent class shadowing. Run composer why besimple/soap-common and pin/alias carefully.
  • Legacy Zend → Laminas dependency. Attachment support historically pulled in zendframework/zend-mime (or a laminas/laminas-mime fork). On modern PHP versions this is often the thing that blocks an upgrade. Check composer.json of the exact tag you install before committing.
  • WsSecurityFilter password digest is fiddly. The server may expect PasswordText vs PasswordDigest, require a Timestamp with a specific expires, or reject a nonce format. Symptoms usually surface as an HTTP 500 with a SOAP fault like Security token could not be authenticated. Toggle withPasswordDigest() and inspect __getLastRequest() in a scratch script.
  • Clock skew breaks WSSE. If the partner is in a different timezone or your host has drifted, Timestamp validation fails. Ensure NTP on the app server; consider widening expires.
  • trace => true in production is expensive. It buffers full request/response payloads in memory. Keep it on only in local/staging, or gate it behind a config toggle.
  • cache_wsdl => WSDL_CACHE_NONE in production is a footgun. Every call re-fetches the WSDL, adding latency and risking a hard failure if the partner's WSDL endpoint is briefly down. Use WSDL_CACHE_DISK, and document the cache path (default sys_get_temp_dir()) across multiple app servers.
  • SSL peer verification. Do not disable verify_peer to "fix" a failing call — install the partner's CA cert instead. Disabling it silently weakens every subsequent call from that client.
  • Error handling is two-layered. You get SoapFault for SOAP-level errors, but transport errors (connection refused, timeout) may surface as generic exceptions from the HTTP layer. Wrap calls in try/catch covering both, log the full fault, and translate to a domain exception before it reaches your controller.
  • Stateful client. Cookies and __getLastRequest live on the client instance. If you bind it as a singleton (as above), be conscious that cookies persist across requests in the same worker. For long-running queue workers, consider rebuilding periodically or using a fresh instance per job.
  • Extension points are in the filter/plugin chain (WSSE, MTOM, SwA, cache). Custom HTTP behaviour goes through the underlying HttpPlug stack, not through middleware — there is no Laravel-style middleware concept here.
  • Given zero dependents and a very low adoption score, treat this fork as lightly road-tested. Pin the exact version in composer.json, add an integration test against the real partner in staging, and keep a note of the upstream besimple/soap-client so you can swap forks if maintenance stalls.
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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib