Files
kupshop/bundles/External/VarioBundle/Synchronizers/BaseSynchronizer.php
2025-08-02 16:30:27 +02:00

296 lines
8.3 KiB
PHP

<?php
namespace External\VarioBundle\Synchronizers;
use External\VarioBundle\Exception\SynchronizerException;
use External\VarioBundle\SoapClient;
use External\VarioBundle\Util\VarioConfig;
use External\VarioBundle\Util\VarioHelper;
use Psr\Log\LoggerInterface;
use Query\QueryBuilder;
abstract class BaseSynchronizer implements SynchronizerInterface
{
use \DatabaseCommunication;
/** @var string */
protected static $type;
/** @var int */
protected static $batch = 100;
/** @var int|null Repeat batch and after repeats set data as done */
protected static $batchRepeat;
/** @var int|null How many batches can be handled in one request? */
protected static $maxBatches = 8;
/** @var bool Ends synchronization after first batch process */
protected $forceEnd = false;
/** @var array [syncField => syncMethod without suffix] */
protected $fields;
/** @var bool */
protected $debug = true;
/** @var bool */
protected $logging = true;
protected $client;
protected $helper;
protected $config;
protected $logger;
private $changedItems = [];
protected $forceSyncID;
public function __construct(
SoapClient $client,
VarioHelper $helper,
VarioConfig $config,
LoggerInterface $logger,
) {
$this->client = $client;
$this->helper = $helper;
$this->config = $config;
$this->logger = $logger;
}
public static function getType()
{
return static::$type;
}
public function setForceSync(?string $id)
{
$this->forceSyncID = $id;
}
/**
* @throws SynchronizerException
*/
public function getEshopID($objectID)
{
throw new SynchronizerException(
sprintf('Class %s should overwrite getEshopID($objectID) method.', get_class($this))
);
}
public function syncDelete($eshopID)
{
}
public function sync()
{
if (!is_array($this->fields)) {
throw new SynchronizerException(
sprintf('Class %s should overwrite $fields attribute.', get_class($this))
);
}
$this->writeLine('Starting type '.static::getType());
$loop = 0;
$batchRepeat = false;
$forceEndOriginal = $this->forceEnd;
do {
// fetch data
if ($forceSync = getVal('force_sync', null, $this->forceSyncID)) {
$this->writeLine(sprintf('Force fetching %s...', $forceSync));
if ($forceSync == 'ALL') {
$items = function () {
$qb = $this->getSyncAllObjects();
if ($qb instanceof QueryBuilder) {
if ($start = getVal('start')) {
$qb->andWhere('id_vario >= :start')
->setParameter('start', $start);
}
$data = $qb->execute();
} else {
$data = $qb;
}
foreach ($data as $row) {
$this->writeLine($row['id_vario'] ?? $row);
foreach ($this->client->forceObjectData(static::getType(), $row['id_vario'] ?? $row) as $item) {
yield $item;
}
}
};
$items = $items();
} else {
$items = $this->client->forceObjectData(static::getType(), $forceSync);
}
$this->forceEnd = true;
} else {
$this->writeLine('Fetching...');
if ($batchRepeat === false) {
$items = $this->client->getJobsData(static::getType(), static::$batch);
}
if (empty($items) && $loop == 0) {
$this->writeLine('No changes to fetch');
break;
}
}
$this->writeLine('Processing...');
// preprocess items
$this->preprocess($items);
$doneJobs = [];
// process data
foreach ($items as $item) {
// log change
$this->logItem($item);
$objectID = $this->getObjectID($item);
$eshopID = $objectID ? $this->getEshopID($objectID) : null;
if (!$eshopID) {
if ($eshopID === null) {
$doneJobs[] = $item->Job->ID;
}
continue;
}
// delete action
if ($item->Job->Action == 'acDelete') {
$this->syncDelete($eshopID);
$doneJobs[] = $item->Job->ID;
continue;
}
foreach ($item->Data as $column => $value) {
// not defined = ignore
if (!isset($this->fields[$column])) {
continue;
}
if (getVal('onlyColumn') && getVal('onlyColumn') != $column) {
continue;
}
$method = 'sync'.ucfirst($this->fields[$column]);
if (!method_exists($this, $method)) {
throw new SynchronizerException(
sprintf('Method %s() for synchronizer type \'%s\' is not defined!', $method, static::getType())
);
}
call_user_func_array([$this, $method], [$value, $eshopID, $column, $item]);
}
// this is needed in sections sync for example (to create tree structure correctly)
$batchRepeat = true;
if (static::$batchRepeat === null || (($loop % static::$batchRepeat == 0) && $loop != 0)) {
$doneJobs[] = $item->Job->ID;
$batchRepeat = false;
}
}
$doneJobs = array_filter($doneJobs);
if (!empty($doneJobs)) {
$this->client->setJobsDone($doneJobs);
}
if (static::$maxBatches !== null && static::$maxBatches <= $loop) {
$this->forceEnd = true;
}
$loop++;
} while (is_countable($items) && count($items) > 0 && $this->forceEnd == false);
$this->postprocess();
if ($forceSync) {
$this->forceEnd = $forceEndOriginal;
}
$this->writeLine('Ended type '.static::getType());
}
protected function preprocess($items)
{
}
protected function postprocess()
{
}
protected function getObjectID($item)
{
return $item->Job->ObjectID;
}
protected function logItem($item)
{
if (isDevelopment()) {
return;
}
if (!$this->logging) {
return;
}
$this->logger->notice(
sprintf('VARIO: Processing change of \'%s\', ObjectID: %s', static::getType(), $item->Job->ObjectID),
[
'Job' => (array) $item->Job,
'Data' => (array) $item->Data,
'Type' => static::getType(),
]
);
}
protected function addChangedItem($identifier)
{
$this->changedItems[static::getType()][] = $identifier;
}
protected function getChangedItems($type = null)
{
if ($type === null) {
return $this->changedItems;
}
if (isset($this->changedItems[static::getType()])) {
return $this->changedItems[static::getType()];
}
return [];
}
/**
* Write text to output.
*/
protected function writeLine(string $text)
{
if (!$this->debug) {
return;
}
echo $text.'<br>';
flush();
}
public function setDebug(bool $bool)
{
$this->debug = $bool;
}
/**
* @return QueryBuilder
*/
protected function getSyncAllObjects()
{
throw new \Exception('Not implemented');
}
public function prepareVarioID($id): string
{
if (empty($id)) {
return '';
}
return '{'.$id.'}';
}
}