Commit c2ef0939c007466c8265a903330db0ae61ae25b8

Authored by Mihail
1 parent 9f082181

add array model validator and adjusted crosses upload form to it

backend/controllers/CrossingUploadController.php
@@ -8,20 +8,16 @@ @@ -8,20 +8,16 @@
8 8
9 namespace backend\controllers; 9 namespace backend\controllers;
10 10
11 -use backend\components\base\BaseActiveRecord;  
12 use backend\components\base\BaseController; 11 use backend\components\base\BaseController;
13 use common\components\CustomArrayHelper; 12 use common\components\CustomArrayHelper;
14 -use common\components\CustomVarDamp;  
15 -use yii\base\ErrorException;  
16 -use yii\base\Model;  
17 use yii\data\ArrayDataProvider; 13 use yii\data\ArrayDataProvider;
18 -use yii\db\ActiveRecord;  
19 use yii\filters\VerbFilter; 14 use yii\filters\VerbFilter;
20 use yii\filters\AccessControl; 15 use yii\filters\AccessControl;
21 use backend\models\UploadFileCrossingForm; 16 use backend\models\UploadFileCrossingForm;
22 use backend\models\DetailsCrosses; 17 use backend\models\DetailsCrosses;
23 use yii\multiparser\DynamicFormHelper; 18 use yii\multiparser\DynamicFormHelper;
24 use yii\web\UploadedFile; 19 use yii\web\UploadedFile;
  20 +use common\components\ModelArrayValidator;
25 use \Yii; 21 use \Yii;
26 22
27 class CrossingUploadController extends BaseController 23 class CrossingUploadController extends BaseController
@@ -141,11 +137,19 @@ class CrossingUploadController extends BaseController @@ -141,11 +137,19 @@ class CrossingUploadController extends BaseController
141 // запустим конвертер над над данными 137 // запустим конвертер над над данными
142 $data = $this->convertDataByConfiguration( $data, $configuration ); 138 $data = $this->convertDataByConfiguration( $data, $configuration );
143 139
  140 + // валидируем отпарсенные данные моделью в которую будем записывать
144 $crosses_model = new DetailsCrosses(); 141 $crosses_model = new DetailsCrosses();
  142 + $model_validator = new ModelArrayValidator( $crosses_model );
  143 + $data = $model_validator->validate( $data );
  144 + $msg = $model_validator->getMassage();
  145 + $type_msg = $model_validator->hasError() ? 'warning' : 'success';
  146 + $model_validator->close();
  147 +
  148 + $data = $this->reverseCrosses( $data );
