ParserController.php 11.9 KB
<?php
namespace console\controllers;

use common\components\archives\ArchiveCreator;
use common\components\CustomVarDamp;
use common\components\mail\ImapMailReader;
use common\components\mail\MailAttachmentsSaver;
use yii\console\Controller;
use yii\helpers\Console;
use common\components\PriceWriter;
use backend\models\ImportersFiles;
use backend\models\Importers;
use yii\base\ErrorException;

class ParserController extends Controller
{
    public function actionParseCsv()
    {
        \Yii::info('Начало загрузки файлов прайсов csv', 'parser');
        foreach (glob(\Yii::getAlias('@auto_upload') . '/*.csv') as $file_path) {
            $file_name = basename($file_path, ".csv");
            \Yii::info("Обработка файла - $file_path", 'parser');
            $importer_id = ImportersFiles::findOne(['id' => $file_name])->importer_id;
            $current_importer = Importers::findOne(['id' => $importer_id]);
            $keys = $current_importer->keys;
            $mult_array = $current_importer->multiply;

            // получим настройки ценообразования и передадим их отдельно в конвертер
            $sign = '';
            $multiplier = '';
            extract( $mult_array );


            $config = ['record_id' => $file_name,
                'importer_id' => $importer_id,
                'parser_config' => ['keys' => $keys,
                    'converter_conf' =>
                    ['sign' => $sign,
                    'multiplier' => $multiplier],
                    'mode' => 'console']
            ];
            if ($this->parseFileConsole($file_path, $config)) {
                unlink(\Yii::getAlias('@temp_upload') . '/' . $file_name . '.csv');
                \Yii::info("Загрузка файла - $file_path успешно завершена", 'parser');
            } else {
                \Yii::error("Загрузка файла - $file_path завершена с ошибкой", 'parser');
            }
            //при любом завершении скрипта файл с очереди автозагрузки нужно удалить
            unlink(\Yii::getAlias('@auto_upload') . '/' . $file_name . '.csv');
        }

    }


    protected function parseFileConsole( $file_path, $configuration ){

        if( !file_exists( $file_path ) )
            throw new ErrorException("$file_path - файл не найден!");

        $parser_config = [];
        if ( isset( $configuration['parser_config'] ) ) {
            $parser_config = $configuration['parser_config'];
        }
        $data = \Yii::$app->multiparser->parse( $file_path, $parser_config );
        if ( ! $data ) {
            throw new ErrorException("Ошибка обработки файла прайса!");
        }

        $writer = new PriceWriter();
        $writer->configuration = $configuration;
        $writer->data = $data;
        $writer->mode = 1; //console-режим

        if ( $writer->writeDataToDB() ){

            return true;
        }

        return false;
    }

    public function actionParseXml ()
    {
         \Yii::info('Начало загрузки файлов прайсов xml', 'parser');
        foreach (glob(\Yii::getAlias('@auto_upload') . '/*.xml') as $file_path) {
            $file_name = basename($file_path, ".xml");
                  \Yii::info("Обработка файла - $file_path", 'parser');

            $files_model = new ImportersFiles();
            // id поставщика всегда = 1 - Склад
            $files_model->importer_id = 1;
            try {
                $files_model->save();
            } catch (ErrorException  $e) {
                throw $e;
            }
            // получим id только что записанной записи
            $record_id = $files_model->find()
                ->where(['importer_id' => $files_model->importer_id])
                ->orderBy(['id' => SORT_DESC])
                ->one()
                ->id;

            $config = ['record_id' => $record_id,
                'importer_id' => 1,
                'parser_config' => [
                    'mode' => 'console']
            ];

            if ($this->parseFileConsole($file_path, $config)) {
                //unlink(\Yii::getAlias('@auto_upload') . '/' . $file_name . '.xml');
                        \Yii::info("Загрузка файла - $file_path успешно завершена", 'parser');
            } else {
                        \Yii::error("Загрузка файла - $file_path завершена с ошибкой", 'parser');
            }
        }
    }

    public function actionTest()
    {
        Console::output('It is working');
        \Yii::info('2', 'parser');

    }

    public function actionSaveMailAttachments()
    {
        \Yii::info('Начало сохранения файлов почты', 'mail');

        // получим разделитель для файлов поставщика
        $importer_id_prefix = ImportersFiles::FILES_PREFIX;
        // подключимся к ящику
        $mail_reader = new ImapMailReader( '{imap.gmail.com:993/imap/ssl/novalidate-cert}', 'tsurkanovm@gmail.com', 'Wtvr@2000' );

        // 1. получим все вложения
        \Yii::info('Начало сохранения файлов почты', 'mail');
        $files = $this->getMailAttachments( $mail_reader, $importer_id_prefix );

        if ( !$files ) {
            // нет файлов в ящиках (не было вложений в письмах)
            \Yii::warning('Вложений не найдено', 'mail');
            return;
        }

        // 2. если в вложениях есть архивы - распакуем их и дополним итоговый массив
        \Yii::info('Запуск распаковки архивов...', 'mail');
        $this->UnpackFiles( $files );


        // 3. переименуем, зарегистрируем прайсы и перенесем извлеченные файлы
        // укажем папку куда нужно перенести все извлеченные вложения
        \Yii::info('Запуск перемещения и регистрации прайсов...', 'mail');
        $new_destination = \Yii::getAlias('@auto_upload')  . '/';

        $this->registerAndReplaceFiles( $files, $new_destination );


    }

    private function getMailAttachments ($mail_reader, $importer_id_prefix = '')
    {
        // получим все внутренние ящики (по ярлыкам)
        $mailboxes = $mail_reader->getListMailboxes();
        // очистим массив в котором в итоге окажуться все файлы вложений, а также распакованные файлы из архивов
        $files = [];
        foreach ( $mailboxes as $custom_label ) {
            // получим поставщика исходя из маски ярлыка
            $importer_id = ImportersFiles::getIdFromMailBox( $mail_reader->getHostname(), $custom_label );

            // читаем письма конкретного ярлыка
            $mail_reader->reOpen( $custom_label );
            // создадим сейвер вложений для данного ярлыка (ящика)
            $saver = new MailAttachmentsSaver( $mail_reader );
            // если данный ярлык содержит id поставщика, то все вложения нужно промаркировать (в начало файла добавить id поставщика + разделитель $importer_id_prefix)
            if ( $importer_id ) {
                $saver->setFileNamePrefix(  $importer_id . $importer_id_prefix );
                //    $importer_id = '';
            }
            // сохраняем вложения
            if( $saver->saveAttachmentsTo(\Yii::getAlias('@temp_upload'), 'UNSEEN') ){
                // закидываем вытащенные файлы в наш итоговый массив
                $files = array_merge( $files, $saver->getSavedFilesArr() );
            }else{
                // ящик не имеет писем с вложениями
                continue;
            }
        }

        return $files;
    }

    private function UnpackFiles ( &$files, $importer_id_prefix = '')
    {
        // если в вложениях встречаются архивы - распакуем
        // иициируем фабрику архиваторов
        $arch_creator = new ArchiveCreator();
        // получим все расширения которые поддерживает фабрика
        $arch_extensions = $arch_creator->getHandleExtension();
        // выбираем только те файлы которые мы можем распаковать
        $arch_files = array_intersect( $files , $arch_extensions );
        foreach ($arch_files as $arch_name => $arch_ext) {
            // создаем конкретный архиватор по расширению
            $arch_reader = $arch_creator->create( $arch_name, $arch_ext );
            // определим ид поставщика по имени файла
            $importer_id = ImportersFiles::getIdFromFileName($arch_name);
            if( $importer_id ){
                // если файл архива содержит поставщика (на предыдущих этапах мы его туда записали)
                // то нужно все вложенные файлы также промаркировать
                $arch_reader->setFileNamePrefix($importer_id . $importer_id_prefix);
                //$importer_id = '';
            }

            // распаковываем файлы
            $arch_reader->extractTo(\Yii::getAlias('@temp_upload') . '/');
            // убираем файл архива из итогового массива
            unset( $files[$arch_name] );
            // удаляем файл архива
            unlink($arch_name);
            // добавляем распакованные файлы к итоговому массиву
            $files = array_merge( $files, $arch_reader->getExtractedFiles());
        }

    }

    private function registerAndReplaceFiles ( &$files, $new_destination )
    {
        foreach ( $files as $name => $ext ) {
            // имена файлов для расширения csv нужно поменять,
            // для остальных оставляем оригинальные имена вложений (плюс ид поставщика если письмо от поставщика)
            $file_name = pathinfo( $name, PATHINFO_BASENAME );
            if( $ext == 'csv' ){
                // определим ид поставщика по имени файла
                $importer_id = ImportersFiles::getIdFromFileName( basename( $name ) );;

                // зарегистрируем прайс
                if ( $importer_id ) {
                    $files_model = new ImportersFiles();
                    $files_model->importer_id = $importer_id;
                    if ($files_model->save()) {
                        // имя файла переименуем на id записи
                        $file_name = \Yii::$app->db->getLastInsertID() . '.csv';

                    } else{

                        $files_model->throwStringErrorException();
                    }
                }
            }
            if( rename( $name, $new_destination . $file_name ) ){
                \Yii::info("Вложение {$name} сохранено", 'mail');
            } else{
                new \ErrorException("Нет возможности переписать файл {$name}");
            }
        }
    }
}