From f16bf66c1e0c9f8891e2bfb5f643a70c7d3539ba Mon Sep 17 00:00:00 2001
From: acrosman <acrosman@65233.no-reply.drupal.org>
Date: Tue, 2 Jul 2019 14:59:53 -0400
Subject: [PATCH] Issue #3038688 by AaronBauman, acrosman: Add "pull allowed",
 analogous to "push allowed"

---
 .../SalesforceExampleSubscriber.php           | 32 +++++++++++++++++++
 .../src/Event/SalesforcePullEvent.php         | 26 +++++++++++++++
 .../src/Plugin/QueueWorker/PullBase.php       | 12 +++++--
 .../tests/src/Unit/PullBaseTest.php           |  3 +-
 4 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/modules/salesforce_example/src/EventSubscriber/SalesforceExampleSubscriber.php b/modules/salesforce_example/src/EventSubscriber/SalesforceExampleSubscriber.php
index 3b34f3c8..e6bc6a4c 100644
--- a/modules/salesforce_example/src/EventSubscriber/SalesforceExampleSubscriber.php
+++ b/modules/salesforce_example/src/EventSubscriber/SalesforceExampleSubscriber.php
@@ -172,6 +172,37 @@ class SalesforceExampleSubscriber implements EventSubscriberInterface {
     }
   }
 
+  /**
+   * PULL_PREPULL event subscriber example.
+   */
+  public function pullPrepull(SalesforcePullEvent $event) {
+    // For the "contact" mapping, if the SF record is marked "Inactive", do not
+    // pull the record and block the user account.
+    $mapping = $event->getMapping();
+    switch ($mapping->id()) {
+      case 'contact':
+        $sf_data = $event->getMappedObject()->getSalesforceRecord();
+        /** @var \Drupal\user\Entity\User $account */
+        $account = $event->getEntity();
+        try {
+          if (!$sf_data->field('Inactive__c')) {
+            // If the SF record is not marked "Inactive", proceed as normal.
+            return;
+          }
+        }
+        catch (\Exception $e) {
+          // Fall through if "Inactive" field was not found.
+        }
+        // If we got here, SF record is marked inactive. Don't pull it.
+        $event->disallowPull();
+        if (!$account->isNew()) {
+          // If this is an update to an existing account, block the account.
+          // If this is a new account, it won't be created.
+          $account->block()->save();
+        }
+    }
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -183,6 +214,7 @@ class SalesforceExampleSubscriber implements EventSubscriberInterface {
       SalesforceEvents::PUSH_FAIL => 'pushFail',
       SalesforceEvents::PULL_PRESAVE => 'pullPresave',
       SalesforceEvents::PULL_QUERY => 'pullQueryAlter',
+      SalesforceEvents::PULL_PREPULL => 'pullPrepull',
     ];
     return $events;
   }
diff --git a/modules/salesforce_mapping/src/Event/SalesforcePullEvent.php b/modules/salesforce_mapping/src/Event/SalesforcePullEvent.php
index 7bd7822a..bb9c78cf 100644
--- a/modules/salesforce_mapping/src/Event/SalesforcePullEvent.php
+++ b/modules/salesforce_mapping/src/Event/SalesforcePullEvent.php
@@ -43,6 +43,13 @@ class SalesforcePullEvent extends SalesforceBaseEvent {
    */
   protected $op;
 
+  /**
+   * TRUE or FALSE to indicate if pull is allowed for this event.
+   *
+   * @var bool
+   */
+  protected $pullAllowed;
+
   /**
    * SalesforcePullEvent constructor.
    *
@@ -56,6 +63,7 @@ class SalesforcePullEvent extends SalesforceBaseEvent {
     $this->entity = $mappedObject->getMappedEntity();
     $this->mapping = $mappedObject->getMapping();
     $this->op = $op;
+    $this->pullAllowed = TRUE;
   }
 
   /**
@@ -103,4 +111,22 @@ class SalesforcePullEvent extends SalesforceBaseEvent {
     return $this->op;
   }
 
+  /**
+   * Disallow and stop pull for the current queue item.
+   */
+  public function disallowPull() {
+    $this->pullAllowed = FALSE;
+    return $this;
+  }
+
+  /**
+   * Will return FALSE if any subscribers have called disallowPull().
+   *
+   * @return bool
+   *   TRUE if pull is allowed, false otherwise.
+   */
+  public function isPullAllowed() {
+    return $this->pullAllowed;
+  }
+
 }
diff --git a/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php b/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
index ec0dfe00..e7d7955f 100644
--- a/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
+++ b/modules/salesforce_pull/src/Plugin/QueueWorker/PullBase.php
@@ -204,10 +204,14 @@ abstract class PullBase extends QueueWorkerBase implements ContainerFactoryPlugi
         }
       }
 
-      $this->eventDispatcher->dispatch(
+      $event = $this->eventDispatcher->dispatch(
         SalesforceEvents::PULL_PREPULL,
         new SalesforcePullEvent($mapped_object, MappingConstants::SALESFORCE_MAPPING_SYNC_SF_UPDATE)
       );
+      if (!$event->isPullAllowed()) {
+        $this->eventDispatcher->dispatch(SalesforceEvents::NOTICE, new SalesforceNoticeEvent(NULL, 'Pull was not allowed for %label with %sfid', ['%label' => $entity->label(), '%sfid' => (string) $sf_object->id()]));
+        return FALSE;
+      }
 
       if ($sf_record_updated > $entity_updated || $mapped_object->force_pull || $force_pull) {
         // Set fields values on the Drupal entity.
@@ -272,10 +276,14 @@ abstract class PullBase extends QueueWorkerBase implements ContainerFactoryPlugi
         ->setDrupalEntity($entity)
         ->setSalesforceRecord($sf_object);
 
-      $this->eventDispatcher->dispatch(
+      $event = $this->eventDispatcher->dispatch(
         SalesforceEvents::PULL_PREPULL,
         new SalesforcePullEvent($mapped_object, MappingConstants::SALESFORCE_MAPPING_SYNC_SF_CREATE)
       );
+      if (!$event->isPullAllowed()) {
+        $this->eventDispatcher->dispatch(SalesforceEvents::NOTICE, new SalesforceNoticeEvent(NULL, 'Pull was not allowed for %label with %sfid', ['%label' => $entity->label(), '%sfid' => (string) $sf_object->id()]));
+        return FALSE;
+      }
 
       $mapped_object->pull();
 
diff --git a/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php b/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
index a4410e42..da4f47b3 100644
--- a/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
+++ b/modules/salesforce_pull/tests/src/Unit/PullBaseTest.php
@@ -8,6 +8,7 @@ use Drupal\Core\Entity\EntityStorageBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
+use Drupal\salesforce_mapping\Event\SalesforcePullEvent;
 use Drupal\Tests\UnitTestCase;
 use Drupal\salesforce\Rest\RestClientInterface;
 use Drupal\salesforce\SFID;
@@ -198,7 +199,7 @@ class PullBaseTest extends UnitTestCase {
     $this->ed
       ->expects($this->any())
       ->method('dispatch')
-      ->willReturn(NULL);
+      ->willReturn(new SalesforcePullEvent($this->mappedObject, MappingConstants::SALESFORCE_MAPPING_SYNC_SF_UPDATE));
 
     $container = new ContainerBuilder();
     $container->set('salesforce.client', $this->sfapi);
-- 
GitLab