comsave/salesforce-outbound-message-bundle

This bundle allows you to easily process outbound messages sent by Salesforce.

0.8.0 2020-01-27 15:41 UTC

README

Create, update, remove objects in Symfony sent through Salesforce outbound messages.

Requirements

This bundle assumes you're using:

  1. MongoDB database (and specifically doctrine/mongodb-odm).
  2. comsave/salesforce-mapper-bundle for Salesforce object mapping to your MongoDB Document classes.

Bundle features

  • Object create
  • Object update
  • Object delete. To enable this complete additional setup steps.
  • Object custom handling beforeFlush
  • Object custom handling afterFlush

Installation

  • composer require comsave/salesforce-outbound-message-bundle
  • Register the bundle in your AppKernel.php by adding new Comsave\SalesforceOutboundMessageBundle\ComsaveSalesforceOutboundMessageBundle()
  • To handle the Salesforce's incoming outbound messages create a route (for example /sync) and a method to a controller:
<?php

use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Comsave\SalesforceOutboundMessageBundle\Services\RequestHandler\OutboundMessageRequestHandler;

class OutboundMessageController extends Controller
{
    public function syncAction(Request $request, OutboundMessageRequestHandler $requestHandler)
    {
        try {
            $outboundMessageXml = $request->getContent();
            return $requestHandler->handle($outboundMessageXml);
        }
        catch (\Throwable $e) {
            throw new \SoapFault("Server", $e->getMessage());
        }
    }
}
  • add the bundle configuration in your app/config/config.yml
comsave_salesforce_outbound_message:
    # WSDL_CACHE_NONE, WSDL_CACHE_DISK, WSDL_CACHE_MEMORY or WSDL_CACHE_BOTH
    wsdl_cache: 'WSDL_CACHE_DISK'                     
    # An absolute path to Salesforce object WSDL files
    wsdl_directory: '/absolute/path/' 
    document_paths:
        # Map a document using its Salesforce name and your local class 
        CustomObject__c:              
            path: 'YourNamespace\Documents\CustomObject'
  • Add DocumentInterface to the document class you'd like to be tracked by the OutboundMessageBundle.
<?php

use Comsave\SalesforceOutboundMessageBundle\Interfaces\DocumentInterface;
use LogicItLab\Salesforce\MapperBundle\Model\Account as BaseAccount;

class Account extends BaseAccount implements DocumentInterface
{
}
  • Create an EventSubscriber for an object you'd like to sync. It would look something like this for the Account object:
<?php

namespace YourNamespace\EventSubscriber;

use Comsave\SalesforceOutboundMessageBundle\Event\OutboundMessageBeforeFlushEvent;
use Comsave\SalesforceOutboundMessageBundle\Event\OutboundMessageAfterFlushEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Comsave\SalesforceOutboundMessageBundle\Interfaces\DocumentInterface; 
use Comsave\Webservice\Core\UserBundle\Document\Account;

class AccountSoapRequestSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            OutboundMessageBeforeFlushEvent::NAME => [
                ['onBeforeFlush'],
            ],
            OutboundMessageAfterFlushEvent::NAME => [
                ['onAfterFlush'],
            ],
        ];
    }

    public function supports(DocumentInterface $document): bool
    {
        $documentClass = get_class($document);

        return Account::class == $documentClass || $document instanceof Account;
    }

    public function onBeforeFlush(OutboundMessageBeforeFlushEvent $event)
    {
        /** @var Account $account */
        $newAccount = $event->getNewDocument();

        /**
         * Make sure to do call $this->supports() before you start processing the object
         * You only want to process the correct object in this EventSubscriber (which is Account in this case)
         */
        if (!$this->supports($account)) return; 
    
        $existingAccount = $event->getExistingDocument();
        
        /**
         * You can do any modifications you want to the object before it get's saved (flushed) to the database.
         * - - -
         * $event->getExistingDocument() provides you access to the existing object (if it exists) 
         * $event->getNewDocument() provides you access to the new object delivered by the outbound message
         */
    }

    public function onAfterFlush(OutboundMessageAfterFlushEvent $event)
    {
        /** @var Account $account */
        $account = $event->getDocument();

        if (!$this->supports($account)) return; 

        /**
         * You can process the object further if necessary after it has been saved (flushed) to the database.
         */
    }
}
  • Add your newly created route to the Salesforce outbound message for the object you want to sync (Account in our example).
  • That's it! Trigger an outbound message to be sent out and see everything happen automagically. 😎 👍

License

This project is licensed under the MIT License.