PriceWriter.php 8.85 KB
<?php
/**
 * Created by PhpStorm.
 * User: Cibermag
 * Date: 30.09.2015
 * Time: 9:34
 */

namespace common\components;


use yii\base\ErrorException;
use backend\models\ImportersFiles;
use backend\models\Importers;
use backend\models\Details;
use common\components\ModelArrayValidator;

/**
 * Class PriceWriter
 * @package common\components
 * записывает в БД отпарсенные данные
 * запись происходит в несколько таблиц
 */
class PriceWriter
{
    /**
     * @var - int - 0 - интерактивный режим, 1 - консольный
     */
    protected $mode;

    /**
     * @var - массив с настройками записи
     */
    protected $configuration;

    /**
     * @var - массив с данными которые нужно записать
     */
    protected $data;

    /**
     * @var - сообщение валидатора об ошибках
     */
    protected $validated_msg;
    /**
     * @var - тип сообщения валидатора - success, warning
     */
    protected $validated_type_msg;



    function __construct()
    {
        set_time_limit(300);
    }

    /**
     * @param mixed $mode
     */
    public function setMode($mode)
    {
        $this->mode = $mode;
    }

    /**
     * @param mixed $configuration
     */
    public function setConfiguration($configuration)
    {
        $this->configuration = $configuration;
    }

    /**
     * @param mixed $data
     */
    public function setData($data)
    {
        $this->data = $data;
    }

    /**
     * @return mixed
     */
    public function getValidatedMsg()
    {
        return $this->validated_msg;
    }

    /**
     * @return mixed
     */
    public function getValidatedTypeMsg()
    {
        return $this->validated_type_msg;
    }


    public function writePriceToDB()
    {
        // 1. запишем дату старта в таблицу файлов поставщика (ImportersFiles)
        // id  загруженного файла получим из конфигурации
        $files_model = ImportersFiles::findOne($this->configuration['record_id']);

        $update_date = date('Y-m-d H:i:s');
        $files_model->time_start = $update_date;
        // запишем дату начала загрузки
        if (!$files_model->save()) {
            throw new \ErrorException(implode(', ', $files_model->getErrors()));
        }

        // 2. конвертируем данные
        // только для ручной загрузки, в авто режиме все делает конвертер при первом же проходе (в процессе парсинга)
        if ( $this->mode == 0 ) {
            // преобразуем значения перед записью в БД
            $this->convertDataByConfiguration();

        }
        //3. провалидируем полученные данные моделью - Details
        $details_model = $this->validateByDetailsModel();

        //4. дополним данные значением импортера и даты обновления цены
        $this->data = CustomArrayHelper::addColumns($this->data, ['IMPORT_ID' => $this->configuration['importer_id'], 'timestamp' => $update_date]);

        //5. запишем данные в связанные таблицы
        $this->writePriceInTransaction($details_model, $files_model, $update_date);

        return true;
    }

    public function deletePriceFromDB()
    {
        $importer_id = '';
        $update_date = '';

        if (isset($this->configuration['importer_id']))
            $importer_id = $this->configuration['importer_id'];

        if (isset($this->configuration['update_date']))
            $update_date = $this->configuration['update_date'];

        if (!$importer_id) {
            throw new \ErrorException('Не указан поставщик прайса для удаления');
        } elseif (!$update_date) {
            throw new \ErrorException('Не указана дата загрузки прайса для удаления');
        }

        $this->deletePriceInTransaction( $importer_id, $update_date );

        return true;
    }

    /**
     * ковертирует отпарсенные данные конвертером по конфигурации
     */
    protected function convertDataByConfiguration ()
    {
        foreach ($this->data as &$row) {
            if (isset($row['PRICE']))
                $row['PRICE'] = \Yii::$app->converter->convertTo('float', $row['PRICE']);

            if (isset($row['BOX']))
                $row['BOX'] = \Yii::$app->converter->convertTo('integer', $row['BOX']);
            // присвоим полный артикул

            if (isset($row['ARTICLE'])) {

                $row['FULL_ARTICLE'] = $row['ARTICLE'];

                if ((int)$this->configuration['delete_prefix']) {
                    $row = \Yii::$app->converter->convertTo('Article', $row, ['importer_id' => $this->configuration['importer_id']]);
                } else {
                    if (isset($row['ARTICLE']))
                        $row['ARTICLE'] = \Yii::$app->converter->convertTo('Article', $row['ARTICLE']);
                }
            }

            if (isset($row['ADD_BOX']))
                $row['ADD_BOX'] = \Yii::$app->converter->convertTo('integer', $row['ADD_BOX']);
        }
    }

    protected function  writePriceInTransaction($details_model, $files_model, $update_date){
        $transaction = \Yii::$app->db->beginTransaction();
        try {

            if (isset($this->configuration['delete_price']) && (int)$this->configuration['delete_price']) {
                $details_model->delete_price = true;
            }

            //2. попытаемся вставить данные в БД с апдейтом по ключам
            $details_model->manualInsert($this->data, $this->configuration['importer_id']);

            // 3. зафиксируем дату конца загрузки в файлах поставщика
            if (!$files_model->save()) {
                $transaction->rollBack();
                throw new \ErrorException(implode(', ', $files_model->getErrors()));
            }

            // 4. зафиксируем дату загрузки в таблице поставщиков
            $imp_model = Importers::findOne($this->configuration['importer_id']);
            $imp_model->price_date_update = $update_date;

            if (!$imp_model->save()) {
                $transaction->rollBack();
                $imp_model->throwStringErrorException();
            }
            $transaction->commit();

        } catch (ErrorException  $e) {
            $transaction->rollBack();
            throw new \ErrorException($e->getMessage());
        }

    }

    protected function  deletePriceInTransaction( $importer_id, $update_date ){
        $transaction = \Yii::$app->db->beginTransaction();
        try {
            // 1. удалим из таблицы файлов поставщика (ImportersFiles)

            $rows = ImportersFiles::deleteAll(['importer_id' => $importer_id, 'time_start' => $update_date]);
            if ($rows != 1) {
                $transaction->rollBack();
                throw new \ErrorException('Ошибка удаления из таблицы файлов поставщиков. Указанный прайс не найден');
            }

            $last_upload_time = ImportersFiles::find()->where(['importer_id' => $importer_id])->orderBy(['time_start' => SORT_DESC])->one()->time_start;

            // 2. удалим прайс из таблицы товаров (Details)
            $details_model = new Details();
            $conditions = "import_id = {$importer_id} AND  timestamp ='$update_date'";

            $details_model->manualDelete( $conditions );

            // 3. откатимся до старой даты загрузки в таблице поставщиков
            $imp_model = Importers::findOne( $importer_id );
            $imp_model->price_date_update = $last_upload_time;

            if (!$imp_model->save()) {
                $transaction->rollBack();
                $imp_model->throwStringErrorException();
            }

            $transaction->commit();
        } catch (ErrorException  $e) {
            $transaction->rollBack();
            throw new \ErrorException($e->getMessage());
        }
    }

    protected function validateByDetailsModel(){

        $details_model = new Details();

        $model_validator = new ModelArrayValidator( $details_model );
        $this->data = $model_validator->validate( $this->data );
        $this->validated_msg = $model_validator->getMassage();
        $this->validated_type_msg =  $model_validator->hasError() ?  'warning' : 'success';

        $model_validator->close();

        return $details_model;
    }
}