ParserController.php 11.5 KB
<?php
namespace backend\controllers;

use Yii;
use yii\data\ActiveDataProvider;
use yii\filters\AccessControl;
use backend\components\base\BaseController;
use yii\filters\VerbFilter;
use backend\models\UploadFileParsingForm;
use yii\web\UploadedFile;
use yii\data\ArrayDataProvider;
use yii\multiparser\DynamicFormHelper;
use backend\models\ImportersFiles;
use backend\models\Importers;
use yii\base\ErrorException;
use common\components\PriceWriter;
use common\components\CustomVarDamp;
use common\components\CustomArrayHelper;

/**
 * Parser controller
 */
class ParserController extends BaseController
{
    public $layout = "/column";

    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
//            'verbs' => [
//                'class' => VerbFilter::className(),
//                'actions' => [
//                    'logout' => ['post'],
//                ],
//            ],
        ];
    }



    public function actionIndex($mode = 0)
    {
//        $path = 'common\components\parsers\CustomConverter';
//        CustomVarDamp::dumpAndDie(new $path());
        $model = new UploadFileParsingForm();
        // установим режим, 0 - ручная загрузка, 1 - автозагрузка
        $model->mode = $mode;
        return $this->render('index', ['model' => $model]);
    }

    public function actionError()
    {
        $exception = Yii::$app->errorHandler->exception;
        if ($exception !== null) {
            return $this->render('error', ['message' => $exception->getMessage()]);
        }
    }

    public function actionResults($mode = 0)
    {
        $model = new UploadFileParsingForm(['mode' => $mode]);
        $data = [];
        if ($model->load(Yii::$app->request->post())) {
            $model->file = UploadedFile::getInstance($model, 'file');
            // первый проход - валидируем, сохраняем файл, ложим в кеш (для ручной загрузки) отпарсенные данные и параметры модели (потом при записи в базу данных они пригодятся)
            if ($model->validate()) {
                // запишем дату загрузки файла в таблицу файлов поставщика (ImportersFiles)
                $files_model = new ImportersFiles();
                // id поставщика получим из конфигурации
                $files_model->load(['ImportersFiles' => $model->toArray()]);
                try {
                    $files_model->save();
                } catch (ErrorException  $e) {
                    throw $e;
                }
                // получим id только что записанной записи - его запишем в название файла
                $model->record_id = $files_model->find()
                    ->where(['importer_id' => $files_model->importer_id])
                    ->orderBy(['id' => SORT_DESC])
                    ->one()
                    ->id;

                $file_name = $model->record_id . '.' . $model->file->extension;

                if ($model->mode) {
                    $model->file_path = Yii::getAlias('@temp_upload') . '/' . $file_name;
                } else {
                    $model->file_path = Yii::getAlias('@manual_upload') . '/' . $file_name;
                }

                $model->file->saveAs($model->file_path);
                // для авто загрузки, обработка завершена
                if ($model->mode) {
                    $model->success = true;

                    return $this->render('index', ['model' => $model]);
                }

                // === ручная загрузка ===========
                //запускаем парсинг
                // доп. опции для парсера
                $options = ['converter_conf' =>
                    ['importer_id' => $files_model->importer_id]
                ];

                if( ! $model->action ) // обработка с кастомным разделителем
                    $options['$delimiter'] = $model->delimiter;

                $data = $model->readFile( $options );
                // сохраняем в кеш отпарсенные даные
                Yii::$app->getCache()->set('parser_data', json_encode($data));
                // сохраняем в кеш модель - в ней настройки для дальнейшей обработки данных
                Yii::$app->getCache()->set('parser_configuration', serialize($model));

            } else {
                // не прошла валидация форма загрузки файлов
                $errors_str = '';
                foreach ($model->getErrors() as $error) {
                    $errors_str .= implode( array_values($error) );
                }
               throw new ErrorException( $errors_str );
            }
            // листаем пагинатором, или повторно вызываем - считываем из кеша отпрасенные данные
        } else if (Yii::$app->getCache()->get('parser_data')) {

            $data = json_decode(Yii::$app->getCache()->get('parser_data'), true);

        }

        $provider = new ArrayDataProvider([
            'allModels' => $data,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);


        $last_index = end( array_flip( $data[0] ) );
        $header_counts = $last_index + 1;
        //формируем заголовок для пользователя, где он сможет выбрать соответсвие полей (выпадающий список)
        $header_model = DynamicFormHelper::CreateDynamicModel( $header_counts );

        return $this->render('results',
            ['model' => $data,
                'header_model' => $header_model,
                // список колонок для выбора
                'basic_column' => Yii::$app->multiparser->getConfiguration('csv', 'basic_column'),
                'dataProvider' => $provider]);
    }

    public function actionWrite()
    {
        //получим колонки которые выбрал пользователь
        $arr_attributes = Yii::$app->request->post()['DynamicModel'];
        //соберем модель по полученным данным
        $model = DynamicFormHelper::CreateDynamicModel($arr_attributes);
        //добавим правила валидации (колонки должны быть те что указаны в конфиге)
        foreach ($arr_attributes as $key => $value) {
            $model->addRule($key, 'in', ['range' => array_keys(Yii::$app->multiparser->getConfiguration('csv', 'basic_column'))]);
        }

        // провалидируем выбранные колонки
        if ($model->validate()) {

            // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы
            $arr = $model->toArray();

            // получим данные из кеша
            if (Yii::$app->getCache()->get('parser_data') && Yii::$app->getCache()->get('parser_configuration')) {
                $data = json_decode(Yii::$app->getCache()->get('parser_data'), true);
                $configuration = unserialize(Yii::$app->getCache()->get('parser_configuration'));
            } else {
                throw new \ErrorException('Ошибка кеша');
            }

            // соотнесем отпарсенные данные с соответсивем полученным от пользователя
            // для этого преобразуем массив отпарсенных данных - назначим ключи согласно соответствию
            $data = CustomArrayHelper::createAssocArray( $data, $arr , 'attr_' );

            // запустим специальный класс который запишет данные в таблицы связанные с прайсами
            $writer = new PriceWriter();
            $writer->configuration = $configuration;
            $writer->data = $data;
            $writer->mode = 0; //web-режим
            if ( $writer->writeDataToDB() ) {

                $configuration['success'] = true;
                // все прошло успешно - очищаем кеш
                Yii::$app->getCache()->delete('parser_data');
                Yii::$app->getCache()->delete('parser_configuration');

                if( file_exists($configuration['file_path']) )
                    unlink($configuration['file_path']);

                return $this->render('index', ['model' => $configuration]);

            };

        }

    }

    public function actionAutoUpload()
    {
        $query = Importers::find()->where(['active' => true])->orderBy(['price_date_update' => SORT_DESC]);

        $provider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);
        return $this->render('check_price',
            [
                'dataProvider' => $provider]);
    }

    public function actionServerFiles ()
    {
            $arr_id_files = [];

        // получим список файлов которые ожидают к загрузке
        foreach ( glob(Yii::getAlias('@temp_upload') . '/*.csv' ) as $server_file ) {
            $file_id = basename($server_file,".csv");
            $arr_id_files[] = (int) $file_id;
        }

        $query = ImportersFiles::find()->where(['in', 'id', $arr_id_files])->orderBy(['upload_time' => SORT_DESC]);

        $provider = new ActiveDataProvider([
            'query' => $query,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);
        return $this->render('server-files',
            [
                'dataProvider' => $provider]);
    }

    public function actionDelete ()
    {
        if ( Yii::$app->request->isAjax ) {

            $files_model = new ImportersFiles();
            if ( isset(Yii::$app->request->post()['id'] )) {
                $id = Yii::$app->request->post()['id'];
                try {
                    $files_model->delete($id);
                    unlink(Yii::getAlias('@temp_upload') . '/' . $id . '.csv' );
                    // сообщим скрипту что все ОК
                    echo 1;
                } catch (ErrorException  $e) {

                    throw $e;

                }
            }
        }

    }

    public function actionLaunchCroneUploads ()
    {
        foreach (glob(Yii::getAlias('@temp_upload') . '/*.csv') as $server_file) {

            $file_name = basename($server_file,".csv");
            copy( $server_file, Yii::getAlias('@auto_upload') . '/' . $file_name . '.csv' );

        }

        Yii::$app->session->setFlash( 'server-files', 'Файл успешно загружен' );
        $this->redirect('server-files');

//        $csv = new \console\controllers\ParserController( 'parse-csv', $this->module );
//        $csv->actionParseCsv();
    }


}