Мне нужны отзывы о том, как правильно выполнить команду, которая импортирует содержимое CSV в базу данных mysql в соответствии с этим сценарием:
Файл CSV содержит один порядок.
Как только заказ завершен, CSV загружается через sFTP на мой сервер.Может случиться так, что несколько CSV могут быть загружены в течение минуты.
Команда будет:
- извлечь все файлы CSV в определенном каталоге
- проанализировать каждый из них
- сделать простой
INSERT
SQL-запрос - удалить файл, если запрос выполнен успешно, или переместить файл в случае любого выданного исключения
Я думал о2 решения:
- задача cron, которая запускает команду каждые 15 минут
- использование
inotify-tools
библиотека
Что касается второго решения, у меня есть несколькоСомнения в случае, когда я выполняю свою команду каждый раз, когда файл создается в папке.Представьте, что есть несколько загруженных файлов с очень коротким интервалом.Не думаете ли вы, что во время выполнения команды могут возникнуть конфликты?
Как вы думаете?
Вот команда symfony:
<?php
namespace AppBundle\Command;
use AppBundle\Model\Entity\Consts\DeliveryNoteFlowOrigin;
use AppBundle\Model\Entity\Consts\DeliveryNoteStatus;
use Doctrine\DBAL\Driver\Connection;
use Doctrine\DBAL\Driver\PDOException;
use League\Csv\Reader;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
class ImportCsvCommand extends ContainerAwareCommand
{
/**
* @var Connection
*/
private $dbal;
/**
* @var string
*/
private $uploadCsv;
/**
* @var string
*/
private $backupCsv;
public function __construct(
Connection $dbal,
string $uploadCsv,
string $backupCsv
) {
$this->dbal = $dbal;
$this->uploadCsv = $uploadCsv;
$this->backupCsv = $backupCsv;
parent::__construct();
}
/**
* {@inheritdoc}
*/
protected function configure()
{
$this
->setName('app:store:csv')
->setDescription('Create delivery notes from CSV.')
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$io->title('Attempting import of CSV files...');
$finder = new Finder();
$finder->files()->name('*.csv')->in($this->uploadCsv);
// Warning: If your CSV document is read on a Macintosh computer,
// add the following lines before using the library to help PHP detect line ending.
// (\r line endings are created by Microsoft Excel when saving as a CSV file)
if (!ini_get('auto_detect_line_endings')) {
ini_set('auto_detect_line_endings', '1');
}
foreach ($finder as $file) {
$csv = Reader::createFromPath($file->getRealPath())
->setHeaderOffset(0)
;
// TODO check memory leak
foreach ($csv as $order) {
dump($order);
die();
try {
$this->importDeliveryNote($file, $order);
} catch (PDOException $PDOException) {
// TODO log
} catch (IOExceptionInterface $IOException) {
// TODO log
} catch (\Exception $exception) {
// TODO log
}
}
}
$io->success('Command exited cleanly!');
}
private function importDeliveryNote(SplFileInfo $file, array $order): void
{
$fileSystem = new Filesystem();
$filename = $file->getFilename();
$fileRealPath = $file->getRealPath();
$now = (new \DateTime('now'))->format('Y-m-d H:i:s');
$sth = $this->dbal->prepare(
'INSERT INTO delivery_note (status, seller_name, first_name, last_name, email) VALUES (:status, :sellerName, :firstname, :lastname, :email)'
);
//Do not forget to validate your data before inserting it in your database
$sth->bindValue(':status', $order['TODO'], DeliveryNoteStatus::PREPARED);
$sth->bindValue(':sellerName', $order['TODO'], \PDO::PARAM_STR);
$sth->bindValue(':firstname', $order['TODO'], \PDO::PARAM_STR);
$sth->bindValue(':lastname', $order['TODO'], \PDO::PARAM_STR);
$sth->bindValue(':email', $order['TODO'], \PDO::PARAM_STR);
$queryHasBeenSuccessful = $sth->execute();
if ($queryHasBeenSuccessful) {
$fileSystem->remove($fileRealPath);
} else {
// Move to backup directory
$newPathname = $this->backupCsv.$filename;
if (!$fileSystem->exists($newPathname)) {
$fileSystem->rename($file->getPathname(), $newPathname);
}
}
}
}