145 149
146 if ( $crosses_model->ManualInsertWithIgnore( $data ) ) { 150 if ( $crosses_model->ManualInsertWithIgnore( $data ) ) {
147 151
148 - Yii::$app->session->setFlash('success', 'Файл кроссов успешно загружен'); 152 + Yii::$app->session->setFlash( $type_msg, $msg );
149 153
150 // очистим кеш 154 // очистим кеш
151 $this->cacheHandler( 2 ); 155 $this->cacheHandler( 2 );
@@ -200,20 +204,10 @@ class CrossingUploadController extends BaseController @@ -200,20 +204,10 @@ class CrossingUploadController extends BaseController
200 $basic_options = Yii::$app->multiparser->getConfiguration( 'csv', 'crosses' ); 204 $basic_options = Yii::$app->multiparser->getConfiguration( 'csv', 'crosses' );
201 $options = array_merge_recursive( $options, $basic_options ); 205 $options = array_merge_recursive( $options, $basic_options );
202 206
203 - // для доп массива обратных строк  
204 - $i = count( $data ) - 1;  
205 - $reverse_data = [];  
206 foreach ( $data as &$row ) { 207 foreach ( $data as &$row ) {
207 $row = Yii::$app->converter->convertByConfiguration( $row, $options['converter_conf'] ); 208 $row = Yii::$app->converter->convertByConfiguration( $row, $options['converter_conf'] );
208 - // нужно добавить обратную строку по кроссам  
209 - $reverse_data[ $i ]['ARTICLE'] = $row['CROSS_ARTICLE'];  
210 - $reverse_data[ $i ]['CROSS_ARTICLE'] = $row['ARTICLE'];  
211 - $reverse_data[ $i ]['BRAND'] = $row['CROSS_BRAND'];  
212 - $reverse_data[ $i ]['CROSS_BRAND'] = $row['BRAND'];  
213 - $i++;  
214 } 209 }
215 210
216 - $data = array_merge( $data, $reverse_data );  
217 return $data; 211 return $data;
218 212
219 } 213 }
@@ -251,21 +245,22 @@ class CrossingUploadController extends BaseController @@ -251,21 +245,22 @@ class CrossingUploadController extends BaseController
251 245
252 } 246 }
253 247
254 -// protected function validateModel( BaseActiveRecord $model, array $data ){  
255 -//  
256 -// foreach ( $data as $row ) {  
257 -// // подготовим данные к валидации  
258 -// $validate_attr[$model->formName()] = $row;  
259 -// if( !$model->load( $validate_attr ) ){  
260 -// // такой ситуации не должно быть, но на всякий случай  
261 -// throw new ErrorException('Незаполнены обязательные поля формы.');  
262 -// }  
263 -// if ( !$model->validate( ) ) {  
264 -// $model->throwStringErrorException( key( $data ) );  
265 -// };  
266 -// }  
267 -//  
268 -// return true;  
269 -//  
270 -// } 248 + protected function reverseCrosses ( $data )
  249 + {
  250 + // для доп массива обратных строк
  251 + $i = count( $data ) - 1;
  252 + $reverse_data = [];
  253 + foreach ( $data as &$row ) {
  254 + // нужно добавить обратную строку по кроссам
  255 + $reverse_data[ $i ]['ARTICLE'] = $row['CROSS_ARTICLE'];
  256 + $reverse_data[ $i ]['CROSS_ARTICLE'] = $row['ARTICLE'];
  257 + $reverse_data[ $i ]['BRAND'] = $row['CROSS_BRAND'];
  258 + $reverse_data[ $i ]['CROSS_BRAND'] = $row['BRAND'];
  259 + $i++;
  260 + }
  261 + $data = array_merge( $data, $reverse_data );
  262 +
  263 + return $data;
  264 + }
  265 +
271 } 266 }
272 \ No newline at end of file 267 \ No newline at end of file
backend/controllers/RgGrupController.php
@@ -125,7 +125,7 @@ class RgGrupController extends BaseController @@ -125,7 +125,7 @@ class RgGrupController extends BaseController
125 } 125 }
126 126
127 // провалидируем выбранные колонки 127 // провалидируем выбранные колонки
128 - if ($model->validate()) { 128 + if ( $model->validate() ) {
129 129
130 // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы 130 // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы
131 $arr = $model->toArray(); 131 $arr = $model->toArray();
@@ -147,7 +147,7 @@ class RgGrupController extends BaseController @@ -147,7 +147,7 @@ class RgGrupController extends BaseController
147 $data = CustomArrayHelper::createAssocArray($data, $arr, 'attr_'); 147 $data = CustomArrayHelper::createAssocArray($data, $arr, 'attr_');
148 148
149 // в первой строке у нас заголовки - уберем 149 // в первой строке у нас заголовки - уберем
150 - unset($data[0]); 150 + unset( $data[0] );
151 // подготовим данные для записи в таблицу w_margins_groups 151 // подготовим данные для записи в таблицу w_margins_groups
152 $arr_values = []; 152 $arr_values = [];
153 $group = ''; 153 $group = '';
backend/views/crossing-upload/index.php
@@ -8,9 +8,6 @@ use yii\helpers\ArrayHelper; @@ -8,9 +8,6 @@ use yii\helpers\ArrayHelper;
8 <div class="col-lg-5"> 8 <div class="col-lg-5">
9 <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['crossing-upload/result']]); 9 <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['crossing-upload/result']]);
10 10
11 - if ($msg = \Yii::$app->session->getFlash('success')) { // вернулись после успешной загрузки данного файла  
12 - echo Html::tag('h3', $msg ,['class'=>'bg-success']);  
13 - }  
14 ?> 11 ?>
15 <h3>Кросс файлы</h3> 12 <h3>Кросс файлы</h3>
16 13
@@ -22,7 +19,16 @@ use yii\helpers\ArrayHelper; @@ -22,7 +19,16 @@ use yii\helpers\ArrayHelper;
22 <?= Html::submitButton(Yii::t( 'app', 'Прочитать' ), ['class' => 'btn btn-primary']) ?> 19 <?= Html::submitButton(Yii::t( 'app', 'Прочитать' ), ['class' => 'btn btn-primary']) ?>
23 </div> 20 </div>
24 21
25 - <?php ActiveForm::end() ?> 22 + <?php ActiveForm::end();
  23 + Html::tag('br');
  24 + if ($msg = \Yii::$app->session->getFlash('success'))
  25 + {
  26 + echo Html::tag('p', $msg ,['class'=>'bg-success']);
  27 + } elseif ($msg = \Yii::$app->session->getFlash('warning'))
  28 + {
  29 + echo Html::tag('p', $msg, ['class' => 'bg-warning']);
  30 + }
  31 + ?>
