feat(command): add command for refresh database

This commit is contained in:
2024-08-02 14:47:23 +02:00
parent 31155efabe
commit 58f43f096a
11 changed files with 404 additions and 1 deletions

View File

@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
namespace App\Command;
use App\Entity\Database\Comments\Comment;
use App\Entity\Database\Posts\Post;
use App\Entity\Database\Users\User;
use App\Repository\Users\CompanyRepository;
use App\Service\Persist\RemoteCommentConvertor;
use App\Service\Persist\RemotePostsConvertor;
use App\Service\Persist\RemoteUsersConvertor;
use App\Service\Remote\BriloApiComments;
use App\Service\Remote\BriloApiPosts;
use App\Service\Remote\BriloApiUsers;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\SharedLockInterface;
/**
* Download new data from Brilo API and import it into the database.
*/
final class RefreshDatabaseCommand extends Command
{
private readonly SharedLockInterface $lock;
public function __construct(
?string $name,
private readonly BriloApiComments $remoteComments,
private readonly BriloApiPosts $remotePosts,
private readonly BriloApiUsers $remoteUsers,
private readonly LoggerInterface $logger,
private readonly RemoteUsersConvertor $remoteUsersConvertor,
private readonly RemotePostsConvertor $remotePostsConvertor,
private readonly RemoteCommentConvertor $remoteCommentsConvertor,
private readonly CompanyRepository $companyRepository,
private readonly EntityManagerInterface $em,
LockFactory $lock,
) {
$this->lock = $lock->createLock('refresh-database');
parent::__construct($name);
}
protected function configure(): void
{
$this->setHelp('Refresh the database from the Brilo API');
$this->setDescription('Import new data from Brilo API and import it into the database.');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->lock->acquire(true);
try {
return $this->runImport();
} finally {
$this->lock->release();
}
}
/**
* @return int
* @throws \Exception
*/
private function runImport(): int
{
$returnCode = 0;
// First import users, then posts and finally comments
$data = $this->remoteUsersConvertor->convert($this->remoteUsers->getUsers());
$code = $this->runGeneratorInTransaction($data, function (User $user) {
$this->logger->info("Processing user: {$user->id}");
$this->em->persist($user->address);
$this->em->persist($user->company);
$this->em->persist($user);
});
if ($code != 0) {
$returnCode = 1;
}
$data = $this->remotePostsConvertor->convert($this->remotePosts->getPosts());
$code = $this->runGeneratorInTransaction($data, function (Post $post) {
$this->logger->info("Processing post: {$post->id}");
$this->em->persist($post);
});
if ($code != 0) {
$returnCode = 1;
}
$data = $this->remoteCommentsConvertor->convert($this->remoteComments->getComments());
$code = $this->runGeneratorInTransaction($data, function (Comment $comment) {
$this->logger->info("Processing comment: {$comment->id}");
$this->em->persist($comment);
});
if ($code != 0) {
$returnCode = 1;
}
$this->companyRepository->deleteOrphanRecords();
$this->logger->info("Refreshing database completed");
return $returnCode;
}
/**
* Run every yielded item from generator in separate transaction and call $callback with item from generator
* @param \Generator $data
* @param callable $callback
* @return int
*/
private function runGeneratorInTransaction(\Generator $data, callable $callback): int
{
$returnCode = 0;
while ($data->valid()) { /* normalni foreach nepouzivam kvuli microtranskaci ...
v tomhle pripade mi prijde lepsi mit v databazi neco nez nic (nebo stara data) v pripade jakekoliv chyby,
navic "velke" transkace nejsou dobre pro databazi a tohle je api 3-ti strany...
ale finalni slovo by mel mit zadavatel, ktereho "nemam" */
$this->em->beginTransaction();
try {
$callback($data->current());
$this->em->flush();
$this->em->commit();
} catch (\Exception $e) {
$returnCode = 1;
$this->em->rollback();
$this->logger->error("Database transaction failed", ['exception' => $e]);
continue;
} finally {
$data->next();
}
}
return $returnCode;
}
}

View File

@@ -9,6 +9,7 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* In case of deleting records, you must modify RefreshDatabaseCommand transaction logic
* @extends ServiceEntityRepository<Post>
*/
class PostRepository extends ServiceEntityRepository

View File

@@ -9,6 +9,7 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* In case of deleting records, you must modify RefreshDatabaseCommand transaction logic
* @extends ServiceEntityRepository<Company>
*/
class CompanyRepository extends ServiceEntityRepository

View File

@@ -9,6 +9,7 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* In case of deleting records, you must modify RefreshDatabaseCommand transaction logic
* @extends ServiceEntityRepository<User>
*/
class UserRepository extends ServiceEntityRepository