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 8  
9 9 namespace backend\controllers;
10 10  
11   -use backend\components\base\BaseActiveRecord;
12 11 use backend\components\base\BaseController;
13 12 use common\components\CustomArrayHelper;
14   -use common\components\CustomVarDamp;
15   -use yii\base\ErrorException;
16   -use yii\base\Model;
17 13 use yii\data\ArrayDataProvider;
18   -use yii\db\ActiveRecord;
19 14 use yii\filters\VerbFilter;
20 15 use yii\filters\AccessControl;
21 16 use backend\models\UploadFileCrossingForm;
22 17 use backend\models\DetailsCrosses;
23 18 use yii\multiparser\DynamicFormHelper;
24 19 use yii\web\UploadedFile;
  20 +use common\components\ModelArrayValidator;
25 21 use \Yii;
26 22  
27 23 class CrossingUploadController extends BaseController
... ... @@ -141,11 +137,19 @@ class CrossingUploadController extends BaseController
141 137 // запустим конвертер над над данными
142 138 $data = $this->convertDataByConfiguration( $data, $configuration );
143 139  
  140 + // валидируем отпарсенные данные моделью в которую будем записывать
144 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 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 155 $this->cacheHandler( 2 );
... ... @@ -200,20 +204,10 @@ class CrossingUploadController extends BaseController
200 204 $basic_options = Yii::$app->multiparser->getConfiguration( 'csv', 'crosses' );
201 205 $options = array_merge_recursive( $options, $basic_options );
202 206  
203   - // для доп массива обратных строк
204   - $i = count( $data ) - 1;
205   - $reverse_data = [];
206 207 foreach ( $data as &$row ) {
207 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 211 return $data;
218 212  
219 213 }
... ... @@ -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 267 \ No newline at end of file
... ...
backend/controllers/RgGrupController.php
... ... @@ -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 131 $arr = $model->toArray();
... ... @@ -147,7 +147,7 @@ class RgGrupController extends BaseController
147 147 $data = CustomArrayHelper::createAssocArray($data, $arr, 'attr_');
148 148  
149 149 // в первой строке у нас заголовки - уберем
150   - unset($data[0]);
  150 + unset( $data[0] );
151 151 // подготовим данные для записи в таблицу w_margins_groups
152 152 $arr_values = [];
153 153 $group = '';
... ...
backend/views/crossing-upload/index.php
... ... @@ -8,9 +8,6 @@ use yii\helpers\ArrayHelper;
8 8 <div class="col-lg-5">
9 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 12 <h3>Кросс файлы</h3>
16 13  
... ... @@ -22,7 +19,16 @@ use yii\helpers\ArrayHelper;
22 19 <?= Html::submitButton(Yii::t( 'app', 'Прочитать' ), ['class' => 'btn btn-primary']) ?>
23 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 32 </div>
27 33 </div>
28 34  
... ...
backend/views/currency/index.php
... ... @@ -27,7 +27,7 @@ $this-&gt;params[&#39;breadcrumbs&#39;][] = $this-&gt;title;
27 27 'rate',
28 28 'timestamp',
29 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 128 \ No newline at end of file
... ...
common/components/parsers/CustomConverter.php
... ... @@ -25,15 +25,17 @@ class CustomConverter extends Converter
25 25  
26 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 39 return $row;
38 40 }
39 41  
... ... @@ -53,7 +55,7 @@ class CustomConverter extends Converter
53 55 return $row;
54 56 }
55 57  
56   - public function ConvertToMultiply(array $row)
  58 + public function ConvertToMultiply( array $row )
57 59 {
58 60 $PRICE = $row['PRICE'];
59 61 $sign = self::$sign;
... ...
common/components/parsers/config.php
... ... @@ -45,7 +45,7 @@
45 45 'hasKey' => 1,
46 46 'configuration' => [
47 47 "brand" => ['BRAND', 'CROSS_BRAND'],
48   - "crosses" => [],
  48 + // "crosses" => [],
49 49 ]
50 50 ],
51 51 'basic_column' => [
... ...
common/models/Currency.php
... ... @@ -30,9 +30,6 @@ class Currency extends \yii\db\ActiveRecord
30 30 {
31 31 return [
32 32 [['name', 'rate'], 'required'],
33   -// [['rate'], 'filter','filter' => function($value){
34   -// return (float) str_replace( ',', '.', $value );}
35   -// ],
36 33 ['rate', \common\components\CommaNumberValidator::className()],
37 34 [['is_default'], 'integer'],
38 35 [['timestamp'], 'safe'],
... ...