26 </div> 32 </div>
27 </div> 33 </div>
28 34
backend/views/currency/index.php
@@ -27,7 +27,7 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title; @@ -27,7 +27,7 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
27 'rate', 27 'rate',
28 'timestamp', 28 'timestamp',
29 ['class' => 'yii\grid\ActionColumn', 29 ['class' => 'yii\grid\ActionColumn',
30 - 'template' => '{update}'], 30 + 'template' => '{update}{delete}'],
31 ], 31 ],
32 ]); ?> 32 ]); ?>
33 33
common/components/ModelArrayValidator.php 0 → 100644
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: Tsurkanov
  5 + * Date: 26.11.2015
  6 + * Time: 9:04
  7 + */
  8 +
  9 +namespace common\components;
  10 +
  11 +use yii\base\Model;
  12 +
  13 +/**
  14 + * Class ModelArrayValidator
  15 + * @package common\components
  16 + * Валидирует переданный массив, сохраняет отдельно ошибки, и возвращает отвалидированные данные
  17 + * также формирует сообщение на форму с количеством обработанных записей и количеством ошибок
  18 + * использовать когда нужно сохранить только отвалидированные данные,
  19 + * а ошибочные откинуть и показать пользователю в сообщении
  20 + */
  21 +class ModelArrayValidator
  22 +{
  23 + protected $arr_errors = [];
  24 + protected $model;
  25 + protected $valid_data = [];
  26 + protected $total_rows = 0;
  27 +
  28 + public function __construct( Model $model )
  29 + {
  30 + $this->model = $model;
  31 + }
  32 +
  33 + /**
  34 + * @return array
  35 + */
  36 + public function getErrors()
  37 + {
  38 + return $this->arr_errors;
  39 + }
  40 +
  41 + /**
  42 + * @return mixed
  43 + */
  44 + public function getValidData()
  45 + {
  46 + return $this->valid_data;
  47 + }
  48 +
  49 + /**
  50 + * @return string - сообщение на форму с результатми обработки
  51 + */
  52 + public function getMassage ()
  53 + {
  54 + $total_count = $this->total_rows;
  55 + $success_count = $this->total_rows - count($this->arr_errors);
  56 + $error_count = count($this->arr_errors);
  57 +
  58 + $msg = "Обработано - {$total_count} строк.</br>
  59 + Успешно загрузились - {$success_count} строк.</br>
  60 + Найдено строк с ошибками - {$error_count}.</br>";
  61 +
  62 + foreach ($this->arr_errors as $row => $error) {
  63 + $msg .= "Ошибка в строке {$row} </br>
  64 + Текст ошибки: {$error} </br>";
  65 + }
  66 +
  67 + return $msg;
  68 + }
  69 +
  70 + /**
  71 + * @param $data
  72 + * @return array
  73 + * метод регистрирует ошибки, регистрирует "чистые данные" и возвращает их
  74 + */
  75 + public function validate( $data )
  76 + {
  77 + foreach ( $data as $row ) {
  78 + $this->total_rows++;
  79 + $validate_row[$this->model->formName()] = $row;
  80 + // clear previous loading
  81 + $this->clearModelAttributes();
  82 + if ( $this->model->load( $validate_row ) && $this->model->validate() ) {
  83 + // everything OK, registred row to valid data
  84 + $this->valid_data[] = $row;
  85 + } else{
  86 + // we have errors
  87 + $this->registredError( $this->total_rows );
  88 + }
  89 + }
  90 +
  91 + return $this->valid_data;
  92 + }
  93 +
  94 + protected function registredError ($index)
  95 + {
  96 + $errors_str = '';
  97 + foreach ($this->model->getErrors() as $error) {
  98 + $errors_str .= implode(array_values($error));
  99 + }
  100 +
  101 + $this->arr_errors[$index] = $errors_str;
  102 + }
  103 +
  104 +
  105 + public function hasError ()
  106 + {
  107 + return (bool) count($this->arr_errors);
  108 + }
  109 +
  110 + protected function clearModelAttributes()
  111 + {
  112 + $attributes = $this->model->safeAttributes();
  113 +
  114 + foreach ( $attributes as $key => $value ) {
  115 + $this->model->$value = '';
  116 + }
  117 +
  118 +}
  119 +
  120 + public function close(){
  121 +
  122 + unset( $this->valid_data );
  123 + unset( $this->arr_errors );
  124 + unset( $this->model );
  125 +
  126 + }
  127 +}
