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 Common Laravel Package

burti/besimple-soap-common

A shared foundation for BeSimple SOAP client and server packages, supplying common classes, WSDL utilities, and type definitions. Simplifies building and consuming SOAP services in PHP and Laravel applications by keeping reusable SOAP components consistent across integrations.

View on GitHub
Deep Wiki
Context7

Getting Started

This is not a Laravel package. It is the shared low‑level library from the old Symfony2-era BeSimpleSoap suite (SOAP client/server classes, MIME/MTOM attachment handling, WSDL cache, type converters). There is no service provider, no config file, no facade, and no auto-discovery. You consume it as a plain Composer dependency and wire it yourself.

Prerequisites and install

php -m | grep -i soap        # ext-soap is mandatory
composer require burti/besimple-soap-common
composer dump-autoload -o

Because the package is untagged/old in most forks, you may need an explicit constraint (^0.3 or a dev-* branch) and possibly "minimum-stability": "dev". Run the install on the exact PHP version you deploy to before committing — old PSR-0 code frequently trips PHP 8.x deprecations.

Where to look first — after install, read the source rather than the README:

  • vendor/burti/besimple-soap-common/src/BeSimple/SoapCommon/SoapClient.php — drop-in \SoapClient subclass with extra options
  • .../SoapServer.php — \SoapServer subclass
  • .../Mime/Part.php, .../Mime/MultiPart.php, .../Mime/Parser.php — MTOM/XOP attachments
  • .../Helper.php — option key constants
  • .../Cache.php — WSDL cache directory handling
  • .../Converter/ — custom XSD type converters

First use case — centralize SOAP configuration and call a third-party service with attachments or a non-standard encoding. Bind a configured client in a service provider:

// config/soap.php
return [
    'billing' => [
        'wsdl' => env('BILLING_WSDL'),
        'options' => [
            'soap_version'       => SOAP_1_2,
            'cache_wsdl'         => WSDL_CACHE_NONE,
            'connection_timeout' => 10,
            'exceptions'         => true,
            'trace'              => env('SOAP_TRACE', false),
        ],
    ],
];
// app/Providers/SoapServiceProvider.php
public function register(): void
{
    $this->app->singleton('soap.billing', function ($app) {
        $cfg = $app['config']['soap.billing'];
        return new \BeSimple\SoapCommon\SoapClient($cfg['wsdl'], $cfg['options']);
    });
}

Then app('soap.billing')->__soapCall('GetInvoice', [$args]);. Note this is the Common package only — WS-Security, WS-Addressing, and WSDL generation live in sibling BeSimple packages that may not be installable on modern PHP.

Implementation Patterns

Wrap the client behind your own interface. Never type-hint the BeSimple class in application code — you want to be able to swap it for phpro/soap-client, laminas-soap, or raw \SoapClient later.

interface BillingGateway { public function invoice(string $id): Invoice; }

class BeSimpleBillingGateway implements BillingGateway
{
    public function __construct(private \BeSimple\SoapCommon\SoapClient $client) {}

    public function invoice(string $id): Invoice
    {
        try {
            $res = $this->client->__soapCall('GetInvoice', [['id' => $id]]);
        } catch (\SoapFault $e) {
            throw new BillingUnavailable($e->getMessage(), previous: $e);
        }
        return Invoice::fromSoap($res);
    }
}

Typed responses via classmap. BeSimple's client forwards standard options, so generated value objects work exactly as with native SOAP:

'classmap' => [
    'Invoice'     => \App\Soap\Types\Invoice::class,
    'InvoiceLine' => \App\Soap\Types\InvoiceLine::class,
],

MTOM attachments. Build a Mime\Part per binary, attach with MultiPart, and match Content-ID to the cid: reference inside your XML body. On responses, feed the raw response body to Mime\Parser and hydrate Part objects by Content-ID. Verify the exact constructor argument order against Part.php — it moves between forks.

Server endpoint. SoapServer writes to output; buffer it in a controller:

