Skip to content

Commit

Permalink
[BUGFIX] Fix multiple errors that occur when calling publishRecordTre…
Browse files Browse the repository at this point in the history
…e more than once
  • Loading branch information
vertexvaar committed Nov 15, 2023
1 parent d797f74 commit 84a1c8b
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 53 deletions.
76 changes: 52 additions & 24 deletions Classes/Component/Core/Publisher/AbstractFilesystemPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,75 @@

use function bin2hex;
use function get_class;
use function implode;
use function json_encode;
use function random_bytes;

abstract class AbstractFilesystemPublisher implements Publisher, FinishablePublisher
use const JSON_THROW_ON_ERROR;

abstract class AbstractFilesystemPublisher implements Publisher, TransactionalPublisher, ReversiblePublisher
{
use ForeignDatabaseReconnectedInjection;
use RemoteCommandDispatcherInjection;

protected string $requestToken;
protected array $instructions = [];

public function __construct()
public function start(): void
{
if (!$this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->beginTransaction();
}
}

public function cancel(): void
{
$this->requestToken = bin2hex(random_bytes(16));
if ($this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->rollBack();
}
}

public function reverse(): void
{
if ($this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->rollBack();
}
}

public function finish(): void
{
if (!empty($this->instructions)) {
$instructions = $this->instructions;
$this->instructions = [];
$data = [];
foreach ($instructions as $instruction) {
$class = get_class($instruction);
$configuration = json_encode($instruction->getConfiguration(), JSON_THROW_ON_ERROR);
$data[] = [
'request_token' => $this->requestToken,
'crdate' => $GLOBALS['EXEC_TIME'],
'tstamp' => $GLOBALS['EXEC_TIME'],
'instruction' => $class,
'configuration' => $configuration,
];
if (empty($this->instructions)) {
if ($this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->commit();
}
return;
}

$this->foreignDatabase->bulkInsert('tx_in2publishcore_filepublisher_instruction', $data);
$requestTokens = [];
$instructions = $this->instructions;
$this->instructions = [];
$data = [];
foreach ($instructions as $instruction) {
$requestTokens[] = $requestToken = bin2hex(random_bytes(16));
$class = get_class($instruction);
$configuration = json_encode($instruction->getConfiguration(), JSON_THROW_ON_ERROR);
$data[] = [
'request_token' => $requestToken,
'crdate' => $GLOBALS['EXEC_TIME'],
'tstamp' => $GLOBALS['EXEC_TIME'],
'instruction' => $class,
'configuration' => $configuration,
];
}

$request = new RemoteCommandRequest('in2publish_core:core:falpublisher', [], [$this->requestToken]);
$response = $this->remoteCommandDispatcher->dispatch($request);
if (!$response->isSuccessful()) {
throw new FalPublisherExecutionFailedException($response);
}
$this->foreignDatabase->bulkInsert('tx_in2publishcore_filepublisher_instruction', $data);
if ($this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->commit();
}

$request = new RemoteCommandRequest('in2publish_core:core:falpublisher', [], [implode(',', $requestTokens)]);
$response = $this->remoteCommandDispatcher->dispatch($request);
if (!$response->isSuccessful()) {
throw new FalPublisherExecutionFailedException($response);
}
}
}
14 changes: 11 additions & 3 deletions Classes/Component/Core/Publisher/Command/FalPublisherCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace In2code\In2publishCore\Component\Core\Publisher\Command;

use Doctrine\DBAL\ArrayParameterType;
use In2code\In2publishCore\CommonInjection\LocalDatabaseInjection;
use In2code\In2publishCore\Component\Core\DemandResolver\Filesystem\Service\FalDriverServiceInjection;
use In2code\In2publishCore\Component\Core\Publisher\Instruction\PublishInstruction;
Expand All @@ -13,6 +14,7 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

use function explode;
use function json_decode;

class FalPublisherCommand extends Command
Expand All @@ -28,17 +30,23 @@ public function isEnabled(): bool

protected function configure(): void
{
$this->addArgument('requestToken', InputArgument::REQUIRED);
$this->addArgument('requestTokens', InputArgument::REQUIRED);
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$requestToken = $input->getArgument('requestToken');
$requestTokens = $input->getArgument('requestTokens');
$requestTokens = explode(',', $requestTokens);

$query = $this->localDatabase->createQueryBuilder();
$query->select('*')
->from('tx_in2publishcore_filepublisher_instruction')
->where($query->expr()->eq('request_token', $query->createNamedParameter($requestToken)));
->where(
$query->expr()->in(
'request_token',
$query->createNamedParameter($requestTokens, ArrayParameterType::STRING)
)
);
$result = $query->executeQuery();
$rows = $result->fetchAllAssociative();

Expand Down
7 changes: 5 additions & 2 deletions Classes/Component/Core/Publisher/DatabaseRecordPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
namespace In2code\In2publishCore\Component\Core\Publisher;

use In2code\In2publishCore\CommonInjection\ForeignDatabaseInjection;
use In2code\In2publishCore\CommonInjection\ForeignDatabaseReconnectedInjection;
use In2code\In2publishCore\Component\Core\Record\Model\AbstractDatabaseRecord;
use In2code\In2publishCore\Component\Core\Record\Model\Record;

use function array_diff_assoc;

class DatabaseRecordPublisher implements Publisher, TransactionalPublisher
{
use ForeignDatabaseInjection;
use ForeignDatabaseReconnectedInjection;

public function canPublish(Record $record): bool
{
Expand Down Expand Up @@ -43,7 +44,9 @@ public function publish(Record $record)

public function start(): void
{
$this->foreignDatabase->beginTransaction();
if (!$this->foreignDatabase->isTransactionActive()) {
$this->foreignDatabase->beginTransaction();
}
}

public function cancel(): void
Expand Down
35 changes: 34 additions & 1 deletion Classes/Component/Core/Publisher/FileRecordPublisher.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@
use In2code\In2publishCore\Component\Core\Publisher\Instruction\ReplaceFileInstruction;
use In2code\In2publishCore\Component\Core\Record\Model\FileRecord;
use In2code\In2publishCore\Component\Core\Record\Model\Record;
use In2code\In2publishCore\Component\RemoteCommandExecution\RemoteCommandDispatcher;
use In2code\In2publishCore\Component\RemoteCommandExecution\RemoteCommandDispatcherInjection;
use In2code\In2publishCore\Component\RemoteCommandExecution\RemoteCommandRequest;
use In2code\In2publishCore\Component\TemporaryAssetTransmission\AssetTransmitterInjection;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerAwareTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class FileRecordPublisher extends AbstractFilesystemPublisher
class FileRecordPublisher extends AbstractFilesystemPublisher implements LoggerAwareInterface
{
use AssetTransmitterInjection;
use FalDriverServiceInjection;
use RemoteCommandDispatcherInjection;
use LoggerAwareTrait;

/** @var array<string> */
protected array $transmittedFiles = [];

public function canPublish(Record $record): bool
{
Expand Down Expand Up @@ -72,6 +83,7 @@ public function publish(Record $record): void
);
} else {
$transmitTemporaryFile = $this->transmitTemporaryFile($record);
$this->transmittedFiles[] = $transmitTemporaryFile;
$instruction = new ReplaceAndRenameFileInstruction(
$storage,
$foreignFileIdentifier,
Expand All @@ -81,6 +93,7 @@ public function publish(Record $record): void
}
} else {
$transmitTemporaryFile = $this->transmitTemporaryFile($record);
$this->transmittedFiles[] = $transmitTemporaryFile;
$instruction = new ReplaceFileInstruction(
$storage,
$localFileIdentifier,
Expand All @@ -102,4 +115,24 @@ protected function transmitTemporaryFile(Record $record): string
$localFile = $driver->getFileForLocalProcessing($identifier);
return $this->assetTransmitter->transmitTemporaryFile($localFile);
}

/**
* Only a partial reverse. Will not un-publish files that have already been processed on foreign.
*/
public function reverse(): void
{
$options = [];
$options[] = '-f';
foreach ($this->transmittedFiles as $transmittedFile) {
$options[] = $transmittedFile;
}
$request = new RemoteCommandRequest('rm', [], $options);
$response = $this->remoteCommandDispatcher->dispatch($request);
if ($response->isSuccessful()) {
$this->logger->alert(
'Removing temporary files during rollback failed',
['output' => $response->getOutput(), 'error' => $response->getErrors()],
);
}
}
}
37 changes: 14 additions & 23 deletions Classes/Component/Core/Publisher/PublisherService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use In2code\In2publishCore\Component\Core\Record\Model\Record;
use In2code\In2publishCore\Component\Core\RecordTree\RecordTree;
use In2code\In2publishCore\Component\PostPublishTaskExecution\Service\TaskExecutionService;
use In2code\In2publishCore\Component\PostPublishTaskExecution\Service\TaskExecutionServiceInjection;
use In2code\In2publishCore\Event\PublishingOfOneRecordBegan;
use In2code\In2publishCore\Event\PublishingOfOneRecordEnded;
use In2code\In2publishCore\Event\RecordWasPublished;
Expand All @@ -19,24 +20,20 @@
class PublisherService
{
use EventDispatcherInjection;
use TaskExecutionServiceInjection;

protected PublisherCollection $publisherCollection;
protected TaskExecutionService $taskExecutionService;
/** @var array<string, array<int, true>> */
protected array $visitedRecords = [];

public function __construct()
{
$this->publisherCollection = new PublisherCollection();
}

/**
* @codeCoverageIgnore
* @noinspection PhpUnused
* Called by the DI container when constructing this service
*/
public function injectTaskExecutionService(TaskExecutionService $taskExecutionService): void
{
$this->taskExecutionService = $taskExecutionService;
}

public function addPublisher(Publisher $publisher): void
{
$this->publisherCollection->addPublisher($publisher);
Expand All @@ -55,10 +52,9 @@ public function publishRecordTree(RecordTree $recordTree, bool $includeChildPage
$this->publisherCollection->start();

try {
$visitedRecords = [];
foreach ($recordTree->getChildren() as $records) {
foreach ($records as $record) {
$this->publishRecord($record, $visitedRecords, $includeChildPages);
$this->publishRecord($record, $includeChildPages);
}
}
} catch (Throwable $exception) {
Expand All @@ -79,15 +75,15 @@ public function publishRecordTree(RecordTree $recordTree, bool $includeChildPage
$this->taskExecutionService->runTasks();
}

protected function publishRecord(Record $record, array &$visitedRecords = [], bool $includeChildPages = false): void
protected function publishRecord(Record $record, bool $includeChildPages = false): void
{
$classification = $record->getClassification();
$id = $record->getId();

if (isset($visitedRecords[$classification][$id])) {
if (isset($this->visitedRecords[$classification][$id])) {
return;
}
$visitedRecords[$classification][$id] = true;
$this->visitedRecords[$classification][$id] = true;

$this->eventDispatcher->dispatch(new RecordWasSelectedForPublishing($record));

Expand All @@ -106,16 +102,11 @@ protected function publishRecord(Record $record, array &$visitedRecords = [], bo
}

foreach ($record->getChildren() as $table => $children) {
if ('pages' !== $table) {
foreach ($children as $child) {
$this->publishRecord($child, $visitedRecords, true);
}
} else {
if ($includeChildPages === true) {
foreach ($children as $child) {
$this->publishRecord($child, $visitedRecords, true);
}
}
if ('pages' === $table && !$includeChildPages) {
continue;
}
foreach ($children as $child) {
$this->publishRecord($child, true);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace In2code\In2publishCore\Component\PostPublishTaskExecution\Service;

/**
* @codeCoverageIgnore
*/
trait TaskExecutionServiceInjection
{
protected TaskExecutionService $taskExecutionService;

/**
* @noinspection PhpUnused
*/
public function injectTaskExecutionService(TaskExecutionService $taskExecutionService): void
{
$this->taskExecutionService = $taskExecutionService;
}
}
4 changes: 4 additions & 0 deletions Configuration/Component/Core/Services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ services:

In2code\In2publishCore\Component\Core\DemandResolver\DemandResolver:
factory: [ '@In2code\In2publishCore\Component\Core\DemandResolver\DemandResolverFactory', 'createDemandResolver' ]

In2code\In2publishCore\Component\Core\Publisher\PublisherService:
public: true
shared: true

0 comments on commit 84a1c8b

Please sign in to comment.