[ 'class' => AccessControl::className(), 'rules' => [ [ 'actions' => ['result', 'index', 'write', 'error'], 'allow' => true, 'roles' => ['@'], ], ], ], 'verbs' => [ 'class' => VerbFilter::className(), 'actions' => [ 'logout' => ['post'], ], ], ]; } public function actionIndex() { $model = new UploadFileCrossingForm(); return $this->render('index', ['model' => $model]); } public function actionResult() { $model = new UploadFileCrossingForm(); $data = []; if ( $model->load(Yii::$app->request->post()) ) { $model->file = UploadedFile::getInstance($model, 'file'); if ( $model->validate() ) { $file_name = $model->file->name; $model->file_path = Yii::getAlias('@temp_upload') . '/' . $file_name; $model->file->saveAs($model->file_path); //запускаем парсинг $options['mode'] = 'crosses'; $data = $model->readFile($options); // сохраняем в кеш отпарсенные даные $this->parserCacheHandler( 1, $data, $model ); } else { // не прошла валидация формы загрузки файлов $errors_str = "Ошибка загрузки файла. "; $this->throwStringErrorException( $model , new CrossParsingException( $errors_str ) ); } } else if ( Yii::$app->getCache()->get('parser_data') ) { $data = json_decode( Yii::$app->getCache()->get('parser_data'), true ); } // сборка динамической модели и её рендеринг return $this->renderResultView( $data ); } public function actionWrite() { set_time_limit(600); //получим колонки которые выбрал пользователь $arr_attributes = Yii::$app->request->post()['DynamicModel']; //соберем модель по полученным данным $model = DynamicFormHelper::CreateDynamicModel($arr_attributes); $crosses_model = new DetailsCrosses(); $arr_keys = array_keys($this->getBasicColumns()); //добавим правила валидации (колонки должны быть те что в модели) foreach ($arr_attributes as $key => $value) { $model->addRule($key, 'in', ['range' => $arr_keys]); } // установим режим проверки обязательных полей $crosses_model->setScenario('form_upload_validation'); $model_validator = new ModelArrayValidator($crosses_model); // провалидируем выбранные колонки if ( $model->validate() && $model_validator->validateRow( array_flip( $arr_attributes ) ) ) { // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы $arr = $model->toArray(); // получим данные из кеша $this->parserCacheHandler( 0, $data, $configuration ); // соотнесем отпарсенные данные с соответствием полученным от пользователя // для этого преобразуем массив отпарсенных данных - назначим ключи согласно соответствию $data = CustomArrayHelper::createAssocArray( $data, $arr, 'attr_' ); // запустим конвертер над над данными $data = $this->convertDataByConfiguration( $data, $configuration ); // валидируем отпарсенные данные моделью в которую будем записывать $crosses_model->setScenario('default'); $data = $model_validator->validate( $data ); $msg = $model_validator->getMassage(); $type_msg = $model_validator->hasError() ? 'warning' : 'success'; $model_validator->close(); $data = $this->reverseCrosses($data); try { if ($crosses_model->ManualInsertWithIgnore( $data )) { // очистим кеш $this->parserCacheHandler(2); if (file_exists($configuration['file_path'])) unlink($configuration['file_path']); Yii::$app->session->setFlash($type_msg, $msg); return $this->render('index', ['model' => $configuration]); } } catch (Exception $e) { new CrossParsingException( $e->getMessage() ); } } else { // не прошла валидация формы загрузки файлов $errors_str = "Ошибка валидации формы загрузки файлов. "; $this->throwStringErrorException( $crosses_model , 'common\components\exceptions\CrossParsingException', $errors_str ); } } protected function getBasicColumns() { $basicColumns_array = Yii::$app->multiparser->getConfiguration('csv', 'crosses'); if (isset($basicColumns_array['basic_column'])) { return $basicColumns_array['basic_column']; } else { throw new \ErrorException('Ошибка конфигурационного файла кроссов. Не указаны базовые колнки для пользовательской формы выбора.'); } } protected function convertDataByConfiguration($data, $configuration) { // доп. опции для парсера - удаление префикса в артикулах $options['mode'] = 'crosses'; $fields = []; if ($configuration['delete_prefix1']) { $fields[] = 'ARTICLE'; } if ($configuration['delete_prefix2']) { $fields[] = 'CROSS_ARTICLE'; } if ($fields) { $options ['converter_conf']['configuration'] = ["article" => $fields, "string" => ['ARTICLE', 'CROSS_ARTICLE'],]; } else { $options ['converter_conf']['configuration'] = ["string" => ['ARTICLE', 'CROSS_ARTICLE'],]; } // получим базовую конфигурацию и объеденим её с той что образовалась после выбора пользователем настроек $basic_options = Yii::$app->multiparser->getConfiguration('csv', 'crosses'); $options = array_merge_recursive($options, $basic_options); foreach ($data as &$row) { $row = Yii::$app->converter->convertByConfiguration($row, $options['converter_conf']); } return $data; } protected function reverseCrosses($data) { // для доп массива обратных строк $i = count($data) - 1; $reverse_data = []; foreach ($data as &$row) { // нужно добавить обратную строку по кроссам $reverse_data[$i]['ARTICLE'] = $row['CROSS_ARTICLE']; $reverse_data[$i]['CROSS_ARTICLE'] = $row['ARTICLE']; $reverse_data[$i]['BRAND'] = $row['CROSS_BRAND']; $reverse_data[$i]['CROSS_BRAND'] = $row['BRAND']; $i++; } $data = array_merge($data, $reverse_data); return $data; } }