Skip to content

Latest commit

 

History

55 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SOAP SWA / MTOM Middleware

This package provides the tools you need in order to add SWA or MTOM Attachments to your PSR-18 based SOAP Transport.

Want to help out? 💚

Want more information about the future of this project? Check out this list of the next big projects we'll be working on.

Installation

composer require php-soap/psr18-attachments-middleware

This package includes the php-soap/psr18-transport package and is meant to be used together with it.

Usage

Attachments middleware

This middleware is used to add attachments to your SOAP request:

use Http\Client\Common\PluginClient;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18AttachmentsMiddleware\Middleware\AttachmentsMiddleware;
use Soap\Psr18AttachmentsMiddleware\Multipart\AttachmentType;
use Soap\Psr18AttachmentsMiddleware\Storage\AttachmentStorage;

// You should store this attachment storage in a central place in your application e.g. inside a service container.
// It is used to store the attachments that are being sent and received.
$attachmentsStorage = new AttachmentStorage();

$transport = Psr18Transport::createForClient(
    new PluginClient($yourPsr18Client, [
        new AttachmentsMiddleware(
            $attachmentsStorage,
            AttachmentType::Swa // or AttachmentType::Mtom
        ),
    ])
);

This middleware will convert your regular SOAP request into a multipart SOAP request that contains the request attachments. A response that contains attachments will be converted back into a regular SOAP response whilst storing a copy of the attachments.

Adding attachments

Adding attachments to your request is done by using the AttachmentsStorage before sending your request to the SOAP server:

use Http\Client\Common\PluginClient;
use Phpro\ResourceStream\Factory\FileStream;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18AttachmentsMiddleware\Attachment\Attachment;
use Soap\Psr18AttachmentsMiddleware\Storage\AttachmentStorage;

// You should store this attachment storage in a central place in your application.
// It is used to store the attachments that are being sent and received.
$attachmentsStorage = new AttachmentStorage();

$attachmentsStorage->requestAttachments()->add(
    Attachment::create(
        name: 'file',
        filename: 'your.pdf',
        content: FileStream::create('path/to/your.pdf', FileStream::READ_MODE),
    )
);
$yourSoapClient->request('Foo', $soapPayload);

Custom attachment headers

An attachment travels with a Content-ID, a Content-Type and a Content-Disposition, built from what you passed. When you need a header beyond those three, pass it along:

use Psl\MIME\Headers;
use Phpro\ResourceStream\Factory\FileStream;
use Soap\Psr18AttachmentsMiddleware\Attachment\Attachment;

$attachmentsStorage->requestAttachments()->add(
    Attachment::create(
        name: 'invoice',
        filename: 'invoice.xml',
        content: FileStream::create('path/to/invoice.xml', FileStream::READ_MODE),
        extraHeaders: Headers::fromPairs([
            ['Content-Type', 'application/xml; charset=UTF-8'],
            ['Content-Location', 'http://example.com/invoice.xml'],
        ]),
    )
);

They travel with the part exactly as given. A header saying something the attachment already says, like the Content-Type above, stands in for the built one rather than being added beside it, so the part never carries the same header twice.

Content-ID is the one exception: an extra one is ignored, and the part always travels under the identity the attachment was built with. That is Attachment::create()'s generated id, or the uri you passed to Attachment::cid(). It has to be, because that is also the id you look the attachment up by when the response comes back, and a part travelling under a different one could not be found again.

If you supply a Content-Type this way and no $mimeType, that header is where the media type is read from, so $attachment->mimeType and what travels always agree.

Attachments you receive keep every header they arrived with, so you can read whatever the server sent:

foreach ($attachmentsStorage->responseAttachments() as $attachment) {
    $attachment->headers()->get('Content-Location');   // 'http://example.com/invoice.xml'
    $attachment->mimeType;                             // 'application/xml', without the charset
}

Receiving attachments

Receiving attachments is done by using the AttachmentsStorage after receiving your response from the SOAP server:

use Http\Client\Common\PluginClient;
use Phpro\ResourceStream\Factory\FileStream;
use Soap\Psr18Transport\Psr18Transport;
use Soap\Psr18AttachmentsMiddleware\Attachment\Attachment;
use Soap\Psr18AttachmentsMiddleware\Storage\AttachmentStorage;

// You should store this attachment storage in a central place in your application.
// It is used to store the attachments that are being sent and received.
$attachmentsStorage = new AttachmentStorage();

$soapResponse = $yourSoapClient->request('Foo', $soapPayload);
$attachments = $attachmentsStorage->responseAttachments()

foreach ($attachments as $attachment) {
    $attachment->content->copyTo(
        FileStream::create('path/to/your/'.$attachment->filename, FileStream::WRITE_MODE)
    );
}

Encoders

XOP Includes

If you are using MTOM attachments in combination with XOP you can use the XopIncludeEncoder to work directly with attachments from within your SOAP objects. This requires you to use the php-soap/encoder pacakge:

composer require php-soap/encoder
use Soap\Encoding\EncoderRegistry;
use Soap\Psr18AttachmentsMiddleware\Encoding\Xop\XopIncludeEncoder

// You should store this attachment storage in a central place in your application.
// It is used to store the attachments that are being sent and received.
$attachmentsStorage = new AttachmentStorage();

EncoderRegistry::default()
    ->addComplexTypeConverter(XopIncludeEncoder::XMLNS_XOP, 'Include', new XopIncludeEncoder($attachmentsStorage));

This will allow you to use attachments directly from within your SOAP request and responses without the need of adding them to the AttachmentStorage manually:

use Phpro\ResourceStream\Factory\FileStream;
use Soap\Psr18AttachmentsMiddleware\Attachment\Attachment;

// Your request can now contain Attachments directly:
// These attachments will be automatically added to the AttachmentStorageInterface and a <xop:Include> element will be added to your request instead.
$yourSoapPayload = (object) [
    // A special cid named constructor is added to make sure your attachment Content-Id is cid spec-compliant and therefore can be used with XOP.
    'file' => Attachment::cid(
        uri: 'foo@domain.com',
        filename: 'your.pdf',
        content: FileStream::create('path/to/your.pdf', FileStream::READ_MODE)
    )
];

// If your resonse contains an <xop:Include> element, the AttachmentStorageInterface will automatically fetch the attachment and replace the <xop:Include> element with the actual attachment content:
$response = $yourSoapClient->request('Foo', $yourSoapPayload);
$response->foo->file->copyTo(FileStream::create('path/to/your.pdf', FileStream::WRITE_MODE));

About

Add SWA / MTOM attachments to your SOAP client

Resources

Code of conduct

Contributing

Stars

2 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages