Импорт нескольких файлов CSV в базу данных после загрузки в каталог - PullRequest
0 голосов
/ 20 мая 2018

Мне нужны отзывы о том, как правильно выполнить команду, которая импортирует содержимое CSV в базу данных mysql в соответствии с этим сценарием:

Файл CSV содержит один порядок.

Как только заказ завершен, CSV загружается через sFTP на мой сервер.Может случиться так, что несколько CSV могут быть загружены в течение минуты.

Команда будет:

  1. извлечь все файлы CSV в определенном каталоге
  2. проанализировать каждый из них
  3. сделать простой INSERT SQL-запрос
  4. удалить файл, если запрос выполнен успешно, или переместить файл в случае любого выданного исключения

Я думал о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);
            }
        }
    }
}
...