You are here

class DeleteHandler in Salesforce Suite 5.0.x

Same name and namespace in other branches
  1. 8.4 modules/salesforce_pull/src/DeleteHandler.php \Drupal\salesforce_pull\DeleteHandler
  2. 8.3 modules/salesforce_pull/src/DeleteHandler.php \Drupal\salesforce_pull\DeleteHandler

Handles pull cron deletion of Drupal entities based onSF mapping settings.

Hierarchy

Expanded class hierarchy of DeleteHandler

See also

\Drupal\salesforce_pull\DeleteHandler

2 files declare their use of DeleteHandler
DeleteHandlerTest.php in modules/salesforce_pull/tests/src/Unit/DeleteHandlerTest.php
PullController.php in modules/salesforce_pull/src/Controller/PullController.php
1 string reference to 'DeleteHandler'
salesforce_pull.services.yml in modules/salesforce_pull/salesforce_pull.services.yml
modules/salesforce_pull/salesforce_pull.services.yml
1 service uses DeleteHandler
salesforce_pull.delete_handler in modules/salesforce_pull/salesforce_pull.services.yml
Drupal\salesforce_pull\DeleteHandler

File

modules/salesforce_pull/src/DeleteHandler.php, line 22

Namespace

Drupal\salesforce_pull
View source
class DeleteHandler {

  /**
   * Rest client service.
   *
   * @var \Drupal\salesforce\Rest\RestClientInterface
   */
  protected $sfapi;

  /**
   * Salesforce mapping storage service.
   *
   * @var \Drupal\salesforce_mapping\SalesforceMappingStorage
   */
  protected $mappingStorage;

  /**
   * Mapped Object storage service.
   *
   * @var \Drupal\salesforce_mapping\MappedObjectStorage
   */
  protected $mappedObjectStorage;

  /**
   * Entity tpye manager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $etm;

  /**
   * State service.
   *
   * @var \Drupal\Core\State\StateInterface
   */
  protected $state;

  /**
   * Request service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * Event dispatcher service.
   *
   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
   */
  protected $eventDispatcher;

  /**
   * Constructor.
   *
   * @param \Drupal\salesforce\Rest\RestClientInterface $sfapi
   *   RestClient object.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   Entity Manager service.
   * @param \Drupal\Core\State\StateInterface $state
   *   State service.
   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
   *   Event dispatcher service.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  public function __construct(RestClientInterface $sfapi, EntityTypeManagerInterface $entity_type_manager, StateInterface $state, EventDispatcherInterface $event_dispatcher) {
    $this->sfapi = $sfapi;
    $this->etm = $entity_type_manager;
    $this->mappingStorage = $this->etm
      ->getStorage('salesforce_mapping');
    $this->mappedObjectStorage = $this->etm
      ->getStorage('salesforce_mapped_object');
    $this->state = $state;
    $this->eventDispatcher = $event_dispatcher;
  }

  /**
   * Process deleted records from salesforce.
   *
   * @return bool
   *   TRUE.
   */
  public function processDeletedRecords() {

    // @TODO Add back in SOAP, and use autoloading techniques
    $pull_info = $this->state
      ->get('salesforce.mapping_pull_info', []);
    foreach ($this->mappingStorage
      ->loadMultiple() as $mapping) {
      if (!$mapping
        ->checkTriggers([
        MappingConstants::SALESFORCE_MAPPING_SYNC_SF_DELETE,
      ])) {
        continue;
      }

      // @TODO add some accommodation to handle deleted records per-mapping.
      $last_delete_sync = !empty($pull_info[$mapping
        ->id()]['last_delete_timestamp']) ? $pull_info[$mapping
        ->id()]['last_delete_timestamp'] : strtotime('-29 days');
      $now = time();

      // getDeleted() constraint: startDate must be at least one minute
      // greater than endDate.
      $now = $now > $last_delete_sync + 60 ? $now : $now + 60;

      // getDeleted() constraint: startDate cannot be more than 30 days ago.
      if ($last_delete_sync < strtotime('-29 days')) {
        $last_delete_sync = strtotime('-29 days');
      }
      $last_delete_sync_sf = gmdate('Y-m-d\\TH:i:s\\Z', $last_delete_sync);
      $now_sf = gmdate('Y-m-d\\TH:i:s\\Z', $now);
      $deleted = $this->sfapi
        ->getDeleted($mapping
        ->getSalesforceObjectType(), $last_delete_sync_sf, $now_sf);
      $this
        ->handleDeletedRecords($deleted, $mapping
        ->getSalesforceObjectType());
      $pull_info[$mapping
        ->id()]['last_delete_timestamp'] = $now;
      $this->state
        ->set('salesforce.mapping_pull_info', $pull_info);
    }
    return TRUE;
  }

