diff --git a/modules/shareholder_register_webform/shareholder_register_webform.services.yml b/modules/shareholder_register_webform/shareholder_register_webform.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..eb857b6b74b7fe5044aea4c7ecc577552c062ce9 --- /dev/null +++ b/modules/shareholder_register_webform/shareholder_register_webform.services.yml @@ -0,0 +1,4 @@ +services: + shareholder_register_webform.mapping: + class: Drupal\shareholder_register_webform\MappingService + arguments: ['@entity_type.manager', '@shareholder_register.default', '@event_dispatcher', '@messenger', '@logger.channel.shareholder_register'] diff --git a/modules/shareholder_register_webform/src/MappingService.php b/modules/shareholder_register_webform/src/MappingService.php new file mode 100644 index 0000000000000000000000000000000000000000..c47841f1fba348084147321c58295c4a70ae3da3 --- /dev/null +++ b/modules/shareholder_register_webform/src/MappingService.php @@ -0,0 +1,245 @@ +<?php + +namespace Drupal\shareholder_register_webform; + +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Messenger\MessengerInterface; + +use Drupal\shareholder_register\ShareholderRegisterServiceInterface; +use Drupal\webform\webformSubmissionInterface; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + + +/** + * MappingService service. + */ +class MappingService { + + /** + * The entity type manager. + * + * @var \Drupal\Core\Entity\EntityTypeManagerInterface + */ + protected $entityTypeManager; + + /** + * The shareholder_register.default service. + * + * @var \Drupal\shareholder_register\ShareholderRegisterServiceInterface + */ + protected $shareholderRegisterDefault; + + /** + * The event dispatcher. + * + * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface + */ + protected $eventDispatcher; + + /** + * The messenger. + * + * @var \Drupal\Core\Messenger\MessengerInterface + */ + protected $messenger; + + /** + * The logger.channel.shareholder_register service. + * + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + + /** + * Constructs a MappingService object. + * + * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager + * The entity type manager. + * @param \Drupal\shareholder_register\ShareholderRegisterServiceInterface $shareholder_register_default + * The shareholder_register.default service. + * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher + * The event dispatcher. + * @param \Drupal\Core\Messenger\MessengerInterface $messenger + * The messenger. + * @param \Psr\Log\LoggerInterface $logger + * The logger.channel.shareholder_register service. + */ + public function __construct(EntityTypeManagerInterface $entity_type_manager, ShareholderRegisterServiceInterface $shareholder_register_default, EventDispatcherInterface $event_dispatcher, MessengerInterface $messenger, LoggerInterface $logger_channel) { + $this->entityTypeManager = $entity_type_manager; + $this->shareholderRegisterDefault = $shareholder_register_default; + $this->eventDispatcher = $event_dispatcher; + $this->messenger = $messenger; + $this->logger = $logger_channel; + } + + /** + * Method description. + */ + public function loadMapping(string $mapping) { + $mapping_array = []; + + $mapping = str_replace("\r", "\n", str_replace("\r\n", "\n", $mapping)); + foreach (explode("\n", $mapping) as $mapping_line) { + if (!$mapping_line || !trim($mapping_line)) { + continue; + } + + $map = explode('=', $mapping_line); + if (count($map) != 2) { + continue; + } + $property = array_filter( + explode('.', trim($map[0])) + ); + if (count($property) < 1 || count($property) > 2) { + continue; + } + + $data_selector = array_filter( + explode('.', trim($map[1])) + ); + if (count($data_selector) < 1) { + continue; + } + + $mapping_array[] = [ + 'property' => $property, + 'data_selector' => $data_selector, + ]; + } + + return $mapping_array; + } + + /** + * Extract data_selector from data array. + * + * throw Exception if first element doesn't exist. + * + * @returns Element value or FALSE. + */ + public function dataSelectorFromData(array $data, array $data_selector) { + $data_element = $data; + if (!array_key_exists($data_selector[0], $data_element)) { + throw new \Exception("key doesn't exist"); + } + + foreach ($data_selector as $ds) { + if (!$ds || !array_key_exists($ds, $data_element)) { + $data_element = FALSE; + break; + } + $data_element = $data_element[$ds]; + } + return $data_element; + } + + /** + * {@inheritdoc} + */ + public function propertyFromEntity(EntityInterface $entity, array $property) { + if (!$entity->hasField($property[0])) { + return NULL; + } + + if (count($property) == 1) { + return $entity->get(trim($property[0]))->value; + } + elseif (count($property) == 2) { + try { + return $entity->get(trim($property[0]))->{trim($property[1])}; + } + catch (Exception $e) { + return NULL; + } + } + } + + /** + * {@inheritdoc} + */ + public function mapSubmissionToEntity(string $mapping, WebformSubmissionInterface $submission, $entity) { + $data = $submission->getData(); + + foreach ($this->loadMapping($mapping) as $mapping_line) { + + try { + $data_element = $this->dataSelectorFromData($data, $mapping_line['data_selector']); + } + catch (\Exception $exception) { + // Data element not found, continue with next mapping line. + continue; + } + + $property = $mapping_line['property']; + + if (!$entity->hasField($property[0])) { + $this->logger->notice( + 'mapSubmissionToEntity: invalid field @field in mapping.', + [ + '@field' => implode('.', $property), + ] + ); + continue; + } + + if (count($property) == 1) { + $entity->{trim($property[0])} = trim($data_element); + } + elseif (count($property) == 2) { + try { + $entity->{trim($property[0])}->{trim($property[1])} = trim($data_element); + } + catch (Exception $e) { + $this->logger->notice( + 'mapSubmissionToEntity: invalid field item @field in mapping.', + [ + '@field' => implode('.', $data_element), + ] + ); + continue; + } + } + + } + } + + /** + * {@inheritdoc} + */ + public function mapEntityToSubmission($mapping, WebformSubmissionInterface $submission, $entity) { + $data = $submission->getData(); + + foreach ($this->loadMapping($mapping) as $mapping_line) { + $data_element_selector = array_slice($mapping_line['data_selector'], 0, 1); + try { + // Test if first element exists. + $data_element = $this->dataSelectorFromData($data, $data_element_selector); + } + catch (\Exception $exception) { + $this->logger->notice( + 'mapEntityToSubmission: invalid field item @field in mapping', + [ + '@field' => implode('.', $mapping_line['property']), + ] + ); + } + + if (count($mapping_line['data_selector'] > 1)) { + // FIXME: support multilevel data selector. + continue; + } + + $property = $this->propertyFromEntity($entity, $mapping_line['property']); + if ($property === NULL) { + continue; + } + + $submission->setElementData(trim($mapping_line['data_selector'][0]), $data_element); + } + } + +}