Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO;
class DateRange
{
public function __construct(
private ?\DateTimeInterface $fromDate,
private ?\DateTimeInterface $toDate,
) {
}
/**
* Get the value of fromDate.
*/
public function getFromDate()
{
return $this->fromDate;
}
/**
* Get the value of toDate.
*/
public function getToDate()
{
return $this->toDate;
}
}

View File

@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Mapping;
class FieldMappingDAO
{
private bool $isRequired;
/**
* @param string $internalObject
* @param string $internalField
* @param string $integrationObject
* @param string $integrationField
* @param string $syncDirection
* @param bool $isRequired
*/
public function __construct(
private $internalObject,
private $internalField,
private $integrationObject,
private $integrationField,
private $syncDirection,
$isRequired,
) {
$this->isRequired = (bool) $isRequired;
}
/**
* @return string
*/
public function getInternalObject()
{
return $this->internalObject;
}
/**
* @return string
*/
public function getInternalField()
{
return $this->internalField;
}
/**
* @return string
*/
public function getIntegrationObject()
{
return $this->integrationObject;
}
/**
* @return string
*/
public function getIntegrationField()
{
return $this->integrationField;
}
/**
* @return string
*/
public function getSyncDirection()
{
return $this->syncDirection;
}
public function isRequired(): bool
{
return $this->isRequired;
}
}

View File

@@ -0,0 +1,266 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Mapping;
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
class MappingManualDAO
{
private array $objectsMapping = [];
private array $internalObjectsMapping = [];
private array $integrationObjectsMapping = [];
public function __construct(
private string $integration,
) {
}
public function getIntegration(): string
{
return $this->integration;
}
public function addObjectMapping(ObjectMappingDAO $objectMappingDAO): void
{
$internalObjectName = $objectMappingDAO->getInternalObjectName();
$integrationObjectName = $objectMappingDAO->getIntegrationObjectName();
if (!array_key_exists($internalObjectName, $this->objectsMapping)) {
$this->objectsMapping[$internalObjectName] = [];
}
$this->objectsMapping[$internalObjectName][$integrationObjectName] = $objectMappingDAO;
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
$this->internalObjectsMapping[$internalObjectName] = [];
}
$this->internalObjectsMapping[$internalObjectName][] = $integrationObjectName;
if (!array_key_exists($integrationObjectName, $this->integrationObjectsMapping)) {
$this->integrationObjectsMapping[$integrationObjectName] = [];
}
$this->integrationObjectsMapping[$integrationObjectName][] = $internalObjectName;
}
public function getObjectMapping(string $internalObjectName, string $integrationObjectName): ?ObjectMappingDAO
{
if (!array_key_exists($internalObjectName, $this->objectsMapping)) {
return null;
}
if (!array_key_exists($integrationObjectName, $this->objectsMapping[$internalObjectName])) {
return null;
}
return $this->objectsMapping[$internalObjectName][$integrationObjectName];
}
/**
* @throws ObjectNotFoundException
*/
public function getMappedIntegrationObjectsNames(string $internalObjectName): array
{
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
throw new ObjectNotFoundException($internalObjectName);
}
return $this->internalObjectsMapping[$internalObjectName];
}
/**
* @throws ObjectNotFoundException
*/
public function getMappedInternalObjectsNames(string $integrationObjectName): array
{
if (!array_key_exists($integrationObjectName, $this->integrationObjectsMapping)) {
throw new ObjectNotFoundException($integrationObjectName);
}
return $this->integrationObjectsMapping[$integrationObjectName];
}
public function getInternalObjectNames(): array
{
return array_keys($this->internalObjectsMapping);
}
/**
* Get a list of fields that should sync from Mautic to the integration.
*
* @throws ObjectNotFoundException
*/
public function getInternalObjectFieldsToSyncToIntegration(string $internalObjectName): array
{
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
throw new ObjectNotFoundException($internalObjectName);
}
$fields = [];
$integrationObjectsNames = $this->internalObjectsMapping[$internalObjectName];
foreach ($integrationObjectsNames as $integrationObjectName) {
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if (ObjectMappingDAO::SYNC_TO_MAUTIC === $fieldMapping->getSyncDirection() && !$fieldMapping->isRequired()) {
// Ignore because this field is a one way sync from the integration to Mautic nor is required
continue;
}
$fields[$fieldMapping->getInternalField()] = true;
}
}
return array_keys($fields);
}
/**
* Get a list of internal fields that are required.
*
* @throws ObjectNotFoundException
*/
public function getInternalObjectRequiredFieldNames(string $internalObjectName): array
{
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
throw new ObjectNotFoundException($internalObjectName);
}
$fields = [];
$integrationObjectsNames = $this->internalObjectsMapping[$internalObjectName];
foreach ($integrationObjectsNames as $integrationObjectName) {
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if (!$fieldMapping->isRequired()) {
continue;
}
$fields[$fieldMapping->getInternalField()] = true;
}
}
return array_keys($fields);
}
public function getIntegrationObjectNames(): array
{
return array_keys($this->integrationObjectsMapping);
}
/**
* Get a list of fields that should sync from the integration to Mautic.
*
* @throws ObjectNotFoundException
*/
public function getIntegrationObjectFieldsToSyncToMautic(string $integrationObjectName): array
{
if (!array_key_exists($integrationObjectName, $this->integrationObjectsMapping)) {
throw new ObjectNotFoundException($integrationObjectName);
}
$fields = [];
$internalObjectsNames = $this->integrationObjectsMapping[$integrationObjectName];
foreach ($internalObjectsNames as $internalObjectName) {
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if (ObjectMappingDAO::SYNC_TO_INTEGRATION === $fieldMapping->getSyncDirection() && !$fieldMapping->isRequired()) {
// Ignore because this field is a one way sync from Mautic to the integration nor a required field
continue;
}
$fields[$fieldMapping->getIntegrationField()] = true;
}
}
return array_keys($fields);
}
/**
* Get a list of integration fields that are required.
*
* @throws ObjectNotFoundException
*/
public function getIntegrationObjectRequiredFieldNames(string $integrationObjectName): array
{
if (!array_key_exists($integrationObjectName, $this->integrationObjectsMapping)) {
throw new ObjectNotFoundException($integrationObjectName);
}
$fields = [];
$internalObjectsNames = $this->integrationObjectsMapping[$integrationObjectName];
foreach ($internalObjectsNames as $internalObjectName) {
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if (!$fieldMapping->isRequired()) {
continue;
}
$fields[$fieldMapping->getIntegrationField()] = true;
}
}
return array_keys($fields);
}
/**
* @throws FieldNotFoundException
* @throws ObjectNotFoundException
*/
public function getIntegrationMappedField(string $integrationObjectName, string $internalObjectName, string $internalFieldName): string
{
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
throw new ObjectNotFoundException($internalObjectName);
}
if (!array_key_exists($integrationObjectName, $this->objectsMapping[$internalObjectName])) {
throw new ObjectNotFoundException($integrationObjectName);
}
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if ($fieldMapping->getInternalField() === $internalFieldName) {
return $fieldMapping->getIntegrationField();
}
}
throw new FieldNotFoundException($internalFieldName, $internalObjectName);
}
/**
* @throws FieldNotFoundException
* @throws ObjectNotFoundException
*/
public function getInternalMappedField(string $internalObjectName, string $integrationObjectName, string $integrationFieldName): string
{
if (!array_key_exists($internalObjectName, $this->internalObjectsMapping)) {
throw new ObjectNotFoundException($internalObjectName);
}
if (!array_key_exists($integrationObjectName, $this->objectsMapping[$internalObjectName])) {
throw new ObjectNotFoundException($integrationObjectName);
}
/** @var ObjectMappingDAO $objectMappingDAO */
$objectMappingDAO = $this->objectsMapping[$internalObjectName][$integrationObjectName];
$fieldMappings = $objectMappingDAO->getFieldMappings();
foreach ($fieldMappings as $fieldMapping) {
if ($fieldMapping->getIntegrationField() === $integrationFieldName) {
return $fieldMapping->getInternalField();
}
}
throw new FieldNotFoundException($integrationFieldName, $integrationObjectName);
}
}