  /**
   * Delete records.
   *
   * @param array $deleted
   *   Array of deleted records.
   * @param string $type
   *   Salesforce object type.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function handleDeletedRecords(array $deleted, $type) {
    if (empty($deleted['deletedRecords'])) {
      return;
    }
    $sf_mappings = $this->mappingStorage
      ->loadByProperties([
      'salesforce_object_type' => $type,
    ]);
    if (empty($sf_mappings)) {
      return;
    }
    foreach ($deleted['deletedRecords'] as $record) {
      $this
        ->handleDeletedRecord($record, $type);
    }
  }

  /**
   * Delete single mapped object.
   *
   * @param array $record
   *   Record array.
   * @param string $type
   *   Salesforce object type.
   *
   * @throws \Drupal\Core\Entity\EntityStorageException
   */
  protected function handleDeletedRecord(array $record, $type) {
    $mapped_objects = $this->mappedObjectStorage
      ->loadBySfid(new SFID($record['id']));
    if (empty($mapped_objects)) {
      return;
    }
    foreach ($mapped_objects as $mapped_object) {
      $entity = $mapped_object
        ->getMappedEntity();
      if (!$entity) {
        $message = 'No entity found for ID %id associated with Salesforce Object ID: %sfid ';
        $args = [
          '%id' => $mapped_object->entity_id->value,
          '%sfid' => $record['id'],
        ];
        $this->eventDispatcher
          ->dispatch(new SalesforceNoticeEvent(NULL, $message, $args), SalesforceEvents::NOTICE);
        $mapped_object
          ->delete();
        return;
      }

      // The mapping entity is an Entity reference field on mapped object, so we
      // need to get the id value this way.
      $sf_mapping = $mapped_object
        ->getMapping();
      if (!$sf_mapping) {
        $message = 'No mapping exists for mapped object %id with Salesforce Object ID: %sfid';
        $args = [
          '%id' => $mapped_object
            ->id(),
          '%sfid' => $record['id'],
        ];
        $this->eventDispatcher
          ->dispatch(new SalesforceWarningEvent(NULL, $message, $args), SalesforceEvents::WARNING);

        // @TODO should we delete a mapped object whose parent mapping no longer exists? Feels like someone else's job.
        // $mapped_object->delete();
        return;
      }
      if (!$sf_mapping
        ->checkTriggers([
        MappingConstants::SALESFORCE_MAPPING_SYNC_SF_DELETE,
      ])) {
        return;
      }

      // Before attempting the final delete, give other modules a chance to disallow it.
      $deleteAllowedEvent = new SalesforceDeleteAllowedEvent($mapped_object);
      $this->eventDispatcher
        ->dispatch($deleteAllowedEvent, SalesforceEvents::DELETE_ALLOWED);
      if ($deleteAllowedEvent
        ->isDeleteAllowed() === FALSE) {
        return;
      }
      try {

        // Flag this entity to avoid duplicate processing.
        $entity->salesforce_pull = TRUE;
        $entity
          ->delete();
        $message = 'Deleted entity %label with ID: %id associated with Salesforce Object ID: %sfid';
        $args = [
          '%label' => $entity
            ->label(),
          '%id' => $mapped_object->entity_id,
          '%sfid' => $record['id'],
        ];
        $this->eventDispatcher
          ->dispatch(new SalesforceNoticeEvent(NULL, $message, $args), SalesforceEvents::NOTICE);
      } catch (\Exception $e) {
        $this->eventDispatcher
          ->dispatch(new SalesforceErrorEvent($e), SalesforceEvents::ERROR);

        // If mapped entity couldn't be deleted, do not delete the mapped
        // object.
        return;
      }
      $mapped_object
        ->delete();
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DeleteHandler::$etm protected property Entity tpye manager service.
DeleteHandler::$eventDispatcher protected property Event dispatcher service.
DeleteHandler::$mappedObjectStorage protected property Mapped Object storage service.
DeleteHandler::$mappingStorage protected property Salesforce mapping storage service.
DeleteHandler::$sfapi protected property Rest client service.
DeleteHandler::$state protected property State service.
DeleteHandler::$time protected property Request service.
DeleteHandler::handleDeletedRecord protected function Delete single mapped object.
DeleteHandler::handleDeletedRecords protected function Delete records.
DeleteHandler::processDeletedRecords public function Process deleted records from salesforce.
DeleteHandler::__construct public function Constructor.