<?php
namespace App\ManualMigrations\Migrations\MigrateNotesFiles;
use App\AsyncTask\Service\LegacyBridge\AsyncTaskLegacyHandler;
use App\AsyncTask\Service\TaskHandler\AbstractAsyncTaskHandler;
use App\AsyncTask\Service\TaskHandler\AsyncTaskBatchItem;
use App\Data\Entity\Record;
use App\Data\LegacyHandler\PreparedStatementHandler;
use App\Engine\Model\Feedback;
use App\MediaObjects\Repository\MediaObjectManagerInterface;
use App\MediaObjects\Services\LocalFileMediaObjectMigratorInterface;
use Psr\Log\LoggerInterface;
class MigrateNotesFilesTaskHandler extends AbstractAsyncTaskHandler
{
public function __construct(
protected AsyncTaskLegacyHandler $legacyHandler,
protected PreparedStatementHandler $preparedStatementHandler,
protected MediaObjectManagerInterface $mediaObjectManager,
protected LocalFileMediaObjectMigratorInterface $migrator,
protected LoggerInterface $logger
) {
}
public function getHandlerKey(): string
{
return 'migrate-notes-files';
}
public function getType(): string
{
return 'manual-migration-tasks';
}
public function getNextBatchToQueue(
Record $task,
array $progress,
int $batchSize
): array {
$offset = $progress['enqueue_offset'] ?? 0;
try {
$qb = $this->preparedStatementHandler->createQueryBuilder();
$qb->select('id', 'filename', 'file_mime_type')
->from('notes')
->where('filename IS NOT NULL')
->andWhere("filename != ''")
->andWhere('deleted = 0')
->setFirstResult($offset)
->setMaxResults($batchSize);
$results = $qb->executeQuery()->fetchAllAssociative();
} catch (\Throwable $e) {
$this->logger->error(
'MigrateNotesFilesTaskHandler::getNextBatchToQueue failed: '
. $e->getMessage(),
['component' => 'migrate-notes-files']
);
return [];
}
$items = [];
foreach ($results as $row) {
$items[] = new AsyncTaskBatchItem(
$row['id'],
[
'record_id' => $row['id'],
'filename' => $row['filename'],
'file_mime_type' => $row['file_mime_type']
?? 'application/octet-stream',
]
);
}
return $items;
}
public function processItem(Record $task, array $item): Feedback
{
$feedback = new Feedback();
$data = $item['data'] ?? [];
$recordId = $data['record_id'] ?? '';
$filename = $data['filename'] ?? '';
$mimeType = $data['file_mime_type'] ?? 'application/octet-stream';
if (empty($recordId) || empty($filename)) {
return $feedback->setSuccess(false)
->setMessages(['Missing record_id or filename']);
}
$this->legacyHandler->startLegacy();
try {
$legacyDir = $this->legacyHandler->getLegacyDir();
$legacyPath = $legacyDir . '/upload/' . $recordId;
// Check if already migrated
$existing = $this->mediaObjectManager->getLinkedMediaObjects(
'private-documents',
'Notes',
$recordId,
'file'
);
if (!empty($existing)) {
// Clean up legacy file if it still exists
if (file_exists($legacyPath)) {
unlink($legacyPath);
}
return $feedback->setSuccess(true)
->setMessages(['Already migrated']);
}
if (!file_exists($legacyPath)) {
return $feedback->setSuccess(false)
->setMessages(['Legacy file not found: upload/' . $recordId]);
}
// Perform the migration
$record = $this->migrator->migrate(
$legacyPath,
'private-documents',
$mimeType,
$filename,
$filename,
'Notes',
$recordId,
'file'
);
$feedback->setSuccess(true);
$feedback->setData(['media_object_id' => $record?->getId()]);
} catch (\Throwable $e) {
$this->logger->error(
'MigrateNotesFilesTaskHandler::processItem failed: '
. $e->getMessage(),
[
'component' => 'migrate-notes-files',
'record_id' => $recordId,
]
);
$feedback->setSuccess(false)->setMessages([$e->getMessage()]);
} finally {
$this->legacyHandler->stopLegacy();
}
return $feedback;
}
}