xero_sync-8.x-1.x-dev/src/XeroSyncEntityHandler.php
src/XeroSyncEntityHandler.php
<?php
namespace Drupal\xero_sync;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\TypedData\TypedDataManagerInterface;
use Drupal\xero_sync\Event\XeroSyncAppropriateEvent;
use Drupal\xero_sync\Event\XeroSyncEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Handles interaction with entities.
*
* It knows which field on an entity contains information identifying its
* Xero item.
*
* Typically used in response to entity CRUD hooks, to
* creates queue jobs for syncing entities with Xero items.
*/
class XeroSyncEntityHandler implements XeroSyncEntityHandlerInterface {
use XeroSyncUtilitiesTrait;
/**
* The default name of the field that holds the synced Xero item's id.
*/
const DEFAULT_FIELD_NAME = 'xero_sync';
/**
* The Xero Sync queue job manager.
*
* @var \Drupal\xero_sync\XeroSyncJobManagerInterface
*/
protected $jobManager;
/**
* The Xero Sync synchronizer.
*
* @var \Drupal\xero_sync\XeroSyncSynchronizerInterface
*/
protected $synchronizer;
/**
* The typed data manager.
*
* @var \Drupal\Core\TypedData\TypedDataManagerInterface
*/
protected $typedDataManager;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The event dispatcher.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* Constructs a new XeroSyncEntityHandler object.
*
* @param \Drupal\xero_sync\XeroSyncJobManagerInterface $job_manager
* The Xero Sync queue job manager.
* @param \Drupal\xero_sync\XeroSyncSynchronizerInterface $synchronizer
* The Xero Sync synchronizer.
* @param \Drupal\Core\TypedData\TypedDataManagerInterface $typed_data_manager
* The typed data manager.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
*/
public function __construct(XeroSyncJobManagerInterface $job_manager, XeroSyncSynchronizerInterface $synchronizer, TypedDataManagerInterface $typed_data_manager, EntityTypeManagerInterface $entity_type_manager, EventDispatcherInterface $event_dispatcher) {
$this->jobManager = $job_manager;
$this->synchronizer = $synchronizer;
$this->typedDataManager = $typed_data_manager;
$this->entityTypeManager = $entity_type_manager;
$this->eventDispatcher = $event_dispatcher;
}
/**
* {@inheritDoc}
*/
public function handleInsert(EntityInterface $entity) {
$this->syncIfAppropriate($entity);
}
/**
* {@inheritDoc}
*/
public function handleDelete(EntityInterface $entity) {
$this->unsyncIfAppropriate($entity, NULL, NULL, TRUE);
}
/**
* {@inheritDoc}
*/
public function handleUpdate(EntityInterface $entity) {
$field = $this->getSyncField($entity);
if ($field) {
$hasXeroId = !$field->isEmpty();
if (!isset($entity->original)) {
if ($hasXeroId) {
$this->handleXeroIdPresent($entity);
return;
}
}
else {
$originalField = $this->getSyncField($entity->original);
$hadXeroId = !$originalField->isEmpty();
if ($hadXeroId) {
if (!$hasXeroId) {
$this->handleXeroIdRemoved($entity);
return;
}
$changedId = $field->first()->guid !== $originalField->first()->guid;
$changedType = $field->first()->type !== $originalField->first()->type;
if ($changedId || $changedType) {
$this->handleXeroIdChanged($entity);
return;
}
$this->handleXeroIdUnchanged($entity);
return;
}
if ($hasXeroId) {
$this->handleXeroIdAdded($entity);
return;
}
}
}
$this->handleXeroIdAbsent($entity);
}
/**
* {@inheritDoc}
*/
public function getFieldName($entityType, $bundle = NULL) {
return self::DEFAULT_FIELD_NAME;
}
/**
* {@inheritDoc}
*/
public function getAppropriatenessFlags(EntityInterface $entity) {
$event = new XeroSyncAppropriateEvent($entity);
$eventId = XeroSyncEvents::SYNC_IS_APPROPRIATE . "." . $entity->getEntityTypeId();
$event = $this->eventDispatcher->dispatch($event, $eventId);
return $event->getFlags();
}
/**
* {@inheritDoc}
*/
public function syncIfAppropriate(EntityInterface $entity, $create = NULL, $update = NULL) {
// If create and update are not specified, use the event to determine if
// they are appropriate.
if (is_null($create) || is_null($update)) {
$flags = $this->getAppropriatenessFlags($entity);
$create = $create ?? $flags['create'];
$update = $update ?? $flags['update'];
}
if ($create || $update) {
$this->jobManager->queueEntitySync($entity, $create, $update);
}
}
/**
* {@inheritDoc}
*/
public function unsyncIfAppropriate(EntityInterface $entity, $itemType = NULL, $itemId = NULL, $serialize_entity = FALSE) {
// Even if the entity should not normally be synced, unsync it if a synced
// item is specified.
if (!is_null($itemId)) {
$shouldUnsync = TRUE;
}
else {
$flags = $this->getAppropriatenessFlags($entity);
$shouldUnsync = $flags['update'];
}
// Even if the entity should not normally be synced, we should still unsync
// it if it has previously been synced.
if (!$shouldUnsync) {
$field = $this->getSyncField($entity);
if ($field) {
$shouldUnsync = !$field->isEmpty();
}
}
if ($shouldUnsync) {
$this->jobManager->queueEntityUnsync($entity, $itemType, $itemId, $serialize_entity);
}
}
/**
* {@inheritDoc}
*/
public function syncMultipleIfAppropriate($entity_type, $entity_ids = NULL, $create = NULL, $update = NULL) {
$storage = $this->entityTypeManager->getStorage($entity_type);
if (is_null($entity_ids)) {
$query = $storage->getQuery()->accessCheck(FALSE);
$entity_ids = $query->execute();
}
foreach ($entity_ids as $entity_id) {
$entity = $storage->load($entity_id);
$this->syncIfAppropriate($entity, $create, $update);
}
}
/**
* {@inheritDoc}
*/
public function unsyncMultipleIfAppropriate($entity_type, $entity_ids = NULL, $serialize_entity = FALSE) {
$storage = $this->entityTypeManager->getStorage($entity_type);
if (is_null($entity_ids)) {
$query = $storage->getQuery()->accessCheck(FALSE);
$entity_ids = $query->execute();
}
foreach ($entity_ids as $entity_id) {
$entity = $storage->load($entity_id);
$this->unsyncIfAppropriate($entity, NULL, NULL, $serialize_entity);
}
}
/**
* Handle the case where the referenced synced item is different.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity.
*/
protected function handleXeroIdChanged(FieldableEntityInterface $entity) {
$itemType = $this->getSyncedItemType($entity->original);
$itemId = $this->getSyncedItemGuid($entity->original);
$this->unsyncIfAppropriate($entity, $itemType, $itemId);
$this->syncIfAppropriate($entity);
}
/**
* Handle the case where a synced item is still referenced.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity.
*/
protected function handleXeroIdUnchanged(FieldableEntityInterface $entity) {
$itemType = $this->getSyncedItemType($entity->original);
$itemId = $this->getSyncedItemGuid($entity->original);
$item = $this->buildXeroItemWithId($itemType, $itemId);
$item->synced = TRUE;
if ($this->synchronizer->isItemUpdateNeeded($entity, $item, $entity->original)) {
$this->syncIfAppropriate($entity);
}
}
/**
* Handle the case where the synced item is no longer referenced.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity.
*/
protected function handleXeroIdRemoved(FieldableEntityInterface $entity) {
$itemType = $this->getSyncedItemType($entity->original);
$itemId = $this->getSyncedItemGuid($entity->original);
$this->unsyncIfAppropriate($entity, $itemType, $itemId);
}
/**
* Handle the case where a synced item is newly referenced.
*
* @param \Drupal\Core\Entity\FieldableEntityInterface $entity
* The entity.
*/
protected function handleXeroIdAdded(FieldableEntityInterface $entity) {
$this->syncIfAppropriate($entity);
}
/**
* Handle where no synced item is/was referenced, or previous state unknown.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*/
protected function handleXeroIdAbsent(EntityInterface $entity) {
$this->syncIfAppropriate($entity);
}
/**
* Handle the case where a synced item is present but previous state unknown.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity.
*/
protected function handleXeroIdPresent(EntityInterface $entity) {
$this->syncIfAppropriate($entity);
}
}
