230 lines
6.7 KiB
PHP
230 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace External\FlexiBeeBundle\Synchronizers;
|
|
|
|
use External\FlexiBeeBundle\Exception\FlexiBeeException;
|
|
use External\FlexiBeeBundle\Util\FlexiBeeApi;
|
|
use External\FlexiBeeBundle\Util\FlexiBeeConfiguration;
|
|
use External\FlexiBeeBundle\Util\FlexiBeeLogger;
|
|
use External\FlexiBeeBundle\Util\FlexiBeeUtil;
|
|
|
|
abstract class BaseSynchronizer implements SynchronizerInterface
|
|
{
|
|
public const MODE_NORMAL = 0;
|
|
public const MODE_FULL = 1;
|
|
|
|
protected static string $type;
|
|
protected static ?string $evidenceClass = null;
|
|
|
|
protected bool $logging = true;
|
|
protected int $mode = self::MODE_NORMAL;
|
|
|
|
protected FlexiBeeLogger $logger;
|
|
protected FlexiBeeConfiguration $configuration;
|
|
protected FlexiBeeApi $flexiBeeApi;
|
|
protected FlexiBeeUtil $flexiBeeUtil;
|
|
|
|
protected ?int $tmpLastSync = null;
|
|
|
|
public function __construct(
|
|
FlexiBeeConfiguration $configuration,
|
|
FlexiBeeApi $flexiBeeApi,
|
|
FlexiBeeUtil $flexiBeeUtil,
|
|
FlexiBeeLogger $logger,
|
|
) {
|
|
$this->configuration = $configuration;
|
|
$this->flexiBeeApi = $flexiBeeApi;
|
|
$this->flexiBeeUtil = $flexiBeeUtil;
|
|
$this->logger = $logger;
|
|
}
|
|
|
|
public static function getType(): string
|
|
{
|
|
return static::$type;
|
|
}
|
|
|
|
public function sync(): void
|
|
{
|
|
$this->process(
|
|
$this->getLastSyncTime()
|
|
);
|
|
|
|
$this->updateLastSyncTime();
|
|
}
|
|
|
|
public function syncSingleItem(int $id, ?int $flexiId = null): void
|
|
{
|
|
throw new FlexiBeeException(sprintf('Single item synchronization is not supported for type "%s"', static::getType()));
|
|
}
|
|
|
|
protected function process(?int $lastSyncTime = null): void
|
|
{
|
|
foreach ($this->getItems($lastSyncTime) as $item) {
|
|
$this->logItem((array) $item);
|
|
$this->processItem($item);
|
|
}
|
|
}
|
|
|
|
abstract protected function processItem(array $item): void;
|
|
|
|
protected function getItems(?int $lastSyncTime = null): iterable
|
|
{
|
|
if (!static::$evidenceClass) {
|
|
throw new FlexiBeeException(
|
|
sprintf('Class "%s" should overwrite "%s" method', get_class($this), __FUNCTION__)
|
|
);
|
|
}
|
|
|
|
// Pokud je nastavena evidence class, tak pro nacteni zmen pouziju ChangesAPI
|
|
|
|
$changesMaxVersion = $this->getLastVersion();
|
|
|
|
// ukladam si startTime, abych mohl limitovat maximalni dobu, kterou muze sync v ramci jednoho sync cyklu bezet
|
|
$startTime = microtime(true);
|
|
|
|
do {
|
|
// nactu si zmeny od posledni synchronizace
|
|
$changes = $this->flexiBeeApi->getChanges($changesMaxVersion, static::$evidenceClass);
|
|
// ulozim si maximalni verzi
|
|
$changesMaxVersion = (int) max($changesMaxVersion, !empty($changes) ? (max(array_map(fn ($x) => $x['@in-version'], $changes)) + 1) : 0);
|
|
// nactu si data podle ID zmen
|
|
$changesIds = array_unique(array_map(fn ($x) => $x['id'], $changes));
|
|
if (!empty($changesIds)) {
|
|
// zavolam preprocess kvuli pripadnym modifikacim dat
|
|
$changedItems = $this->preprocessChangedItems(
|
|
$this->flexiBeeApi->getEvidenceDataByIds(static::$evidenceClass, $changesIds, filters: $this->getItemsFilter())
|
|
);
|
|
// zacnu vracet polozky, aby se v synchronizaci zpracovali
|
|
foreach ($changedItems as $item) {
|
|
yield $item;
|
|
}
|
|
}
|
|
|
|
// aktualizuju si posledni sesynchronizovanou verzi
|
|
$this->updateLastVersion($changesMaxVersion);
|
|
|
|
$isTimedOut = (microtime(true) - $startTime) > 300;
|
|
// pokud sync bezi uz dele jak 5 minut, tak ji ukoncim
|
|
// pravdepodobne ve Flexi vzniklo hodne zmen, tak to postupne syncneme nez blokovat sync na dlouhou dobu
|
|
if ($this->mode === self::MODE_NORMAL && $isTimedOut) {
|
|
break;
|
|
}
|
|
} while (!empty($changes));
|
|
}
|
|
|
|
protected function preprocessChangedItems(array $items): array
|
|
{
|
|
return $items;
|
|
}
|
|
|
|
protected function logItem(array $item): void
|
|
{
|
|
if (!$this->logging) {
|
|
return;
|
|
}
|
|
|
|
$this->logger->data(
|
|
sprintf('[FlexiBee] Processing change of \'%s\'', static::getType()),
|
|
[
|
|
'Data' => $item,
|
|
'Type' => static::getType(),
|
|
]
|
|
);
|
|
}
|
|
|
|
protected function logUpdate(array $item): void
|
|
{
|
|
if (!$this->logging) {
|
|
return;
|
|
}
|
|
|
|
$this->logger->data(
|
|
sprintf('[FlexiBee] Sending to Flexi change of \'%s\'', static::getType()),
|
|
[
|
|
'Data' => $item,
|
|
'Type' => static::getType(),
|
|
]
|
|
);
|
|
}
|
|
|
|
protected function getLastVersion(?string $type = null): int
|
|
{
|
|
if ($this->mode === self::MODE_FULL) {
|
|
return 0;
|
|
}
|
|
|
|
$dbcfg = \Settings::getDefault();
|
|
$flexiBee = $dbcfg->loadValue('flexibee') ?: [];
|
|
|
|
return !empty($flexiBee['sync_versions'][$type ?: static::getType()]) ? (int) $flexiBee['sync_versions'][$type ?: static::getType()] : 0;
|
|
}
|
|
|
|
protected function updateLastVersion(int $version): void
|
|
{
|
|
if ($this->mode === self::MODE_FULL) {
|
|
return;
|
|
}
|
|
|
|
$dbcfg = \Settings::getDefault();
|
|
$flexiBee = $dbcfg->loadValue('flexibee') ?: [];
|
|
|
|
$flexiBee['sync_versions'][static::getType()] = $version;
|
|
|
|
$dbcfg->saveValue('flexibee', $flexiBee);
|
|
}
|
|
|
|
protected function getLastSyncTime(?string $type = null): ?int
|
|
{
|
|
if ($this->mode === self::MODE_FULL) {
|
|
return null;
|
|
}
|
|
|
|
$dbcfg = \Settings::getDefault();
|
|
$flexiBee = $dbcfg->loadValue('flexibee') ?: [];
|
|
|
|
$this->tmpLastSync = time() - (60 * 5);
|
|
|
|
return $flexiBee['timestamps'][$type ?: static::getType()] ?? null;
|
|
}
|
|
|
|
protected function updateLastSyncTime(): void
|
|
{
|
|
if ($this->mode === self::MODE_FULL) {
|
|
return;
|
|
}
|
|
|
|
$dbcfg = \Settings::getDefault();
|
|
$flexiBee = $dbcfg->loadValue('flexibee') ?: [];
|
|
|
|
$flexiBee['timestamps'][static::getType()] = $this->tmpLastSync ?: (time() - (60 * 5));
|
|
|
|
$dbcfg->saveValue('flexibee', $flexiBee);
|
|
}
|
|
|
|
protected function createDateTime(?int $timestamp): ?\DateTime
|
|
{
|
|
if (!$timestamp) {
|
|
return null;
|
|
}
|
|
|
|
$datetime = new \DateTime();
|
|
$datetime->setTimestamp($timestamp);
|
|
|
|
return $datetime;
|
|
}
|
|
|
|
public function setMode(int $mode): self
|
|
{
|
|
$this->mode = $mode;
|
|
|
|
return $this;
|
|
}
|
|
|
|
protected function getItemsFilter(): array
|
|
{
|
|
return [];
|
|
}
|
|
}
|