0 \ No newline at end of file 128 \ No newline at end of file
common/components/parsers/CustomConverter.php
@@ -25,15 +25,17 @@ class CustomConverter extends Converter @@ -25,15 +25,17 @@ class CustomConverter extends Converter
25 25
26 $details_model = new Details(); 26 $details_model = new Details();
27 // проверим все ли обязательные колонки были указаны пользователем 27 // проверим все ли обязательные колонки были указаны пользователем
28 - $details_model->load(['Details' => $row]); 28 +// $details_model->load(['Details' => $row]);
  29 +//
  30 +// if (!$details_model->validate()) {
  31 +// $errors = '';
  32 +// foreach ($details_model->errors as $key => $arr_errors) {
  33 +// $errors .= "Аттрибут $key - " . implode(' , ', $arr_errors);
  34 +// }
  35 +// throw new \ErrorException($errors);
  36 +// }
  37 +
29 38
30 - if (!$details_model->validate()) {  
31 - $errors = '';  
32 - foreach ($details_model->errors as $key => $arr_errors) {  
33 - $errors .= "Аттрибут $key - " . implode(' , ', $arr_errors);  
34 - }  
35 - throw new \ErrorException($errors);  
36 - }  
37 return $row; 39 return $row;
38 } 40 }
39 41
@@ -53,7 +55,7 @@ class CustomConverter extends Converter @@ -53,7 +55,7 @@ class CustomConverter extends Converter
53 return $row; 55 return $row;
54 } 56 }
55 57
56 - public function ConvertToMultiply(array $row) 58 + public function ConvertToMultiply( array $row )
57 { 59 {
58 $PRICE = $row['PRICE']; 60 $PRICE = $row['PRICE'];
59 $sign = self::$sign; 61 $sign = self::$sign;
common/components/parsers/config.php
@@ -45,7 +45,7 @@ @@ -45,7 +45,7 @@
45 'hasKey' => 1, 45 'hasKey' => 1,
46 'configuration' => [ 46 'configuration' => [
47 "brand" => ['BRAND', 'CROSS_BRAND'], 47 "brand" => ['BRAND', 'CROSS_BRAND'],
48 - "crosses" => [], 48 + // "crosses" => [],
49 ] 49 ]
50 ], 50 ],
51 'basic_column' => [ 51 'basic_column' => [
common/models/Currency.php
@@ -30,9 +30,6 @@ class Currency extends \yii\db\ActiveRecord @@ -30,9 +30,6 @@ class Currency extends \yii\db\ActiveRecord
30 { 30 {
31 return [ 31 return [
32 [['name', 'rate'], 'required'], 32 [['name', 'rate'], 'required'],
33 -// [['rate'], 'filter','filter' => function($value){  
34 -// return (float) str_replace( ',', '.', $value );}  
35 -// ],  
36 ['rate', \common\components\CommaNumberValidator::className()], 33 ['rate', \common\components\CommaNumberValidator::className()],
37 [['is_default'], 'integer'], 34 [['is_default'], 'integer'],
38 [['timestamp'], 'safe'], 35 [['timestamp'], 'safe'],