public function __invoke(Request $request, \BeSimple\SoapCommon\SoapServer $server)
{
    $server->setObject(new OrdersHandler());
    ob_start();
    try {
        $server->handle($request->getContent());
    } catch (\SoapFault $e) {
        // SoapServer already emitted a fault envelope
    }
    return response(ob_get_clean(), 200, ['Content-Type' => 'text/xml; charset=utf-8']);
}

Bind SoapServer per service with the correct WSDL and uri options, and disable Laravel's CSRF/VerifyCsrfToken for that route.

Logging / tracing. The idiomatic extension point is subclassing and overriding __doRequest (or __doResponse), not middleware:

class LoggingSoapClient extends \BeSimple\SoapCommon\SoapClient
{
    public function __construct($wsdl, array $options, private LoggerInterface $log)
    { parent::__construct($wsdl, $options); }

    public function __doRequest($request, $location, $action, $version, $oneWay = false): ?string
    {
        $this->log->debug('soap.req', ['location' => $location, 'xml' => $request]);
        $r = parent::__doRequest($request, $location, $action, $version, $oneWay);
        $this->log->debug('soap.res', ['xml' => (string) $r]);
        return $r;
    }
}

Register it in the container instead of the base class. Same hook is where you'd insert XML-DSig signing if you add robrichards/wse-php.

Testing. Because the transport is ext-soap streams, you can't Http::fake() it. Test your BillingGateway consumers against a fake implementation of your interface, and keep one integration test that hits a recorded WSDL/fixture (e.g. via soap.wsdl_cache_enabled=0 and a local .wsdl).

Gotchas and Tips

  • Abandoned-signal risk. 0 stars, 0 dependents, and the upstream project is archived. Treat this as vendored code: pin the exact commit in composer.lock, mirror the fork in your VCS, and keep the adapter interface so replacing it is a one-file change.
  • PSR-0 autoloading. The classes are BeSimple\SoapCommon\...; Composer handles it, but opcache/preloading setups sometimes miss PSR-0 paths. composer dump-autoload -o after every deploy.
  • PHP 8 compatibility. Expect dynamic-property deprecations, __doRequest signature mismatches, and each()/create_function() remnants in older tags. Pin to the newest fork commit and silence deprecations only after reading each one. PHP's built-in \SoapClient::__doRequest now requires ?string return and bool $oneWay — match it exactly.
  • WSDL cache is a filesystem concern. Cache:: writes under a configured directory; point it at storage/framework/cache/soap and ensure it is writable by the PHP-FPM user. On multi-node deployments use a shared volume or WSDL_CACHE_NONE, or every request re-fetches the WSDL over the network.
  • trace => true in production is expensive and PII-leaky. Gate it by env and route the log channel to a redacted/rotated sink.
  • SSL and proxies. Native SOAP ignores Laravel HTTP client config. Pass stream_context with ssl cafile/verify_peer, and set HTTP_PROXY env for outbound calls; failures surface as generic SoapFault: Could not connect to host.
  • Attachment pitfalls: check Content-Transfer-Encoding (base64 vs binary) on both directions; decode base64 parts before persisting; watch memory on large MTOMs — the whole envelope is in memory, so cap memory_limit accordingly and stream to a temp file if needed.
  • Fault handling. exceptions => true gives SoapFault; false returns a SoapFault object that is easy to accidentally treat as a result. Wrap __soapCall in your gateway and normalize.
  • Don't conflate packages. WS-Security, WS-Addressing, MTOM server-side dispatch, and WSDL generation are separate BeSimple sub-packages that historically required Symfony2 DI. If you need them, evaluate phpro/soap-client + wse-php instead of stitching the old suite together.
  • Extension points worth using: Mime\Part factories for attachment serialization, Converter\AbstractConverter subclasses for xsd:dateTime/base64Binary, Helper:: option constants instead of magic strings, and __doRequest overrides for logging/signing/metrics. Everything else should stay in Laravel: config, container, jobs, retries, and an adapter that hides the library.
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.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk