feat(command): add command for refresh database
This commit is contained in:
148
src/Command/RefreshDatabaseCommand.php
Normal file
148
src/Command/RefreshDatabaseCommand.php
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user