View File

@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Mapping;
class ObjectMappingDAO
{
public const SYNC_TO_MAUTIC = 'mautic';
public const SYNC_TO_INTEGRATION = 'integration';
public const SYNC_BIDIRECTIONALLY = 'bidirectional';
private array $internalIdMapping = [];
private array $integrationIdMapping = [];
/**
* @var FieldMappingDAO[]
*/
private array $fieldMappings = [];
public function __construct(
private string $internalObjectName,
private string $integrationObjectName,
) {
}
/**
* @param string $internalField
* @param string $integrationField
* @param string $direction
* @param bool $isRequired
*/
public function addFieldMapping($internalField, $integrationField, $direction = self::SYNC_BIDIRECTIONALLY, $isRequired = false): self
{
$this->fieldMappings[] = new FieldMappingDAO(
$this->internalObjectName,
$internalField,
$this->integrationObjectName,
$integrationField,
$direction,
$isRequired
);
return $this;
}
/**
* @return FieldMappingDAO[]
*/
public function getFieldMappings(): array
{
return $this->fieldMappings;
}
public function getMappedIntegrationObjectId(int $internalObjectId): ?int
{
if (array_key_exists($internalObjectId, $this->internalIdMapping)) {
return $this->internalIdMapping[$internalObjectId];
}
return null;
}
/**
* @param mixed $integrationObjectId
*
* @return mixed|null
*/
public function getMappedInternalObjectId($integrationObjectId)
{
if (array_key_exists($integrationObjectId, $this->integrationIdMapping)) {
return $this->integrationIdMapping[$integrationObjectId];
}
return null;
}
public function getInternalObjectName(): string
{
return $this->internalObjectName;
}
public function getIntegrationObjectName(): string
{
return $this->integrationObjectName;
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Mapping;
class RemappedObjectDAO
{
/**
* @param mixed $oldObjectId
* @param mixed $newObjectId
*/
public function __construct(
private string $integration,
private string $oldObjectName,
private $oldObjectId,
private string $newObjectName,
private $newObjectId,
) {
}
public function getIntegration(): string
{
return $this->integration;
}
public function getOldObjectName(): string
{
return $this->oldObjectName;
}
/**
* @return mixed
*/
public function getOldObjectId()
{
return $this->oldObjectId;
}
public function getNewObjectName(): string
{
return $this->newObjectName;
}
/**
* @return mixed
*/
public function getNewObjectId()
{
return $this->newObjectId;
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Mapping;
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
class UpdatedObjectMappingDAO
{
private \DateTimeInterface $objectModifiedDate;
private ?ObjectMapping $objectMapping = null;
/**
* @param string $integration
* @param string $integrationObjectName
* @param mixed $integrationObjectId
*/
public function __construct(
private $integration,
private $integrationObjectName,
private $integrationObjectId,
\DateTimeInterface $objectModifiedDate,
) {
$this->objectModifiedDate = $objectModifiedDate instanceof \DateTimeImmutable ? new \DateTime(
$objectModifiedDate->format('Y-m-d H:i:s'),
$objectModifiedDate->getTimezone()
) : $objectModifiedDate;
}
public function getIntegration(): string
{
return $this->integration;
}
public function getIntegrationObjectName(): string
{
return $this->integrationObjectName;
}
/**
* @return mixed
*/
public function getIntegrationObjectId()
{
return $this->integrationObjectId;
}
public function getObjectModifiedDate(): \DateTimeInterface
{
return $this->objectModifiedDate;
}
public function setObjectMapping(ObjectMapping $objectMapping): void
{
$this->objectMapping = $objectMapping;
}
/**
* This is set after the ObjectMapping entity has been persisted to the database with the updates from this object.
*/
public function getObjectMapping(): ?ObjectMapping
{
return $this->objectMapping;
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync;
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
class InformationChangeRequestDAO
{
private ?\DateTimeInterface $possibleChangeDateTime = null;
private ?\DateTimeInterface $certainChangeDateTime = null;
/**
* @param string $integration
* @param string $objectName
* @param mixed $objectId
* @param string $field
*/
public function __construct(
private $integration,
private $objectName,
private $objectId,
private $field,
private NormalizedValueDAO $newValue,
) {
}
public function getIntegration(): string
{
return $this->integration;
}
/**
* @return mixed
*/
public function getObjectId()
{
return $this->objectId;
}
public function getObject(): string
{
return $this->objectName;
}
public function getField(): string
{
return $this->field;
}
public function getNewValue(): NormalizedValueDAO
{
return $this->newValue;
}
public function getPossibleChangeDateTime(): ?\DateTimeInterface
{
return $this->possibleChangeDateTime;
}
public function setPossibleChangeDateTime(?\DateTimeInterface $possibleChangeDateTime = null): self
{
$this->possibleChangeDateTime = $possibleChangeDateTime;
return $this;
}
public function getCertainChangeDateTime(): ?\DateTimeInterface
{
return $this->certainChangeDateTime;
}
public function setCertainChangeDateTime(?\DateTimeInterface $certainChangeDateTime = null): self
{
$this->certainChangeDateTime = $certainChangeDateTime;
return $this;
}
}

View File

@@ -0,0 +1,202 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync;
use DateTimeInterface;
use Mautic\IntegrationsBundle\Exception\InvalidValueException;
use Mautic\IntegrationsBundle\Sync\SyncDataExchange\Internal\Object\Contact;
class InputOptionsDAO
{
/**
* @var string
*/
private $integration;
private bool $firstTimeSync;
private bool $disablePush;
private bool $disablePull;
private bool $disableActivityPush;
private ?ObjectIdsDAO $mauticObjectIds;
private ?ObjectIdsDAO $integrationObjectIds;
private ?\DateTimeInterface $startDateTime;
private ?\DateTimeInterface $endDateTime;
private array $options;
/**
* Example $input:
* [
* 'integration' => 'Magento', // required
* 'first-time-sync' => true,
* 'disable-push' => false,
* 'disable-pull' => false,
* 'disable-activity-push' => false,
* 'mautic-object-id' => ['contact:12', 'contact:13'] or a ObjectIdsDAO object,
* 'integration-object-id' => ['Lead:hfskjdhf', 'Lead:hfskjdhr'] or a ObjectIdsDAO object,
* 'start-datetime' => '2019-09-12T12:01:20' or a DateTimeInterface object, Expecting UTC timezone
* 'end-datetime' => '2019-09-12T12:01:20' or a DateTimeInterface object, Expecting UTC timezone
* ].
*
* @throws InvalidValueException
*/
public function __construct(array $input)
{
if (empty($input['integration'])) {
throw new InvalidValueException('An integration must be specified. None provided.');
}
$input = $this->fixNaming($input);
$this->integration = $input['integration'];
$this->firstTimeSync = (bool) ($input['first-time-sync'] ?? false);
$this->disablePush = (bool) ($input['disable-push'] ?? false);
$this->disablePull = (bool) ($input['disable-pull'] ?? false);
$this->disableActivityPush = (bool) ($input['disable-activity-push'] ?? false);
$this->startDateTime = $this->validateDateTime($input, 'start-datetime');
$this->endDateTime = $this->validateDateTime($input, 'end-datetime');
$this->mauticObjectIds = $this->validateObjectIds($input, 'mautic-object-id');
$this->integrationObjectIds = $this->validateObjectIds($input, 'integration-object-id');
$this->options = $this->validateOptions($input);
}
public function getIntegration(): string
{
return $this->integration;
}
public function isFirstTimeSync(): bool
{
return $this->firstTimeSync;
}
public function pullIsEnabled(): bool
{
return !$this->disablePull;
}
public function activityPushIsEnabled(): bool
{
return !$this->disableActivityPush;
}
public function pushIsEnabled(): bool
{
return !$this->disablePush;
}
public function getMauticObjectIds(): ?ObjectIdsDAO
{
return $this->mauticObjectIds;
}
public function getIntegrationObjectIds(): ?ObjectIdsDAO
{
return $this->integrationObjectIds;
}
public function getStartDateTime(): ?\DateTimeInterface
{
return $this->startDateTime;
}
public function getEndDateTime(): ?\DateTimeInterface
{
return $this->endDateTime;
}
public function getOptions(): array
{
return $this->options;
}
/**
* @throws InvalidValueException
*/
private function validateDateTime(array $input, string $optionName): ?\DateTimeInterface
{
if (empty($input[$optionName])) {
return null;
}
if ($input[$optionName] instanceof \DateTimeInterface) {
return $input[$optionName];
} else {
try {
return is_string($input[$optionName]) ? new \DateTimeImmutable($input[$optionName], new \DateTimeZone('UTC')) : null;
} catch (\Throwable) {
throw new InvalidValueException("'$input[$optionName]' is not valid. Use 'Y-m-d H:i:s' format like '2018-12-24 20:30:00' or something like '-10 minutes'");
}
}
}
/**
* @throws InvalidValueException
*/
private function validateObjectIds(array $input, string $optionName): ?ObjectIdsDAO
{
if (empty($input[$optionName])) {
return null;
}
if ($input[$optionName] instanceof ObjectIdsDAO) {
return $input[$optionName];
} elseif (is_array($input[$optionName])) {
return ObjectIdsDAO::createFromCliOptions($input[$optionName]);
} else {
throw new InvalidValueException("{$optionName} option has an unexpected type. Use an array or ObjectIdsDAO object.");
}
}
/**
* This method exists only because Mautic leads were renamed to contacts. Users will be able
* to use the "contact" keywoard and developers "lead" as the integration bundle use "lead" everywhere.
*/
private function fixNaming(array $input): array
{
if (empty($input['mautic-object-id'])) {
return $input;
}
if (!is_array($input['mautic-object-id'])) {
return $input;
}
foreach ($input['mautic-object-id'] as $key => $mauticObjectId) {
$input['mautic-object-id'][$key] = preg_replace(
'/^contact:/',
Contact::NAME.':',
"$mauticObjectId"
);
}
return $input;
}
private function validateOptions(array $input): array
{
if (is_array($input['options'] ?? null)) {
return $input['options'];
}
$options = [];
if (is_array($input['option'] ?? null)) {
foreach ($input['option'] as $option) {
$parsedOption = explode(':', $option);
if (2 === count($parsedOption)) {
$options[$parsedOption[0]] = $parsedOption[1];
}
}
}
return $options;
}
}

View File

@@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync;
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
/**
* Holds IDs for different types of objects. Can be used for Mautic or integration objects.
*/
class ObjectIdsDAO
{
/**
* Expected structure:
* [
* 'objectA' => [12, 13],
* 'objectB' => ['asfdaswty', 'wetegdfsd'],
* ].
*
* @var array[]
*/
private array $objects = [];
/**
* Expected $cliOptions structure:
* [
* 'abjectA:12',
* 'abjectA:13',
* 'abjectB:asfdaswty',
* 'abjectB:wetegdfsd',
* ]
* Simply put, an array of object types and IDs separated by colon.
*
* @param string[] $cliOptions
*/
public static function createFromCliOptions(array $cliOptions): self
{
$objectsIdDAO = new self();
foreach ($cliOptions as $cliOption) {
if (is_string($cliOption) && str_contains($cliOption, ':')) {
$objectsIdDAO->addObjectId(...explode(':', $cliOption));
}
}
return $objectsIdDAO;
}
public function addObjectId(string $objectType, string $id): void
{
if (!isset($this->objects[$objectType])) {
$this->objects[$objectType] = [];
}
$this->objects[$objectType][] = $id;
}
/**
* @return string[]
*
* @throws ObjectNotFoundException
*/
public function getObjectIdsFor(string $objectType): array
{
if (empty($this->objects[$objectType])) {
throw new ObjectNotFoundException("Object {$objectType} doesn't have any IDs to return");
}
return $this->objects[$objectType];
}
/**
* @return string[]
*/
public function getObjectTypes(): array
{
return array_keys($this->objects);
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
class FieldDAO
{
/**
* @param string $name
*/
public function __construct(
private $name,
private NormalizedValueDAO $value,
) {
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
public function getValue(): NormalizedValueDAO
{
return $this->value;
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
class NotificationDAO
{
public function __construct(
private ObjectChangeDAO $objectChangeDAO,
private string $message,
) {
}
/**
* @return ObjectChangeDAO
*/
public function getMauticObject(): string
{
return $this->objectChangeDAO->getMappedObject();
}
public function getMauticObjectId(): int
{
return (int) $this->objectChangeDAO->getMappedObjectId();
}
public function getIntegration(): string
{
return $this->objectChangeDAO->getIntegration();
}
public function getIntegrationObject(): string
{
return $this->objectChangeDAO->getObject();
}
/**
* @return mixed
*/
public function getIntegrationObjectId()
{
return $this->objectChangeDAO->getObjectId();
}
public function getMessage(): string
{
return $this->message;
}
}

View File

@@ -0,0 +1,201 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\FieldDAO as ReportFieldDAO;
class ObjectChangeDAO
{
/**
* @var FieldDAO[]
*/
private array $fields = [];
private ?ObjectMapping $objectMapping = null;
/**
* @var FieldDAO[]
*/
private array $fieldsByState = [
ReportFieldDAO::FIELD_CHANGED => [],
ReportFieldDAO::FIELD_UNCHANGED => [],
ReportFieldDAO::FIELD_REQUIRED => [],
];
/**
* @param string $integration
* @param string $object
* @param mixed $objectId
* @param string $mappedObject Name of the source object type
* @param mixed $mappedId ID of the source object
* @param \DateTimeInterface $changeDateTime Date\Time the object was last changed
*/
public function __construct(
private $integration,
private $object,
private $objectId,
private $mappedObject,
private $mappedId,
private ?\DateTimeInterface $changeDateTime = null,
) {
}
public function getIntegration(): string
{
return $this->integration;
}
public function addField(FieldDAO $fieldDAO, string $state = ReportFieldDAO::FIELD_CHANGED): self
{
$this->fields[$fieldDAO->getName()] = $fieldDAO;
$this->fieldsByState[$state][$fieldDAO->getName()] = $fieldDAO;
if (ReportFieldDAO::FIELD_REQUIRED === $state) {
// Make this field also available to the unchanged fields array so the integration can get which
// ever one it wants based on it's implementation (i.e. patch vs put)
$this->fieldsByState[ReportFieldDAO::FIELD_UNCHANGED][$fieldDAO->getName()] = $fieldDAO;
}
return $this;
}
/**
* @return string
*/
public function getObject()
{
return $this->object;
}
/**
* @param mixed $objectId
*/
public function setObjectId($objectId): void
{
$this->objectId = $objectId;
}
/**
* @return mixed
*/
public function getObjectId()
{
return $this->objectId;
}
/**
* Returns the name/type for the object in this system that is being synced to the other.
*
* @return string
*/
public function getMappedObject()
{
return $this->mappedObject;
}
/**
* Returns the ID for the object in this system that is being synced to the other.
*
* @return mixed
*/
public function getMappedObjectId()
{
return $this->mappedId;
}
/**
* @param string $name
*
* @return FieldDAO|null
*/
public function getField($name)
{
return $this->fields[$name] ?? null;
}
/**
* Returns all fields whether changed, unchanged required.
*
* @return FieldDAO[]
*/
public function getFields(): array
{
return $this->fields;
}
/**
* Returns only fields that we assume have been changed/modified.
*
* @return FieldDAO[]
*/
public function getChangedFields(): array
{
return $this->fieldsByState[ReportFieldDAO::FIELD_CHANGED];
}
/**
* Returns only fields that are required but were not updated.
*
* @return FieldDAO[]
*/
public function getRequiredFields(): array
{
return $this->fieldsByState[ReportFieldDAO::FIELD_REQUIRED];
}
/**
* Returns fields that were mapped that values were known even though the value was not updated. It does include FieldDAO::FIELD_REQUIRED fields.
*
* @return FieldDAO[]
*/
public function getUnchangedFields(): array
{
return $this->fieldsByState[ReportFieldDAO::FIELD_UNCHANGED];
}
public function shouldSync(): bool
{
return !empty(count($this->fields));
}
public function getChangeDateTime(): \DateTimeInterface
{
return $this->changeDateTime;
}
/**
* @return ObjectChangeDAO
*/
public function setChangeDateTime(?\DateTimeInterface $changeDateTime = null)
{
if (null === $changeDateTime) {
$changeDateTime = new \DateTime();
}
$this->changeDateTime = $changeDateTime;
return $this;
}
public function setObjectMapping(ObjectMapping $objectMapping): void
{
$this->objectMapping = $objectMapping;
}
/**
* This is set after the ObjectMapping entity has been persisted to the database with the updates from this object.
*/
public function getObjectMapping(): ObjectMapping
{
return $this->objectMapping;
}
public function removeField(string $field): void
{
unset($this->fields[$field]);
unset($this->fieldsByState[ReportFieldDAO::FIELD_CHANGED][$field]);
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
class ObjectMappingsDAO
{
/**
* @var ObjectMapping[]
*/
private array $updatedMappings = [];
/**
* @var ObjectMapping[]
*/
private array $newMappings = [];
public function addUpdatedObjectMapping(ObjectMapping $objectMapping): void
{
$this->updatedMappings[] = $objectMapping;
}
public function addNewObjectMapping(ObjectMapping $objectMapping): void
{
$this->newMappings[] = $objectMapping;
}
/**
* @return ObjectMapping[]
*/
public function getUpdatedMappings(): array
{
return $this->updatedMappings;
}
/**
* @return ObjectMapping[]
*/
public function getNewMappings(): array
{
return $this->newMappings;
}
}

View File

@@ -0,0 +1,305 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
use Mautic\IntegrationsBundle\Exception\UnexpectedValueException;
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\RemappedObjectDAO;
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\UpdatedObjectMappingDAO;
class OrderDAO
{
/**
* @var ObjectChangeDAO[][]
*/
private array $identifiedObjects = [];
/**
* @var ObjectChangeDAO[][]
*/
private array $unidentifiedObjects = [];
/**
* Array of all changed objects.
*
* @var ObjectChangeDAO[][]
*/
private array $changedObjects = [];
/**
* @var ObjectMapping[]
*/
private array $objectMappings = [];
/**
* @var UpdatedObjectMappingDAO[]
*/
private array $updatedObjectMappings = [];
/**
* @var RemappedObjectDAO[]
*/
private array $remappedObjects = [];
/**
* @var ObjectChangeDAO[]
*/
private array $deleteTheseObjects = [];
private array $retryTheseLater = [];
private int $objectCounter = 0;
/**
* @var NotificationDAO[]
*/
private array $notifications = [];
/**
* @param bool $isFirstTimeSync
* @param string $integration
*/
public function __construct(
private \DateTimeInterface $syncDateTime,
private $isFirstTimeSync,
private $integration,
private array $options = [],
) {
}
public function addObjectChange(ObjectChangeDAO $objectChangeDAO): self
{
if (!isset($this->identifiedObjects[$objectChangeDAO->getObject()])) {
$this->identifiedObjects[$objectChangeDAO->getObject()] = [];
$this->unidentifiedObjects[$objectChangeDAO->getObject()] = [];
$this->changedObjects[$objectChangeDAO->getObject()] = [];
}
$this->changedObjects[$objectChangeDAO->getObject()][] = $objectChangeDAO;
++$this->objectCounter;
if ($objectChangeDAO->getObjectId()) {
$this->identifiedObjects[$objectChangeDAO->getObject()][$objectChangeDAO->getObjectId()] = $objectChangeDAO;
return $this;
}
// These objects are not already tracked and thus possibly need to be created
$this->unidentifiedObjects[$objectChangeDAO->getObject()][$objectChangeDAO->getMappedObjectId()] = $objectChangeDAO;
return $this;
}
/**
* @throws UnexpectedValueException
*/
public function getChangedObjectsByObjectType(string $objectType): array
{
if (isset($this->changedObjects[$objectType])) {
return $this->changedObjects[$objectType];
}
throw new UnexpectedValueException("There are no change objects for object type '$objectType'");
}
/**
* @return ObjectChangeDAO[][]
*/
public function getIdentifiedObjects(): array
{
return $this->identifiedObjects;
}
/**
* @return ObjectChangeDAO[][]
*/
public function getUnidentifiedObjects(): array
{
return $this->unidentifiedObjects;
}
/**
* Create a new mapping between the Mautic and Integration objects.
*
* @param string $integrationObjectName
* @param string|int $integrationObjectId
*/
public function addObjectMapping(
ObjectChangeDAO $objectChangeDAO,
$integrationObjectName,
$integrationObjectId,
?\DateTimeInterface $objectModifiedDate = null,
): void {
if (null === $objectModifiedDate) {
$objectModifiedDate = new \DateTime();
}
$objectMapping = new ObjectMapping();
$objectMapping->setIntegration($this->integration)
->setInternalObjectName($objectChangeDAO->getMappedObject())
->setInternalObjectId($objectChangeDAO->getMappedObjectId())
->setIntegrationObjectName($integrationObjectName)
->setIntegrationObjectId($integrationObjectId)
->setLastSyncDate($objectModifiedDate);
$this->objectMappings[] = $objectMapping;
}
/**
* Update an existing mapping in the case of conversions (i.e. Lead converted to Contact).
*
* @param mixed $oldObjectId
* @param string $oldObjectName
* @param string $newObjectName
* @param mixed $newObjectId
*/
public function remapObject($oldObjectName, $oldObjectId, $newObjectName, $newObjectId = null): void
{
if (null === $newObjectId) {
$newObjectId = $oldObjectId;
}
$this->remappedObjects[$oldObjectId] = new RemappedObjectDAO($this->integration, $oldObjectName, $oldObjectId, $newObjectName, $newObjectId);
}
/**
* Update the last sync date of an existing mapping.
*/
public function updateLastSyncDate(ObjectChangeDAO $objectChangeDAO, ?\DateTimeInterface $objectModifiedDate = null): void
{
if (null === $objectModifiedDate) {
$objectModifiedDate = new \DateTime();
}
$this->updatedObjectMappings[] = new UpdatedObjectMappingDAO(
$this->integration,
$objectChangeDAO->getObject(),
$objectChangeDAO->getObjectId(),
$objectModifiedDate
);
}
/**
* Mark an object as deleted in the integration so Mautic doesn't continue to attempt to sync it.
*/
public function deleteObject(ObjectChangeDAO $objectChangeDAO): void
{
$this->deleteTheseObjects[] = $objectChangeDAO;
}
/**
* If there is a temporary issue with syncing the object, tell the sync engine to not wipe out the tracked changes on Mautic's object fields
* so that they are attempted again for the next sync.
*/
public function retrySyncLater(ObjectChangeDAO $objectChangeDAO): void
{
if (!isset($this->retryTheseLater[$objectChangeDAO->getMappedObject()])) {
$this->retryTheseLater[$objectChangeDAO->getMappedObject()] = [];
}
$this->retryTheseLater[$objectChangeDAO->getMappedObject()][$objectChangeDAO->getMappedObjectId()] = $objectChangeDAO;
}
public function noteObjectSyncIssue(ObjectChangeDAO $objectChangeDAO, string $message): void
{
$this->notifications[] = new NotificationDAO($objectChangeDAO, $message);
}
/**
* @return ObjectMapping[]
*/
public function getObjectMappings(): array
{
return $this->objectMappings;
}
/**
* @return UpdatedObjectMappingDAO[]
*/
public function getUpdatedObjectMappings(): array
{
return $this->updatedObjectMappings;
}
/**
* @return ObjectChangeDAO[]
*/
public function getDeletedObjects(): array
{
return $this->deleteTheseObjects;
}
/**
* @return RemappedObjectDAO[]
*/
public function getRemappedObjects(): array
{
return $this->remappedObjects;
}
/**
* @return NotificationDAO[]
*/
public function getNotifications()
{
return $this->notifications;
}
/**
* @return ObjectChangeDAO[]
*/
public function getSuccessfullySyncedObjects(): array
{
$synced = [];
foreach ($this->changedObjects as $objectChanges) {
foreach ($objectChanges as $objectChange) {
if (isset($this->retryTheseLater[$objectChange->getMappedObject()][$objectChange->getMappedObjectId()])) {
continue;
}
$synced[] = $objectChange;
}
}
return $synced;
}
public function getIdentifiedObjectIds(string $object): array
{
if (!array_key_exists($object, $this->identifiedObjects)) {
return [];
}
return array_keys($this->identifiedObjects[$object]);
}
/**
* @return \DateTime
*/
public function getSyncDateTime(): \DateTimeInterface
{
return $this->syncDateTime;
}
public function isFirstTimeSync(): bool
{
return $this->isFirstTimeSync;
}
public function shouldSync(): bool
{
return !empty($this->changedObjects);
}
public function getObjectCount(): int
{
return $this->objectCounter;
}
public function getOptions(): array
{
return $this->options;
}
}

View File

@@ -0,0 +1,169 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Order;
use Mautic\IntegrationsBundle\Entity\ObjectMapping;
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\RemappedObjectDAO;
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
class OrderResultsDAO
{
/**
* @var ObjectMapping[][]
*/
private array $newObjectMappings = [];
/**
* @var ObjectMapping[][]
*/
private array $updatedObjectMappings = [];
/**
* @var RemappedObjectDAO[][]
*/
private array $remappedObjects = [];
/**
* @var ObjectChangeDAO[][]
*/
private array $deletedObjects = [];
/**
* @param ObjectMapping[] $newObjectMappings
* @param ObjectMapping[] $updatedObjectMappings
* @param RemappedObjectDAO[] $remappedObjects
* @param ObjectChangeDAO[] $deletedObjects
*/
public function __construct(array $newObjectMappings, array $updatedObjectMappings, array $remappedObjects, array $deletedObjects)
{
$this->groupNewObjectMappingsByObjectName($newObjectMappings);
$this->groupUpdatedObjectMappingsByObjectName($updatedObjectMappings);
$this->groupRemappedObjectsByObjectName($remappedObjects);
$this->groupDeletedObjectsByObjectName($deletedObjects);
}
/**
* @return ObjectMapping[]
*/
public function getObjectMappings(string $objectName): array
{
$newObjectMappings = $this->newObjectMappings[$objectName] ?? [];
$updatedObjectMappings = $this->updatedObjectMappings[$objectName] ?? [];
return array_merge($newObjectMappings, $updatedObjectMappings);
}
/**
* @return ObjectMapping[]
*
* @throws ObjectNotFoundException
*/
public function getNewObjectMappings(string $objectName): array
{
if (!isset($this->newObjectMappings[$objectName])) {
throw new ObjectNotFoundException($objectName);
}
return $this->newObjectMappings[$objectName];
}
/**
* @return ObjectMapping[]
*
* @throws ObjectNotFoundException
*/
public function getUpdatedObjectMappings(string $objectName): array
{
if (!isset($this->updatedObjectMappings[$objectName])) {
throw new ObjectNotFoundException($objectName);
}
return $this->updatedObjectMappings[$objectName];
}
/**
* @return RemappedObjectDAO[]
*
* @throws ObjectNotFoundException
*/
public function getRemappedObjects(string $objectName): array
{
if (!isset($this->remappedObjects[$objectName])) {
throw new ObjectNotFoundException($objectName);
}
return $this->remappedObjects[$objectName];
}
/**
* @return ObjectChangeDAO[]
*
* @throws ObjectNotFoundException
*/
public function getDeletedObjects(string $objectName): array
{
if (!isset($this->deletedObjects[$objectName])) {
throw new ObjectNotFoundException($objectName);
}
return $this->deletedObjects[$objectName];
}
/**
* @param ObjectMapping[] $objectMappings
*/
private function groupNewObjectMappingsByObjectName(array $objectMappings): void
{
foreach ($objectMappings as $objectMapping) {
if (!isset($this->newObjectMappings[$objectMapping->getIntegrationObjectName()])) {
$this->newObjectMappings[$objectMapping->getIntegrationObjectName()] = [];
}
$this->newObjectMappings[$objectMapping->getIntegrationObjectName()][] = $objectMapping;
}
}
/**
* @param ObjectMapping[] $objectMappings
*/
private function groupUpdatedObjectMappingsByObjectName(array $objectMappings): void
{
foreach ($objectMappings as $objectMapping) {
if (!isset($this->updatedObjectMappings[$objectMapping->getIntegrationObjectName()])) {
$this->updatedObjectMappings[$objectMapping->getIntegrationObjectName()] = [];
}
$this->updatedObjectMappings[$objectMapping->getIntegrationObjectName()][] = $objectMapping;
}
}
/**
* @param RemappedObjectDAO[] $remappedObjects
*/
private function groupRemappedObjectsByObjectName(array $remappedObjects): void
{
foreach ($remappedObjects as $remappedObject) {
if (!isset($this->remappedObjects[$remappedObject->getNewObjectName()])) {
$this->remappedObjects[$remappedObject->getNewObjectName()] = [];
}
$this->remappedObjects[$remappedObject->getNewObjectName()][] = $remappedObject;
}
}
/**
* @param ObjectChangeDAO[] $deletedObjects
*/
private function groupDeletedObjectsByObjectName(array $deletedObjects): void
{
foreach ($deletedObjects as $deletedObject) {
if (!isset($this->deletedObjects[$deletedObject->getObject()])) {
$this->deletedObjects[$deletedObject->getObject()] = [];
}
$this->deletedObjects[$deletedObject->getObject()][] = $deletedObject;
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync;
use Mautic\IntegrationsBundle\Sync\DAO\Sync\Report\RelationDAO;
class RelationsDAO implements \Iterator, \Countable
{
/**
* @var RelationDAO[]
*/
private array $relations = [];
private int $position = 0;
/**
* @param RelationDAO[] $relations
*/
public function addRelations(array $relations): void
{
foreach ($relations as $relation) {
$this->addRelation($relation);
}
}
public function addRelation(RelationDAO $relation): void
{
$this->relations[] = $relation;
}
public function current(): RelationDAO
{
return $this->relations[$this->position];
}
public function next(): void
{
++$this->position;
}
public function key(): int
{
return $this->position;
}
public function valid(): bool
{
return isset($this->relations[$this->position]);
}
public function rewind(): void
{
$this->position = 0;
}
public function count(): int
{
return count($this->relations);
}
}

View File

@@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Report;
use Mautic\IntegrationsBundle\Sync\DAO\Value\NormalizedValueDAO;
class FieldDAO
{
public const FIELD_CHANGED = 'changed';
public const FIELD_REQUIRED = 'required';
public const FIELD_UNCHANGED = 'unchanged';
private ?\DateTimeInterface $changeDateTime = null;
public function __construct(
private string $name,
private NormalizedValueDAO $value,
private string $state = self::FIELD_CHANGED,
) {
}
public function getName(): string
{
return $this->name;
}
public function getValue(): NormalizedValueDAO
{
return $this->value;
}
public function getChangeDateTime(): ?\DateTimeInterface
{
return $this->changeDateTime;
}
public function setChangeDateTime(\DateTimeInterface $changeDateTime): self
{
$this->changeDateTime = $changeDateTime;
return $this;
}
public function getState(): string
{
return $this->state;
}
}

View File

@@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Report;
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
class ObjectDAO
{
/**
* @var FieldDAO[]
*/
private array $fields = [];
/**
* @param string $object
* @param mixed $objectId
*/
public function __construct(
private $object,
private $objectId,
private ?\DateTimeInterface $changeDateTime = null,
) {
}
public function getChangeDateTime(): ?\DateTimeInterface
{
return $this->changeDateTime;
}
public function setChangeDateTime(\DateTimeInterface $changeDateTime): self
{
$this->changeDateTime = $changeDateTime;
return $this;
}
/**
* @return $this
*/
public function addField(FieldDAO $fieldDAO)
{
$this->fields[$fieldDAO->getName()] = $fieldDAO;
return $this;
}
/**
* @return mixed
*/
public function getObjectId()
{
return $this->objectId;
}
/**
* @return string
*/
public function getObject()
{
return $this->object;
}
/**
* @param string $name
*
* @return FieldDAO|null
*
* @throws FieldNotFoundException
*/
public function getField($name)
{
if (!isset($this->fields[$name])) {
throw new FieldNotFoundException($name, $this->object);
}
return $this->fields[$name];
}
/**
* @return FieldDAO[]
*/
public function getFields(): array
{
return $this->fields;
}
}

View File

@@ -0,0 +1,54 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Report;
class RelationDAO
{
private ?int $relObjectInternalId = null;
public function __construct(
private string $objectName,
private string $relFieldName,
private string $relObjectName,
private string $objectIntegrationId,
private string $relObjectIntegrationId,
) {
}
public function getObjectName(): string
{
return $this->objectName;
}
public function getRelObjectName(): string
{
return $this->relObjectName;
}
public function getRelFieldName(): string
{
return $this->relFieldName;
}
public function getObjectIntegrationId(): string
{
return $this->objectIntegrationId;
}
public function getRelObjectIntegrationId(): string
{
return $this->relObjectIntegrationId;
}
public function getRelObjectInternalId(): ?int
{
return $this->relObjectInternalId;
}
public function setRelObjectInternalId(int $relObjectInternalId): void
{
$this->relObjectInternalId = $relObjectInternalId;
}
}

View File

@@ -0,0 +1,146 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Report;
use Mautic\IntegrationsBundle\Sync\DAO\Mapping\RemappedObjectDAO;
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InformationChangeRequestDAO;
use Mautic\IntegrationsBundle\Sync\DAO\Sync\RelationsDAO;
use Mautic\IntegrationsBundle\Sync\Exception\FieldNotFoundException;
use Mautic\IntegrationsBundle\Sync\Exception\ObjectNotFoundException;
class ReportDAO
{
private array $objects = [];
private array $remappedObjects = [];
private RelationsDAO $relationsDAO;
/**
* @param string $integration
*/
public function __construct(
private $integration,
) {
$this->relationsDAO = new RelationsDAO();
}
/**
* @return string
*/
public function getIntegration()
{
return $this->integration;
}
/**
* @return $this
*/
public function addObject(ObjectDAO $objectDAO)
{
if (!isset($this->objects[$objectDAO->getObject()])) {
$this->objects[$objectDAO->getObject()] = [];
}
$this->objects[$objectDAO->getObject()][$objectDAO->getObjectId()] = $objectDAO;
return $this;
}
/**
* @param mixed $oldObjectId
* @param string $oldObjectName
* @param string $newObjectName
* @param mixed $newObjectId
*/
public function remapObject($oldObjectName, $oldObjectId, $newObjectName, $newObjectId = null): void
{
if (null === $newObjectId) {
$newObjectId = $oldObjectId;
}
$this->remappedObjects[$oldObjectId] = new RemappedObjectDAO($this->integration, $oldObjectName, $oldObjectId, $newObjectName, $newObjectId);
}
/**
* @throws ObjectNotFoundException
* @throws FieldNotFoundException
*/
public function getInformationChangeRequest($objectName, $objectId, $fieldName): InformationChangeRequestDAO
{
if (empty($this->objects[$objectName][$objectId])) {
throw new ObjectNotFoundException($objectName.':'.$objectId);
}
/** @var ObjectDAO $reportObject */
$reportObject = $this->objects[$objectName][$objectId];
$reportField = $reportObject->getField($fieldName);
$informationChangeRequest = new InformationChangeRequestDAO(
$this->integration,
$objectName,
$objectId,
$fieldName,
$reportField->getValue()
);
$informationChangeRequest->setPossibleChangeDateTime($reportObject->getChangeDateTime())
->setCertainChangeDateTime($reportField->getChangeDateTime());
return $informationChangeRequest;
}
/**
* @return ObjectDAO[]
*/
public function getObjects(?string $objectName)
{
$returnedObjects = [];
if (null === $objectName) {
foreach ($this->objects as $objects) {
foreach ($objects as $object) {
$returnedObjects[] = $object;
}
}
return $returnedObjects;
}
return $this->objects[$objectName] ?? [];
}
/**
* @return RemappedObjectDAO[]
*/
public function getRemappedObjects(): array
{
return $this->remappedObjects;
}
/**
* @param int $objectId
*/
public function getObject(string $objectName, $objectId): ?ObjectDAO
{
if (!isset($this->objects[$objectName])) {
return null;
}
if (!isset($this->objects[$objectName][$objectId])) {
return null;
}
return $this->objects[$objectName][$objectId];
}
public function shouldSync(): bool
{
return !empty($this->objects);
}
public function getRelations(): RelationsDAO
{
return $this->relationsDAO;
}
}

View File

@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Request;
class ObjectDAO
{
/**
* @var string[]
*/
private array $fields = [];
/**
* @var string[]
*/
private array $requiredFields = [];
public function __construct(
private string $object,
/**
* Date/time based on last synced date for the object or the start date/time fed through the command's arguments.
* This value does not change between iterations.
*/
private ?\DateTimeInterface $fromDateTime = null,
/**
* Date/Time the sync started.
*/
private ?\DateTimeInterface $toDateTime = null,
) {
}
public function getObject(): string
{
return $this->object;
}
/**
* @return self
*/
public function addField(string $field)
{
$this->fields[] = $field;
return $this;
}
/**
* @return string[]
*/
public function getFields(): array
{
return $this->fields;
}
public function setRequiredFields(array $fields): void
{
$this->requiredFields = $fields;
}
/**
* @return string[]
*/
public function getRequiredFields(): array
{
return $this->requiredFields;
}
public function getFromDateTime(): ?\DateTimeInterface
{
return $this->fromDateTime;
}
public function getToDateTime(): ?\DateTimeInterface
{
return $this->toDateTime;
}
}

View File

@@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Sync\Request;
use Mautic\IntegrationsBundle\Sync\DAO\Sync\InputOptionsDAO;
class RequestDAO
{
private int $syncIteration;
/**
* @var ObjectDAO[]
*/
private array $objects = [];
public function __construct(
private string $syncToIntegration,
int $syncIteration,
private InputOptionsDAO $inputOptionsDAO,
) {
$this->syncIteration = (int) $syncIteration;
}
/**
* @return self
*/
public function addObject(ObjectDAO $objectDAO)
{
$this->objects[] = $objectDAO;
return $this;
}
/**
* @return ObjectDAO[]
*/
public function getObjects(): array
{
return $this->objects;
}
public function getSyncIteration(): int
{
return $this->syncIteration;
}
public function isFirstTimeSync(): bool
{
return $this->inputOptionsDAO->isFirstTimeSync();
}
/**
* The integration that will be synced to.
*/
public function getSyncToIntegration(): string
{
return $this->syncToIntegration;
}
/**
* Returns DAO object with all input options.
*/
public function getInputOptionsDAO(): InputOptionsDAO
{
return $this->inputOptionsDAO;
}
/**
* Returns true if there are objects to sync.
*/
public function shouldSync(): bool
{
return !empty($this->objects);
}
}

View File

@@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Value;
class EncodedValueDAO
{
public const STRING_TYPE = 'string';
public const INT_TYPE = 'int';
public const FLOAT_TYPE = 'float';
public const DOUBLE_TYPE = 'double';
public const DATETIME_TYPE = 'datetime';
public const BOOLEAN_TYPE = 'boolean';
/**
* @param string $type
* @param string $value
*/
public function __construct(
private $type,
private $value,
) {
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return string
*/
public function getValue()
{
return $this->value;
}
}

View File

@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Value;
class NormalizedValueDAO
{
public const BOOLEAN_TYPE = 'boolean';
public const DATE_TYPE = 'date';
public const DATETIME_TYPE = 'datetime';
public const DOUBLE_TYPE = 'double';
public const EMAIL_TYPE = 'email';
public const FLOAT_TYPE = 'float';
public const INT_TYPE = 'int';
public const LOOKUP_TYPE = 'lookup';
public const MULTISELECT_TYPE = 'multiselect';
public const PHONE_TYPE = 'phone';
public const SELECT_TYPE = 'select';
public const STRING_TYPE = 'string';
public const REGION_TYPE = 'region';
public const TEXT_TYPE = 'text';
public const TEXTAREA_TYPE = 'textarea';
public const TIME_TYPE = 'time';
public const URL_TYPE = 'url';
public const REFERENCE_TYPE = 'reference';
/**
* @var mixed
*/
private $normalizedValue;
/**
* @param string $type
* @param mixed $value
* @param mixed $normalizedValue
*/
public function __construct(
private $type,
private $value,
$normalizedValue = null,
) {
$this->normalizedValue = $normalizedValue ?: $value;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return mixed
*/
public function getOriginalValue()
{
return $this->value;
}
/**
* @return mixed
*/
public function getNormalizedValue()
{
return $this->normalizedValue;
}
}

View File

@@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace Mautic\IntegrationsBundle\Sync\DAO\Value;
class ReferenceValueDAO implements \Stringable
{
private ?int $value = null;
private ?string $type = null;
public function getValue(): ?int
{
return $this->value;
}
public function setValue(int $value): void
{
$this->value = $value;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): void
{
$this->type = $type;
}
public function __toString(): string
{
return (string) $this->value;
}
/** @return array<string, mixed> */
public function __serialize(): array
{
return [
'value' => $this->value,
'types' => $this->type,
];
}
/** @param array<string, mixed> $data */
public function __unserialize(array $data): void
{
$this->value = $data['value'] ?? null;
$this->type = $data['type'] ?? null;
}
}