Commit c3d64258a6230ff4e8a12a1d9a7a4a34890e8e6c
1 parent
45c41a76
merge with server
Showing
26 changed files
with
1268 additions
and
61 deletions
Show diff stats
1 | +<?php | |
2 | +/** | |
3 | + * Created by PhpStorm. | |
4 | + * User: Cibermag | |
5 | + * Date: 21.09.2015 | |
6 | + * Time: 17:36 | |
7 | + */ | |
8 | + | |
9 | +namespace backend\components\base; | |
10 | + | |
11 | +use yii\db\Connection; | |
12 | + | |
13 | +class CustomDbConnection extends Connection { | |
14 | + //@todo - переписать с использованием событий - почемуто не сработало это событие | |
15 | + public function afterOpen() | |
16 | + { | |
17 | + $now = new \DateTime(); | |
18 | + $mins = $now->getOffset() / 60; | |
19 | + $sgn = ($mins < 0 ? -1 : 1); | |
20 | + $mins = abs($mins); | |
21 | + $hrs = floor($mins / 60); | |
22 | + $mins -= $hrs * 60; | |
23 | + $offset = sprintf('%+d:%02d', $hrs*$sgn, $mins); | |
24 | + | |
25 | + $this->pdo->exec("SET time_zone='$offset';"); | |
26 | + | |
27 | + } | |
28 | + | |
29 | + protected function initConnection() | |
30 | + { | |
31 | + parent::initConnection(); | |
32 | + $this->afterOpen(); | |
33 | + | |
34 | + } | |
35 | + | |
36 | + | |
37 | +} | |
0 | 38 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +namespace backend\components\parsers; | |
3 | +use yii\multiparser\Converter; | |
4 | + | |
5 | +class CustomConverter extends Converter { | |
6 | + | |
7 | + /** | |
8 | + * @param $value_arr - двумерный массив значений, которому нужно присвоить ключи | |
9 | + * @param $key_array - ключи для вложенного массива | |
10 | + * @return array - таблица с проименованными колонками | |
11 | + */ | |
12 | + public static function convertToAssocArray ( array $value_arr, array $key_array, $key_prefix = '') | |
13 | + { | |
14 | + // очистка служебного префикса в массиве заголовков | |
15 | + if ($key_prefix) { | |
16 | + $params_array = array_fill( 0, count($key_array), $key_prefix ); | |
17 | + //@todo переписать с использованием array_walk | |
18 | + $key_array = array_map( function ($value, $key_prefix){ return str_replace( $key_prefix, '',$value ); }, $key_array, $params_array ); | |
19 | + //уберем пустые элементы | |
20 | + $key_array = array_filter($key_array, function ($value){ return $value !==''; }); | |
21 | + } | |
22 | + | |
23 | + // преобразуем массив ключей (обернем в массив), для передачи его в качестве параметра в анонимную функцию для array_map | |
24 | + // для этого увеличим размерность массива, что бы при каждом обходе массива $value_arr , функции был доступен исходный массив ключей | |
25 | + $key_array = array_fill( 0, count($value_arr), $key_array ); | |
26 | + // \common\components\CustomVarDamp::dumpAndDie($key_array); | |
27 | + $result = array_map( | |
28 | + function ($value, $key_array) { | |
29 | + $res = $value; | |
30 | + foreach ($value as $key => $sub_value) { | |
31 | + if (isset($key_array[$key])) { | |
32 | + // если такой ключ в базовом массиве (массиве ключей) есть, то заменим новым, иначе просто удалим | |
33 | + $new_key = $key_array[$key]; | |
34 | + if( !array_key_exists( $new_key , $res ) ){ | |
35 | + $res[ $new_key ] = $res[$key]; | |
36 | + } | |
37 | + } | |
38 | + unset( $res[$key] ); | |
39 | + } | |
40 | + | |
41 | + return $res; | |
42 | + }, | |
43 | + $value_arr, $key_array); | |
44 | + return $result; | |
45 | + } | |
46 | + | |
47 | + /** | |
48 | + * @param $value_arr - двумерный массив к которому нужно добавить колонки | |
49 | + * @param $add_array - массив с колонками (ключи) и занчениями колонок | |
50 | + * @return mixed | |
51 | + */ | |
52 | + public function addColumns ( array $value_arr , array $add_array ) | |
53 | + { | |
54 | + $i = 0; | |
55 | + while ($i < count($value_arr)) { | |
56 | + foreach ($add_array as $add_key => $add_value) { | |
57 | + $value_arr[$i][$add_key] = $add_value; | |
58 | + } | |
59 | + $i++; | |
60 | + } | |
61 | + return $value_arr; | |
62 | + } | |
63 | +} | |
0 | 64 | \ No newline at end of file | ... | ... |
backend/components/parsers/CustomCsvParser.php
... | ... | @@ -16,15 +16,27 @@ class CustomCsvParser extends \yii\multiparser\CsvParser { |
16 | 16 | // public $keys = ['first','second', 'third', 'forth', 'fifth']; |
17 | 17 | public function setupConverter() |
18 | 18 | { |
19 | + if (!count($this->converter_conf)) { | |
20 | + if ($this->hasHeaderRow) { | |
21 | + // если у файла есть заголовок, то в результате имеем ассоциативный массив | |
22 | + $this->converter_conf['hasKey'] = 1; | |
23 | + } | |
19 | 24 | |
20 | - if ($this->hasHeaderRow) { | |
21 | - // если у файла есть заголовок, то в результате имеем ассоциативный массив | |
22 | - $this->converter_conf['hasKey'] = 1; | |
23 | 25 | } |
24 | 26 | |
25 | - $this->converter = \Yii::createObject($this->converter_conf); | |
26 | - | |
27 | 27 | } |
28 | 28 | |
29 | + /** | |
30 | + * @param $arr | |
31 | + * @return mixed | |
32 | + * преобразовует значения прочитанного массива в нужные типы, согласно конфигурации конвертера | |
33 | + */ | |
34 | + protected function convert($arr) | |
35 | + { | |
36 | + $result = \Yii::$app->multiparser->convertByConfiguration( $arr, $this->converter_conf ); | |
37 | + | |
38 | + return $result; | |
39 | + | |
40 | + } | |
29 | 41 | |
30 | 42 | } |
31 | 43 | \ No newline at end of file | ... | ... |
backend/components/parsers/config.php
1 | 1 | <?php |
2 | 2 | return [ |
3 | + 'global' => | |
4 | + ['ini' => ['upload_max_filesize' => '20M', | |
5 | + 'post_max_size integer' => '30M', | |
6 | + ]], | |
3 | 7 | 'csv' => |
4 | 8 | ['web' => |
5 | 9 | ['class' => 'backend\components\parsers\CustomCsvParser', |
6 | 10 | 'auto_detect_first_line' => true, |
7 | - 'converter_conf' => ['class' => 'yii\multiparser\Converter', | |
8 | - 'configuration' => [ | |
9 | - "string" => 'DESCR' | |
10 | - ] | |
11 | - ,]], | |
11 | + 'converter_conf' => ['class' => ' backend\components\parsers\CustomConverter', | |
12 | + 'configuration' => ["string" => 'DESCR'],] | |
13 | + ], | |
12 | 14 | |
13 | 15 | 'basic_column' => [ |
14 | 16 | Null => 'Пусто', | ... | ... |
backend/config/main.php
1 | +<?php | |
2 | +namespace backend\controllers; | |
3 | + | |
4 | +use Yii; | |
5 | +use yii\bootstrap\Modal; | |
6 | +use yii\data\ActiveDataProvider; | |
7 | +use yii\filters\AccessControl; | |
8 | +use backend\components\base\BaseController; | |
9 | +use yii\filters\VerbFilter; | |
10 | +use backend\models\Details; | |
11 | +use backend\models\ImporterFiles; | |
12 | +use backend\models\Importer; | |
13 | +use yii\base\ErrorException; | |
14 | + | |
15 | +use common\components\CustomVarDamp; | |
16 | + | |
17 | +/** | |
18 | + * Parser controller | |
19 | + */ | |
20 | +class CheckPriceController extends BaseController | |
21 | +{ | |
22 | + public $layout = "/column"; | |
23 | + | |
24 | + /** | |
25 | + * @inheritdoc | |
26 | + */ | |
27 | + public function behaviors() | |
28 | + { | |
29 | + return [ | |
30 | + 'access' => [ | |
31 | + 'class' => AccessControl::className(), | |
32 | + 'rules' => [ | |
33 | + [ | |
34 | + 'actions' => ['index', 'view'], | |
35 | + 'allow' => true, | |
36 | + 'roles' => ['@'], | |
37 | + ], | |
38 | + ], | |
39 | + ], | |
40 | +// 'verbs' => [ | |
41 | +// 'class' => VerbFilter::className(), | |
42 | +// 'actions' => [ | |
43 | +// 'logout' => ['post'], | |
44 | +// ], | |
45 | +// ], | |
46 | + ]; | |
47 | + } | |
48 | + | |
49 | + /** | |
50 | + * @inheritdoc | |
51 | + */ | |
52 | + public function actions() | |
53 | + { | |
54 | + return [ | |
55 | + 'error' => [ | |
56 | + 'class' => 'yii\web\ErrorAction', | |
57 | + ], | |
58 | + ]; | |
59 | + } | |
60 | + | |
61 | + | |
62 | + public function actionIndex() | |
63 | + { | |
64 | + if(Yii::$app->request->isAjax){ | |
65 | + CustomVarDamp::dumpAndDie(1); | |
66 | + } | |
67 | + | |
68 | + //$query = (new Query())->select('*')->from('{{%importer_files}}')->where(['not', ['time_end' => null]])->orderBy(['upload_time' => SORT_DESC]); | |
69 | + $query = Importer::find()->where(['active' => true])->orderBy(['price_date_update' => SORT_DESC]); | |
70 | + | |
71 | + $provider = new ActiveDataProvider([ | |
72 | + 'query' => $query, | |
73 | + 'pagination' => [ | |
74 | + 'pageSize' => 10, | |
75 | + ], | |
76 | + ]); | |
77 | + return $this->render('index', | |
78 | + [ | |
79 | + 'dataProvider' => $provider, | |
80 | + ]); | |
81 | + } | |
82 | + | |
83 | + | |
84 | + public function actionView ($id) | |
85 | + { | |
86 | + // @todo переписать запрос - нужно условие на равенство даты, а также вьюшка должна быть модальным окном вызываемой по аджаксу | |
87 | + $query = Details::find()->where(['IMPORT_ID' => $id])->orderBy(['timestamp' => SORT_DESC]); | |
88 | + | |
89 | + $provider = new ActiveDataProvider([ | |
90 | + 'query' => $query, | |
91 | + 'pagination' => [ | |
92 | + 'pageSize' => 16, | |
93 | + ], | |
94 | + ]); | |
95 | + return $this->render('view', | |
96 | + ['dataProvider' => $provider]); | |
97 | + } | |
98 | + | |
99 | +} | ... | ... |
1 | +<?php | |
2 | +namespace backend\controllers; | |
3 | + | |
4 | +use Yii; | |
5 | +use yii\bootstrap\Modal; | |
6 | +use yii\data\ActiveDataProvider; | |
7 | +use yii\filters\AccessControl; | |
8 | +use backend\components\base\BaseController; | |
9 | +use yii\filters\VerbFilter; | |
10 | +use backend\models\UploadFileParsingForm; | |
11 | +use yii\web\UploadedFile; | |
12 | +use yii\data\ArrayDataProvider; | |
13 | +use yii\multiparser\DynamicFormHelper; | |
14 | +use backend\components\parsers\CustomParserConfigurator; | |
15 | +use backend\models\Details; | |
16 | +use backend\models\ImporterFiles; | |
17 | +use backend\models\Importer; | |
18 | +use yii\base\ErrorException; | |
19 | +use yii\db\Query; | |
20 | + | |
21 | +use common\components\CustomVarDamp; | |
22 | + | |
23 | +/** | |
24 | + * Parser controller | |
25 | + */ | |
26 | +class Check_priceController extends BaseController | |
27 | +{ | |
28 | + public $layout = "/column"; | |
29 | + | |
30 | + /** | |
31 | + * @inheritdoc | |
32 | + */ | |
33 | + public function behaviors() | |
34 | + { | |
35 | + return [ | |
36 | + 'access' => [ | |
37 | + 'class' => AccessControl::className(), | |
38 | + 'rules' => [ | |
39 | + [ | |
40 | + 'actions' => ['index', 'view'], | |
41 | + 'allow' => true, | |
42 | + 'roles' => ['@'], | |
43 | + ], | |
44 | + ], | |
45 | + ], | |
46 | +// 'verbs' => [ | |
47 | +// 'class' => VerbFilter::className(), | |
48 | +// 'actions' => [ | |
49 | +// 'logout' => ['post'], | |
50 | +// ], | |
51 | +// ], | |
52 | + ]; | |
53 | + } | |
54 | + | |
55 | + /** | |
56 | + * @inheritdoc | |
57 | + */ | |
58 | + public function actions() | |
59 | + { | |
60 | + return [ | |
61 | + 'error' => [ | |
62 | + 'class' => 'yii\web\ErrorAction', | |
63 | + ], | |
64 | + ]; | |
65 | + } | |
66 | + | |
67 | + | |
68 | + public function actionIndex() | |
69 | + { | |
70 | + | |
71 | + if(Yii::$app->request->isAjax){ | |
72 | + CustomVarDamp::dumpAndDie(1); | |
73 | + } | |
74 | + | |
75 | + //$query = (new Query())->select('*')->from('{{%importer_files}}')->where(['not', ['time_end' => null]])->orderBy(['upload_time' => SORT_DESC]); | |
76 | + $query = Importer::find()->where(['active' => true])->orderBy(['price_date_update' => SORT_DESC]); | |
77 | + | |
78 | + $provider = new ActiveDataProvider([ | |
79 | + 'query' => $query, | |
80 | + 'pagination' => [ | |
81 | + 'pageSize' => 10, | |
82 | + ], | |
83 | + ]); | |
84 | + return $this->render('index', | |
85 | + [ | |
86 | + 'dataProvider' => $provider, | |
87 | + ]); | |
88 | + } | |
89 | + | |
90 | + | |
91 | + public function actionView ($id) | |
92 | + { | |
93 | + | |
94 | + | |
95 | + | |
96 | + | |
97 | + $query = Details::find()->where(['IMPORT_ID' => $id])->orderBy(['timestamp' => SORT_DESC]); | |
98 | + | |
99 | + $provider = new ActiveDataProvider([ | |
100 | + 'query' => $query, | |
101 | + 'pagination' => [ | |
102 | + 'pageSize' => 16, | |
103 | + ], | |
104 | + ]); | |
105 | + return $this->render('view', | |
106 | + ['dataProvider' => $provider]); | |
107 | + } | |
108 | +} | ... | ... |
backend/controllers/ParserController.php
... | ... | @@ -2,6 +2,7 @@ |
2 | 2 | namespace backend\controllers; |
3 | 3 | |
4 | 4 | use Yii; |
5 | +use yii\data\ActiveDataProvider; | |
5 | 6 | use yii\filters\AccessControl; |
6 | 7 | use backend\components\base\BaseController; |
7 | 8 | use yii\filters\VerbFilter; |
... | ... | @@ -10,16 +11,21 @@ use yii\web\UploadedFile; |
10 | 11 | use yii\data\ArrayDataProvider; |
11 | 12 | use yii\multiparser\DynamicFormHelper; |
12 | 13 | use backend\components\parsers\CustomParserConfigurator; |
14 | +use backend\models\Details; | |
15 | +use backend\models\ImporterFiles; | |
16 | +use backend\models\Importer; | |
17 | +use yii\base\ErrorException; | |
18 | +use yii\db\Query; | |
13 | 19 | |
14 | 20 | use common\components\CustomVarDamp; |
15 | 21 | |
16 | 22 | /** |
17 | 23 | * Parser controller |
18 | 24 | */ |
19 | - | |
20 | 25 | class ParserController extends BaseController |
21 | 26 | { |
22 | 27 | public $layout = "/column"; |
28 | + | |
23 | 29 | /** |
24 | 30 | * @inheritdoc |
25 | 31 | */ |
... | ... | @@ -30,7 +36,6 @@ class ParserController extends BaseController |
30 | 36 | 'class' => AccessControl::className(), |
31 | 37 | 'rules' => [ |
32 | 38 | [ |
33 | - 'actions' => ['index','results','write'], | |
34 | 39 | 'allow' => true, |
35 | 40 | 'roles' => ['@'], |
36 | 41 | ], |
... | ... | @@ -58,34 +63,84 @@ class ParserController extends BaseController |
58 | 63 | } |
59 | 64 | |
60 | 65 | |
61 | - | |
62 | - public function actionIndex() | |
66 | + public function actionIndex($mode = 0) | |
63 | 67 | { |
64 | 68 | $model = new UploadFileParsingForm(); |
65 | - | |
69 | + // установим режим, 0 - ручная загрузка, 1 - автозагрузка | |
70 | + $model->mode = $mode; | |
71 | + //CustomVarDamp::dumpAndDie(phpinfo()); | |
66 | 72 | return $this->render('index', ['model' => $model]); |
67 | 73 | } |
68 | 74 | |
69 | - public function actionResults(){ | |
75 | +// public function beforeAction($action) | |
76 | +// { | |
77 | +// if($action->actionMethod ='actionResults'){ | |
78 | +// CustomVarDamp::dumpAndDie(phpinfo()); | |
79 | +// } | |
80 | +// } | |
70 | 81 | |
71 | - $model = new UploadFileParsingForm(); | |
82 | + public function actionResults($mode = 0) | |
83 | + { | |
84 | + $model = new UploadFileParsingForm(['mode' => $mode]); | |
72 | 85 | $data = []; |
73 | 86 | if ($model->load(Yii::$app->request->post())) { |
74 | 87 | $model->file = UploadedFile::getInstance($model, 'file'); |
75 | - | |
88 | + // первый проход - валидируем, сохраняем файл, ложим в кеш (для ручной загрузки) отпарсенные данные и параметры модели (потом при записи в базу данных они пригодятся) | |
76 | 89 | if ($model->validate()) { |
77 | - $filePath = Yii::getAlias('@webroot') . '/uploads/' . $model->file->baseName . '.' . $model->file->extension; | |
90 | + // запишем дату загрузки файла в таблицу файлов поставщика (ImportersFiles) | |
91 | + $files_model = new ImporterFiles(); | |
92 | + // id поставщика получим из конфигурации | |
93 | + $files_model->load(['ImporterFiles' => $model->toArray()]); | |
94 | + try { | |
95 | + $files_model->save(); | |
96 | + } catch (ErrorException $e) { | |
97 | + CustomVarDamp::dump($e->getMessage()); | |
98 | + } | |
99 | + // получим id только что записанной записи - его запишем в название файла | |
100 | + $model->record_id = $files_model->find() | |
101 | + ->where(['importer_id' => $files_model->importer_id]) | |
102 | + ->orderBy(['id' => SORT_DESC]) | |
103 | + ->one() | |
104 | + ->id; | |
78 | 105 | |
79 | - $model->file->saveAs( $filePath ); | |
80 | - $data = $model->readFile($filePath); | |
106 | + $file_name = $model->record_id . '.' . $model->file->extension; | |
81 | 107 | |
82 | - Yii::$app->getCache()->set( 'parser_data', json_encode($data) ); | |
108 | + if ($model->mode) { | |
109 | + $model->file_path = Yii::getAlias('@auto_upload') . '/' . $file_name; | |
110 | + } else { | |
111 | + $model->file_path = Yii::getAlias('@manual_upload') . '/' . $file_name; | |
112 | + } | |
83 | 113 | |
84 | - } | |
114 | + $model->file->saveAs($model->file_path); | |
85 | 115 | |
86 | - } else if( Yii::$app->getCache()->get( 'parser_data' )) { | |
116 | + // для авто загрузки, обработка завершена | |
117 | + if ($model->mode) { | |
118 | + $model->success = true; | |
119 | + return $this->render('index', ['model' => $model]); | |
120 | + } | |
87 | 121 | |
88 | - $data = json_decode( Yii::$app->getCache()->get( 'parser_data' ),true ); | |
122 | + // === ручная загрузка =========== | |
123 | + //запускаем парсинг | |
124 | + $data = $model->readFile(); | |
125 | + // сохраняем в кеш отпарсенные даные | |
126 | + Yii::$app->getCache()->set('parser_data', json_encode($data)); | |
127 | + // сохраняем в кеш модель - в ней настройки для дальнейшей обработки данных | |
128 | + Yii::$app->getCache()->set('parser_configuration', serialize($model)); | |
129 | + | |
130 | + | |
131 | + } else { | |
132 | + // не прошла валидация форма загрузки файлов | |
133 | + //@todo - отправка на страницу ошибок | |
134 | + $errors_arr = $model->getErrors(); | |
135 | + foreach ($errors_arr as $error) { | |
136 | + CustomVarDamp::dump(array_values($error)); | |
137 | + } | |
138 | + die; | |
139 | + } | |
140 | + // листаем пагинатором, или повторно вызываем - считываем из кеша отпрасенные данные | |
141 | + } else if (Yii::$app->getCache()->get('parser_data')) { | |
142 | + | |
143 | + $data = json_decode(Yii::$app->getCache()->get('parser_data'), true); | |
89 | 144 | |
90 | 145 | } |
91 | 146 | |
... | ... | @@ -96,38 +151,168 @@ class ParserController extends BaseController |
96 | 151 | ], |
97 | 152 | ]); |
98 | 153 | |
99 | - // CustomVarDamp::dumpAndDie($data); | |
100 | - $header_model = DynamicFormHelper::CreateDynamicModel( count( $data[0] ) ); | |
154 | + //формируем заголовок для пользователя, где он сможет выбрать соответсвие полей (выпадающий список) | |
155 | + $header_model = DynamicFormHelper::CreateDynamicModel(count($data[0])); | |
101 | 156 | |
102 | - // CustomVarDamp::dumpAndDie(Yii::$app->multiparser->getConfiguration('csv','basic_column')); | |
103 | 157 | return $this->render('results', |
104 | 158 | ['model' => $data, |
105 | 159 | 'header_model' => $header_model, |
106 | - 'basic_column' => Yii::$app->multiparser->getConfiguration('csv','basic_column'), | |
160 | + // список колонок для выбора | |
161 | + 'basic_column' => Yii::$app->multiparser->getConfiguration('csv', 'basic_column'), | |
107 | 162 | 'dataProvider' => $provider]); |
108 | 163 | } |
109 | 164 | |
110 | -public function actionWrite() | |
111 | -{ | |
112 | - //CustomVarDamp::dumpAndDie(Yii::$app->request->post()); | |
165 | + public function actionWrite() | |
166 | + { | |
167 | + //получим колонки которые выбрал пользователь | |
168 | + $arr_attributes = Yii::$app->request->post()['DynamicModel']; | |
169 | + //соберем модель по полученным данным | |
170 | + $model = DynamicFormHelper::CreateDynamicModel($arr_attributes); | |
171 | + //добавим правила валидации (колонки должны быть те что указаны в конфиге) | |
172 | + foreach ($arr_attributes as $key => $value) { | |
173 | + $model->addRule($key, 'in', ['range' => array_keys(Yii::$app->multiparser->getConfiguration('csv', 'basic_column'))]); | |
174 | + } | |
175 | + | |
176 | + // провалидируем выбранные колонки | |
177 | + if ($model->validate()) { | |
178 | + | |
179 | + // валидация успешна у нас есть соответсвие колонок, преобразуем в массив данное соответсвие для дальнейшей работы | |
180 | + $arr = $model->toArray(); | |
181 | + | |
182 | + // получим данные из кеша | |
183 | + if (Yii::$app->getCache()->get('parser_data') && Yii::$app->getCache()->get('parser_configuration')) { | |
184 | + $data = json_decode(Yii::$app->getCache()->get('parser_data'), true); | |
185 | + $configuration = unserialize(Yii::$app->getCache()->get('parser_configuration')); | |
186 | + } else { | |
187 | + CustomVarDamp::dumpAndDie('Ошибка кеша'); | |
188 | + } | |
189 | + | |
190 | + // соотнесем отпарсенные данные с соответсивем полученным от пользователя | |
191 | + // для этого преобразуем массив отпарсенных данных - назначим ключи согласно соответствию | |
192 | + $data = \Yii::$app->multiparser->convertToAssocArray($data, $arr, 'attr_'); | |
193 | + | |
194 | + | |
195 | + // 1. запишем дату старта в таблицу файлов поставщика (ImportersFiles) | |
196 | + // id загруженного файла получим из конфигурации | |
197 | + $files_model = ImporterFiles::findOne( $configuration->record_id ); | |
198 | + | |
199 | + //$files_model->load(['ImporterFiles' => $configuration->toArray()]); | |
200 | + $update_date = date('Y-m-d H:i:s'); | |
201 | + $files_model->time_start = $update_date; | |
202 | + // запишем дату начала загрузки | |
203 | + if (!$files_model->save()) { | |
204 | + CustomVarDamp::dumpAndDie($files_model->getErrors()); | |
205 | + } | |
206 | + | |
207 | + | |
208 | + // 2. запишем полученные данные в таблицу товаров (Details) | |
209 | + $details_model = new Details(); | |
210 | + // проверим все ли обязательные колонки были указаны пользователем | |
211 | + $details_model->load(['Details' => $data[0]]); | |
212 | + if ($details_model->validate()) { | |
213 | + // дополним данные значением импортера и даты обновления цены | |
214 | + $data = \Yii::$app->multiparser->addColumns($data, ['IMPORT_ID' => $configuration->importer_id, 'timestamp' => $update_date]); | |
215 | + | |
216 | + try { | |
217 | + //@todo add transaction | |
218 | + // попытаемся вставить данные в БД с апдейтом по ключам | |
219 | + $details_model->ManualInsert($data); | |
220 | + | |
221 | + // 3. зафиксируем дату конца загрузки в файлах поставщика | |
222 | + | |
223 | + $files_model->time_end = date('Y-m-d H:i:s'); | |
224 | + // CustomVarDamp::dumpAndDie($files_model); | |
225 | + if (!$files_model->save()) { | |
226 | + CustomVarDamp::dumpAndDie($files_model->getErrors()); | |
227 | + } | |
228 | + | |
229 | + // 4. зафиксируем дату загрузки в таблице поставщиков | |
230 | + $imp_model = Importer::findOne($configuration['importer_id']); | |
231 | + $imp_model->price_date_update = $update_date; | |
232 | + | |
233 | + if (!$imp_model->save()) { | |
234 | + CustomVarDamp::dumpAndDie($imp_model->getErrors()); | |
235 | + } | |
236 | + $configuration['success'] = true; | |
237 | + // все прошло успешно - очищаем кеш | |
238 | + Yii::$app->getCache()->delete('parser_data'); | |
239 | + Yii::$app->getCache()->delete('parser_configuration'); | |
240 | + | |
241 | + unlink($configuration['file_path']); | |
242 | + return $this->render('index', ['model' => $configuration]); | |
243 | + | |
244 | + } catch (ErrorException $e) { | |
245 | + CustomVarDamp::dump($e->getMessage()); | |
246 | + } | |
247 | + } | |
248 | + if ($details_model->hasErrors()) { | |
249 | + $errors_arr = $details_model->getErrors(); | |
250 | + foreach ($errors_arr as $error) { | |
251 | + CustomVarDamp::dump(array_values($error)); | |
252 | + } | |
253 | + | |
254 | + } | |
255 | + | |
256 | + | |
257 | + } | |
113 | 258 | |
114 | - $arr_attributes = Yii::$app->request->post()['DynamicModel']; | |
115 | - $model = DynamicFormHelper::CreateDynamicModel( $arr_attributes ); | |
116 | - foreach ($arr_attributes as $key => $value) { | |
117 | - $model->addRule($key, 'in', ['range' => array_keys( Yii::$app->multiparser->getConfiguration('csv','basic_column') )]); | |
118 | 259 | } |
119 | 260 | |
120 | - //CustomVarDamp::dumpAndDie($model); | |
121 | - if ($model->validate()) { | |
122 | - $arr = $model->toArray(); | |
123 | - $data = json_decode( Yii::$app->getCache()->get( 'parser_data' ),true ); | |
261 | + public function actionAutoUpload() | |
262 | + { | |
263 | + $query = Importer::find()->where(['active' => true])->orderBy(['price_date_update' => SORT_DESC]); | |
124 | 264 | |
125 | - // CustomVarDamp::dumpAndDie(DynamicFormHelper::CreateAssocArray($data, $arr)); | |
126 | - CustomVarDamp::dumpAndDie($arr); | |
265 | + $provider = new ActiveDataProvider([ | |
266 | + 'query' => $query, | |
267 | + 'pagination' => [ | |
268 | + 'pageSize' => 10, | |
269 | + ], | |
270 | + ]); | |
271 | + return $this->render('check_price', | |
272 | + [ | |
273 | + 'dataProvider' => $provider]); | |
127 | 274 | } |
128 | 275 | |
276 | + public function actionServerFiles () | |
277 | + { | |
278 | + $arr_id = []; | |
279 | + // получим список файлов которые ожидают к загрузке | |
280 | + foreach (glob(Yii::getAlias('@auto_upload') . '/*') as $server_file) { | |
281 | + $file_id = basename($server_file,".csv"); | |
282 | + $arr_id[] = (int) $file_id; | |
283 | + } | |
129 | 284 | |
285 | + $query = ImporterFiles::find()->where(['in', 'id', $arr_id])->orderBy(['upload_time' => SORT_DESC]); | |
130 | 286 | |
131 | -} | |
287 | + $provider = new ActiveDataProvider([ | |
288 | + 'query' => $query, | |
289 | + 'pagination' => [ | |
290 | + 'pageSize' => 10, | |
291 | + ], | |
292 | + ]); | |
293 | + return $this->render('server-files', | |
294 | + [ | |
295 | + 'dataProvider' => $provider]); | |
296 | + } | |
297 | + | |
298 | + public function actionDelete ($id) | |
299 | + { | |
300 | + if(Yii::$app->request->isAjax){ | |
301 | + CustomVarDamp::dumpAndDie(1); | |
302 | + } | |
303 | + | |
304 | + $files_model = new ImporterFiles(); | |
305 | + try { | |
306 | + | |
307 | + $files_model->delete($id); | |
308 | + unlink(Yii::getAlias('@auto_upload') . '/' . $id . '.csv' ); | |
309 | + | |
310 | + } catch (ErrorException $e) { | |
132 | 311 | |
312 | + CustomVarDamp::dump($e->getMessage()); | |
313 | + | |
314 | + } | |
315 | + | |
316 | + $this->redirect('server-files'); | |
317 | + } | |
133 | 318 | } | ... | ... |
1 | +<?php | |
2 | + | |
3 | +namespace backend\models; | |
4 | + | |
5 | +use Yii; | |
6 | +use backend\components\base\BaseActiveRecord; | |
7 | + | |
8 | +/** | |
9 | + * This is the model class for table "{{%details}}". | |
10 | + * | |
11 | + * @property string $ID | |
12 | + * @property string $IMPORT_ID | |
13 | + * @property string $BRAND | |
14 | + * @property string $ARTICLE | |
15 | + * @property string $FULL_ARTICLE | |
16 | + * @property double $PRICE | |
17 | + * @property string $DESCR | |
18 | + * @property string $BOX | |
19 | + * @property string $ADD_BOX | |
20 | + * @property string $GROUP | |
21 | + * @property string $timestamp | |
22 | + */ | |
23 | +class Details extends BaseActiveRecord | |
24 | +{ | |
25 | + const KEY_COLUMN = ['IMPORT_ID','BRAND','ARTICLE']; | |
26 | + const BATCH = 500; | |
27 | + /** | |
28 | + * @inheritdoc | |
29 | + */ | |
30 | + public static function tableName() | |
31 | + { | |
32 | + return '{{%details}}'; | |
33 | + } | |
34 | + | |
35 | + /** | |
36 | + * @inheritdoc | |
37 | + */ | |
38 | + public function rules() | |
39 | + { | |
40 | + return [ | |
41 | + [[ 'BRAND', 'ARTICLE', 'PRICE', 'DESCR', 'BOX'], 'required'], | |
42 | + // [['IMPORT_ID', 'BOX', 'ADD_BOX'], 'integer'], | |
43 | + [['PRICE'], 'number'], | |
44 | + [['timestamp'], 'safe'], | |
45 | + [['BRAND', 'ARTICLE'], 'string', 'max' => 100], | |
46 | + [['FULL_ARTICLE'], 'string', 'max' => 150], | |
47 | + [['DESCR', 'GROUP'], 'string', 'max' => 200] | |
48 | + ]; | |
49 | + } | |
50 | + | |
51 | + /** | |
52 | + * @inheritdoc | |
53 | + */ | |
54 | + public function attributeLabels() | |
55 | + { | |
56 | + return [ | |
57 | + 'ID' => Yii::t('app', 'ID'), | |
58 | + 'IMPORT_ID' => Yii::t('app', 'Import ID'), | |
59 | + 'BRAND' => Yii::t('app', 'Brand'), | |
60 | + 'ARTICLE' => Yii::t('app', 'Article'), | |
61 | + 'FULL_ARTICLE' => Yii::t('app', 'Full Article'), | |
62 | + 'PRICE' => Yii::t('app', 'Price'), | |
63 | + 'DESCR' => Yii::t('app', 'Descr'), | |
64 | + 'BOX' => Yii::t('app', 'Box'), | |
65 | + 'ADD_BOX' => Yii::t('app', 'Add Box'), | |
66 | + 'GROUP' => Yii::t('app', 'Group'), | |
67 | + 'timestamp' => Yii::t('app', 'Timestamp'), | |
68 | + ]; | |
69 | + } | |
70 | + | |
71 | + public function ManualInsert ($data) | |
72 | + { | |
73 | + // \common\components\CustomVarDamp::dumpAndDie($data); | |
74 | + $table_name = self::tableName(); | |
75 | + $keys_arr = array_keys( $data[0] ); | |
76 | + // найдем те поля которые не являются ключами. Их нужно будет при дубляже апдейтить | |
77 | + $fields_arr_to_update = array_diff( $keys_arr, $this::KEY_COLUMN ); | |
78 | + | |
79 | + $query_update = ' on duplicate key update '; | |
80 | + foreach ($fields_arr_to_update as $field) { | |
81 | + $query_update .= "{$field} = values({$field}),"; | |
82 | + } | |
83 | + // удалим последнюю запятую | |
84 | + $query_update = substr($query_update, 0, strlen($query_update) - 1); | |
85 | + | |
86 | + // запросы будем выполнять пакетами | |
87 | + // размер пакета установлен в константе | |
88 | + // разобъем массив на пакеты и будем их проходить | |
89 | + $data = array_chunk($data, $this::BATCH ); | |
90 | + foreach( $data as $current_batch_array ){ | |
91 | + | |
92 | + //воспользуемся пакетной вставкой от фреймворка, плюс сразу с экранированием и защитой от инъекций | |
93 | + $query_insert = Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $current_batch_array)->sql; | |
94 | + // добавим фрагмент с апдейтом при дубляже | |
95 | + $query = "{$query_insert} {$query_update}"; | |
96 | + // \common\components\CustomVarDamp::dumpAndDie($query); | |
97 | + $res = Yii::$app->db->createCommand($query)->execute(); | |
98 | + | |
99 | + } | |
100 | + | |
101 | + } | |
102 | +} | ... | ... |
1 | +<?php | |
2 | +/** | |
3 | + * Created by PhpStorm. | |
4 | + * User: Cibermag | |
5 | + * Date: 15.09.2015 | |
6 | + * Time: 16:49 | |
7 | + */ | |
8 | + | |
9 | +namespace backend\models; | |
10 | + | |
11 | +use yii\base\Model; | |
12 | +use Yii; | |
13 | + | |
14 | +class Details_old extends Model{ | |
15 | + const KEY_COLUMN = ['IMPORT_ID','BRAND','ARTICLE']; | |
16 | + const BATCH = 500; | |
17 | + | |
18 | + private $mode; | |
19 | + | |
20 | + // обязательные поля модели | |
21 | + public $BRAND; | |
22 | + public $ARTICLE; | |
23 | + public $PRICE; | |
24 | + public $BOX; | |
25 | + | |
26 | + function __construct($mode) | |
27 | + { | |
28 | + $this->mode = $mode; | |
29 | + } | |
30 | + | |
31 | + public function rules() | |
32 | + { | |
33 | + return [ | |
34 | + [['BRAND','ARTICLE', 'PRICE', 'BOX'], 'required' ], | |
35 | + ]; | |
36 | + } | |
37 | + | |
38 | + public function formName() | |
39 | + { | |
40 | + return 'Details'; | |
41 | + } | |
42 | + | |
43 | + | |
44 | + public static function tableName() | |
45 | + { | |
46 | + return '{{%details}}'; | |
47 | + } | |
48 | + | |
49 | +// //@todo вероятно этой функции не место здесь | |
50 | +// public function prepareData ( $data, $configuration ) | |
51 | +// { | |
52 | +// if ( isset($configuration['importer_id']) && $configuration['importer_id']) { | |
53 | +// $data = \Yii::$app->multiparser->addColumn( $data, 'IMPORT_ID', $configuration['importer_id'] ); | |
54 | +// } | |
55 | +// // \common\components\CustomVarDamp::dumpAndDie($data); | |
56 | +// return $data; | |
57 | +// } | |
58 | + | |
59 | + /** | |
60 | + * @param $data - двумерный массив данных для записи в таблицу details | |
61 | + * @throws \yii\db\Exception | |
62 | + * вставляет записи с апдейтом при дубляже ключей | |
63 | + */ | |
64 | + public function save ($data) | |
65 | + { | |
66 | + $table_name = self::tableName(); | |
67 | + $keys_arr = array_keys( $data[0] ); | |
68 | + // найдем те поля которые не являются ключами. Их нужно будет при дубляже апдейтить | |
69 | + $fields_arr_to_update = array_diff( $keys_arr, $this::KEY_COLUMN ); | |
70 | + | |
71 | + $query_update = ' on duplicate key update '; | |
72 | + foreach ($fields_arr_to_update as $field) { | |
73 | + $query_update .= "{$field} = values({$field}),"; | |
74 | + } | |
75 | + // удалим последнюю запятую | |
76 | + $query_update = substr($query_update, 0, strlen($query_update) - 1); | |
77 | + | |
78 | + // запросы будем выполнять пакетами | |
79 | + // размер пакета установлен в константе | |
80 | + // разобъем массив на пакеты и будем их проходить | |
81 | + $data = array_chunk($data, $this::BATCH ); | |
82 | + foreach( $data as $current_batch_array ){ | |
83 | + | |
84 | + //воспользуемся пакетной вставкой от фреймворка, плюс сразу с экранированием и защитой от инъекций | |
85 | + $query_insert = Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $current_batch_array)->sql; | |
86 | + // добавим фрагмент с апдейтом при дубляже | |
87 | + $query = "{$query_insert} {$query_update}"; | |
88 | + // \common\components\CustomVarDamp::dumpAndDie($query); | |
89 | + $res = Yii::$app->db->createCommand($query)->execute(); | |
90 | + | |
91 | + } | |
92 | + | |
93 | + } | |
94 | +} | |
95 | + | |
96 | +// | |
97 | + | |
98 | +//$q = " INSERT INTO {$table_name} ({$keys_string}) VALUES ("; | |
99 | + | |
100 | +//$q .= " on duplicate key update `FULL_ARTICLE` = values (`FULL_ARTICLE`), | |
101 | +// `PRICE` = values (`PRICE`), | |
102 | +// `DESCR` = values(`DESCR`), | |
103 | +// `BOX` = values(`BOX`), | |
104 | +// `ADD_BOX` = values(`ADD_BOX`), | |
105 | +// `GROUP` = values(`GROUP`);"; | |
106 | + | |
107 | +// INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6) | |
108 | +// ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b); | |
109 | + | |
110 | + | |
111 | + | |
112 | +//INSERT INTO `books` (`UserId`, `BookId`, `Count`) VALUES (13, 1001, 3) | |
113 | +//ON DUPLICATE KEY UPDATE `Count` = `Count` + VALUES(`Count`); | |
114 | + | |
115 | +//$values_string = ''; | |
116 | +//$keys_arr = array_keys( $data[0] ); | |
117 | +//$keys_string = implode( ',', $keys_arr); | |
118 | +//$table_name = self::tableName(); | |
119 | +//$current_batch = 0; | |
120 | +//for ($i = $current_batch; $i < $this::BATCH AND $i < count($data); $i++) { | |
121 | +// $values_string .= '(' . implode( ',', $data[$i]) . '),'; | |
122 | +//} | |
123 | +// for ($current_batch = $this::BATCH; $current_batch<count($data); $current_batch + $this::BATCH ) | |
124 | +//// удалим последнюю запятую | |
125 | +//$values_string = substr($values_string, 0, strlen($values_string) - 1) . ' '; | |
126 | +////\common\components\CustomVarDamp::dumpAndDie($values_string); | |
127 | +//// $query = "INSERT INTO {$table_name}({$keys_string}) VALUES {$values_string}"; | |
128 | +//// on duplicate key update `PRICE` = values (`PRICE`),`DESCR` = values(`DESCR`),`BOX` = values(`BOX`)"; | |
129 | +//$query_insert = Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $data)->sql; | |
130 | +//$query = "{$query_insert} on duplicate key update `PRICE` = values (`PRICE`),`DESCR` = values(`DESCR`),`BOX` = values(`BOX`)"; | |
131 | +//$res = Yii::$app->db->createCommand($query)->execute(); | |
132 | + | |
133 | + | |
134 | + | |
135 | +// Yii::$app->db->createCommand()->batchInsert($table_name, $keys_arr, $data)->sql execute(); | |
0 | 136 | \ No newline at end of file | ... | ... |
backend/models/Importer.php
... | ... | @@ -47,13 +47,14 @@ class Importer extends BaseActiveRecord |
47 | 47 | public function rules() |
48 | 48 | { |
49 | 49 | return [ |
50 | - [['code', 'name', 'name_price', 'currency_id', 'delivery', 'email', 'info', 'PARSER_FIELD_SIGN', 'price_date_update'], 'required'], | |
50 | + [['code', 'name', 'currency_id', 'delivery', 'price_date_update'], 'required'], | |
51 | + [['name_price', 'email', 'PARSER_FIELD_SIGN', 'info'], 'safe'], | |
51 | 52 | [['currency_id', 'active', 'PARSER_IS_ACTIVE', 'PARSER_COLUMN_COUNT', 'PARSER_FIELD_BRAND', 'PARSER_FIELD_ARTICLE', 'PARSER_FIELD_ARTICLE_PREFIX', 'PARSER_FIELD_PRICE', 'PARSER_FIELD_DESCR', 'PARSER_FIELD_BOX', 'PARSER_FIELD_ADD_BOX', 'PARSER_FIELD_GROUP_RG'], 'integer'], |
52 | 53 | [['info'], 'string'], |
53 | 54 | [['PARSER_FIELD_MULTIPLIER'], 'number'], |
54 | 55 | [['code', 'name', 'name_price', 'delivery', 'email'], 'string', 'max' => 254], |
55 | 56 | [['PARSER_FIELD_SIGN'], 'string', 'max' => 1], |
56 | - [['price_date_update'], 'string', 'max' => 15], | |
57 | + // [['price_date_update'], 'string', 'max' => 15], | |
57 | 58 | [['code'], 'unique'], |
58 | 59 | [['name'], 'unique'] |
59 | 60 | ]; | ... | ... |
1 | +<?php | |
2 | + | |
3 | +namespace backend\models; | |
4 | + | |
5 | +use common\components\CustomVarDamp; | |
6 | +use Yii; | |
7 | + | |
8 | +/** | |
9 | + * This is the model class for table "{{%importer_files}}". | |
10 | + * | |
11 | + * @property integer $id | |
12 | + * @property string $importer_id | |
13 | + * @property string $upload_time | |
14 | + * @property string $time_start | |
15 | + * @property string $time_end | |
16 | + */ | |
17 | +class ImporterFiles extends \yii\db\ActiveRecord | |
18 | +{ | |
19 | + /** | |
20 | + * @inheritdoc | |
21 | + */ | |
22 | + public static function tableName() | |
23 | + { | |
24 | + return '{{%importer_files}}'; | |
25 | + } | |
26 | + | |
27 | + /** | |
28 | + * @inheritdoc | |
29 | + */ | |
30 | + public function rules() | |
31 | + { | |
32 | + return [ | |
33 | + [['importer_id'], 'required'], | |
34 | + [['importer_id'], 'integer'], | |
35 | + [['upload_time', 'time_start', 'time_end'], 'safe'] | |
36 | + ]; | |
37 | + } | |
38 | + | |
39 | + public function getImporter () | |
40 | + { | |
41 | + return $this->hasOne(Importer::className(), ['id' => 'importer_id'])->one()->name; | |
42 | + } | |
43 | + | |
44 | + /** | |
45 | + * @inheritdoc | |
46 | + */ | |
47 | + public function attributeLabels() | |
48 | + { | |
49 | + return [ | |
50 | + 'id' => Yii::t('app', 'ID'), | |
51 | + 'importer_id' => Yii::t('app', 'Importer ID'), | |
52 | + 'upload_time' => Yii::t('app', 'Upload Time'), | |
53 | + 'time_start' => Yii::t('app', 'Time Start'), | |
54 | + 'time_end' => Yii::t('app', 'Time End'), | |
55 | + ]; | |
56 | + } | |
57 | +} | ... | ... |
backend/models/UploadFileParsingForm.php
... | ... | @@ -14,28 +14,48 @@ class UploadFileParsingForm extends Model |
14 | 14 | /** |
15 | 15 | * @var UploadedFile file attribute |
16 | 16 | */ |
17 | + // атрибуты формы | |
17 | 18 | public $file; |
18 | - public $importer; | |
19 | + public $importer_id; | |
19 | 20 | public $action; |
20 | 21 | public $delimiter; |
21 | 22 | public $delete_price; |
22 | 23 | public $delete_prefix; |
23 | 24 | |
25 | + // служебные атрибуты | |
26 | + public $file_path; | |
27 | + public $success; | |
28 | + public $mode; //0 - режим ручной загрузки, 1 - режим автозагрузки | |
29 | + public $record_id; // id таблицы в которую записывается информация о файле | |
30 | + | |
24 | 31 | /** |
25 | 32 | * @return array the validation rules. |
26 | 33 | */ |
34 | + public function __construct($config = []) | |
35 | + { | |
36 | + parent::__construct($config); | |
37 | + if ( $this->mode ) { | |
38 | + // автозагрузка, проставим сценарий | |
39 | + $this->scenario = 'auto'; | |
40 | + } | |
41 | + | |
42 | + } | |
43 | + | |
44 | + | |
27 | 45 | public function rules() |
28 | 46 | { |
29 | 47 | return [ |
30 | - ['importer', 'required', 'message' => 'Не указан поставщик!' ], | |
48 | + ['importer_id', 'required', 'message' => 'Не указан поставщик!' ], | |
31 | 49 | ['file', 'required', 'message' => 'Не выбран файл!' ], |
32 | 50 | //@todo - not working this file validator!!! - fixed |
33 | 51 | [['file'], 'file'],// 'extensions' => ['csv', 'xml'] ], |
34 | 52 | // 'wrongMimeType' => 'Указан неподдерживаемый тип файла. Можно выбирать csv, xml файлы.' ], |
35 | - ['importer', 'integer','max' => 999999, 'min' => 0 ], | |
36 | - [['action','delete_prefix', 'delete_price'], 'boolean'], | |
53 | + ['importer_id', 'integer','max' => 999999, 'min' => 0 ], | |
54 | + [['action','delete_prefix', 'delete_price', 'success'], 'boolean', 'except' => 'auto' ], // только для ручной загрузки | |
37 | 55 | ['delimiter', 'string', 'max' => 1], |
38 | - ['delimiter', 'default', 'value' => ';'] | |
56 | + [['mode','record_id'], 'safe'], | |
57 | + ['delimiter', 'default', 'value' => ';'], | |
58 | + [ 'success', 'default', 'value' => false] | |
39 | 59 | |
40 | 60 | ]; |
41 | 61 | } |
... | ... | @@ -44,17 +64,34 @@ class UploadFileParsingForm extends Model |
44 | 64 | { |
45 | 65 | return [ |
46 | 66 | 'file' => Yii::t('app', 'Источник'), |
47 | - 'importer' => Yii::t('app', 'Поставщик'), | |
67 | + 'importer_id' => Yii::t('app', 'Поставщик'), | |
48 | 68 | 'delimiter' => Yii::t('app', 'Разделитель'), |
49 | 69 | ]; |
50 | 70 | } |
51 | 71 | |
52 | - public function readFile($filePath){ | |
72 | + public function readFile(){ | |
53 | 73 | |
54 | - $data = Yii::$app->multiparser->parse($filePath); | |
74 | + $data = Yii::$app->multiparser->parse( $this->file_path ); | |
55 | 75 | if( !is_array($data) ){ |
56 | 76 | $data = ['No results']; |
57 | 77 | } |
78 | + | |
58 | 79 | return $data; |
59 | 80 | } |
81 | + | |
82 | + public function fields() | |
83 | + { | |
84 | + return [ | |
85 | + | |
86 | + 'importer_id', | |
87 | + 'delimiter', | |
88 | + 'delete_price', | |
89 | + 'delete_prefix', | |
90 | + 'file_path', | |
91 | + // id записи таблицы ImportersFiles, | |
92 | + // 'id' => 'record_id', | |
93 | + ]; | |
94 | + } | |
95 | + | |
96 | + | |
60 | 97 | } |
61 | 98 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +use yii\helpers\Html; | |
3 | +use yii\grid\GridView; | |
4 | +use yii\grid\SerialColumn; | |
5 | +use yii\grid\ActionColumn; | |
6 | +use yii\widgets\Pjax; | |
7 | + | |
8 | + | |
9 | +/* @var $this yii\web\View */ | |
10 | +/* @var $searchModel backend\models\CatalogSearch */ | |
11 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
12 | + | |
13 | +$this->title = 'Проверка прайсов'; | |
14 | +$this->params['breadcrumbs'][] = $this->title; | |
15 | +?> | |
16 | +<div class="catalog-index"> | |
17 | + | |
18 | + <h1><?= Html::encode($this->title) ?></h1> | |
19 | + | |
20 | + | |
21 | + <?= GridView::widget( ['dataProvider' => $dataProvider, | |
22 | + 'columns' => [['class' => SerialColumn::className()], | |
23 | + [ | |
24 | + 'class' => ActionColumn::className(), | |
25 | + 'template'=>'{view}', | |
26 | + 'contentOptions' => function ($model, $key, $index, $column){ | |
27 | + return ['data' => ['id' => $model->id, 'date' => $model->price_date_update]]; | |
28 | + } | |
29 | + ], | |
30 | + [ | |
31 | + 'label' =>'Поставщик', | |
32 | + 'value' => function ($data) { | |
33 | + return '№ ' .$data->id . ' ' . $data->name; | |
34 | + }, | |
35 | + ], | |
36 | + ['label' =>'Дата обновления', | |
37 | + 'attribute' => 'price_date_update' ], | |
38 | + ['label' => 'Кол-во дней', | |
39 | + 'value' => function ($data) { | |
40 | + $date1 = new DateTime("now"); | |
41 | + $date2 = new DateTime( $data->price_date_update ); | |
42 | + $quo_days = $date2->diff($date1)->format('%R%a'); | |
43 | + // уберем первый символ - там знак "+" | |
44 | + $quo_days = substr( $quo_days, 1, strlen($quo_days) ); | |
45 | + $quo_days = (int) $quo_days; | |
46 | + | |
47 | + if($quo_days > 15) | |
48 | + $quo_days = '>15'; | |
49 | + | |
50 | + return $quo_days; | |
51 | + } | |
52 | + ], | |
53 | + ]] );?> | |
54 | + | |
55 | + | |
56 | + | |
57 | + | |
58 | +</div> | |
0 | 59 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +use yii\helpers\Html; | |
3 | +use yii\grid\GridView; | |
4 | +use yii\grid\SerialColumn; | |
5 | +use yii\bootstrap\Modal; | |
6 | + | |
7 | + | |
8 | +/* @var $this yii\web\View */ | |
9 | +/* @var $searchModel backend\models\CatalogSearch */ | |
10 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
11 | + | |
12 | +$this->title = 'Проверка прайсов'; | |
13 | +$this->params['breadcrumbs'][] = $this->title; | |
14 | + | |
15 | +?> | |
16 | +<div class="catalog-index"> | |
17 | + | |
18 | + <h1><?= Html::encode($this->title) ?></h1> | |
19 | + | |
20 | + <?= GridView::widget( ['dataProvider' => $dataProvider, | |
21 | + | |
22 | + ] ); | |
23 | + | |
24 | + | |
25 | + ?> | |
26 | + | |
27 | + | |
28 | + | |
29 | +</div> | |
30 | +<?php | |
31 | + | |
32 | +?> | |
0 | 33 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +use yii\helpers\Html; | |
3 | +use yii\grid\GridView; | |
4 | +use yii\grid\SerialColumn; | |
5 | +use yii\grid\ActionColumn; | |
6 | +use yii\widgets\Pjax; | |
7 | + | |
8 | + | |
9 | +/* @var $this yii\web\View */ | |
10 | +/* @var $searchModel backend\models\CatalogSearch */ | |
11 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
12 | + | |
13 | +$this->title = 'Проверка прайсов'; | |
14 | +$this->params['breadcrumbs'][] = $this->title; | |
15 | +?> | |
16 | +<div class="catalog-index"> | |
17 | + | |
18 | + <h1><?= Html::encode($this->title) ?></h1> | |
19 | + | |
20 | + | |
21 | + <?= GridView::widget( ['dataProvider' => $dataProvider, | |
22 | + 'columns' => [['class' => SerialColumn::className()], | |
23 | + [ | |
24 | + 'class' => ActionColumn::className(), | |
25 | + 'template'=>'{view}', | |
26 | + 'contentOptions' => function ($model, $key, $index, $column){ | |
27 | + return ['data' => ['id' => $model->id, 'date' => $model->price_date_update]]; | |
28 | + } | |
29 | + ], | |
30 | + [ | |
31 | + 'label' =>'Поставщик', | |
32 | + 'value' => function ($data) { | |
33 | + return '№ ' .$data->id . ' ' . $data->name; | |
34 | + }, | |
35 | + ], | |
36 | + ['label' =>'Дата обновления', | |
37 | + 'attribute' => 'price_date_update' ], | |
38 | + ['label' => 'Кол-во дней', | |
39 | + 'value' => function ($data) { | |
40 | + $date1 = new DateTime("now"); | |
41 | + $date2 = new DateTime( $data->price_date_update ); | |
42 | + $quo_days = $date2->diff($date1)->format('%R%a'); | |
43 | + // уберем первый символ - там знак "+" | |
44 | + $quo_days = substr( $quo_days, 1, strlen($quo_days) ); | |
45 | + $quo_days = (int) $quo_days; | |
46 | + | |
47 | + if($quo_days > 15) | |
48 | + $quo_days = '>15'; | |
49 | + | |
50 | + return $quo_days; | |
51 | + } | |
52 | + ], | |
53 | + ]] );?> | |
54 | + | |
55 | + | |
56 | + | |
57 | + | |
58 | +</div> | |
0 | 59 | \ No newline at end of file | ... | ... |
1 | +<?php | |
2 | +use yii\helpers\Html; | |
3 | +use yii\grid\GridView; | |
4 | +use yii\grid\SerialColumn; | |
5 | +use yii\bootstrap\Modal; | |
6 | + | |
7 | + | |
8 | +/* @var $this yii\web\View */ | |
9 | +/* @var $searchModel backend\models\CatalogSearch */ | |
10 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
11 | + | |
12 | +$this->title = 'Проверка прайсов'; | |
13 | +$this->params['breadcrumbs'][] = $this->title; | |
14 | + | |
15 | +?> | |
16 | +<div class="catalog-index"> | |
17 | + | |
18 | + <h1><?= Html::encode($this->title) ?></h1> | |
19 | + | |
20 | + <?= GridView::widget( ['dataProvider' => $dataProvider, | |
21 | + | |
22 | + ] ); | |
23 | + | |
24 | + | |
25 | + ?> | |
26 | + | |
27 | + | |
28 | + | |
29 | +</div> | |
30 | +<?php | |
31 | + | |
32 | +?> | |
0 | 33 | \ No newline at end of file | ... | ... |
backend/views/layouts/column.php
... | ... | @@ -282,7 +282,13 @@ $this->beginContent('@app/views/layouts/main.php'); |
282 | 282 | echo Menu::widget([ |
283 | 283 | 'options' => ['class' => 'sidebar-menu'], |
284 | 284 | 'items' => [ |
285 | - ['label' => "Прайс парсер", 'url' => ['parser/index']], | |
285 | + ['label' => "Загрузка файлов", 'url' => ['#'], 'items' => [ | |
286 | + ['label' => 'Файлы на сервере', 'url' => ['parser/server-files']], | |
287 | + ['label' => 'Загрузить файл на сервер', 'url' => ['parser/index', 'mode' => 1]], | |
288 | + ['label' => 'Ручная загрузка', 'url' => ['parser/index']], | |
289 | + ['label' => 'Проверка прайс файлов', 'url' => ['check-price/index']], | |
290 | + ], | |
291 | + ], | |
286 | 292 | ['label' => 'Управление ролями', 'url' => ['#'], 'items' => [ |
287 | 293 | ['label' => 'Покупатели', 'url' => '#'], |
288 | 294 | ['label' => 'Поставщики', 'url' => '#'], | ... | ... |
backend/views/parser/index.php
... | ... | @@ -3,29 +3,50 @@ use yii\widgets\ActiveForm; |
3 | 3 | use yii\helpers\Html; |
4 | 4 | use backend\models\Importer; |
5 | 5 | use yii\helpers\ArrayHelper; |
6 | +if ( $model->mode ) { | |
7 | + // авто загрузка | |
8 | + $mode = 1; | |
9 | + $button_label = 'Загрузить'; | |
10 | +} else { | |
11 | + // ручная загрузка | |
12 | + $mode = 0; | |
13 | + $button_label = 'Прочитать'; | |
14 | +} | |
6 | 15 | |
7 | 16 | ?> |
8 | 17 | <div class="row"> |
9 | 18 | <div class="col-lg-5"> |
10 | - <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['parser/results']]); | |
19 | + <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['parser/results', 'mode' => $mode]]); | |
11 | 20 | if (!$model->action) { |
12 | 21 | $model->action = 1; |
13 | 22 | } |
23 | + if ($model->success) { // вернулись после успешной загрузки данного файла | |
24 | + echo Html::tag('h3', 'Файл успешно загружен',['class'=>'bg-success']); | |
25 | + } | |
14 | 26 | ?> |
15 | 27 | <h3>Загрузка прайсов поставщиков</h3> |
16 | 28 | |
17 | 29 | |
18 | - <?= $form->field($model, 'importer')->dropDownList(ArrayHelper::map( Importer::find()->all(), 'id','name' )); ?> | |
19 | - <?= $form->field($model, 'delete_price')->checkbox(['label' => 'Загрузить с удалением старого прайса']) ?> | |
30 | + <?= $form->field($model, 'importer_id')->dropDownList(ArrayHelper::map( Importer::find()->all(), 'id','name' )); ?> | |
31 | + | |
32 | + <?php if ( !$mode ) { | |
33 | + echo $form->field($model, 'delete_price')->checkbox(['label' => 'Загрузить с удалением старого прайса']); | |
34 | + } | |
35 | + ?> | |
36 | + | |
20 | 37 | <?= $form->field($model, 'file')->fileInput()->label(false) ?> |
21 | - <?= $form->field($model, 'action')->radioList([1 => 'Стандартная обработка', 0 => 'С разделителем'])->label(false) ?> | |
22 | - <?= $form->field($model, 'delimiter', ['inputOptions' => ['value' => ';']]) ?> | |
23 | 38 | |
24 | - <?= $form->field($model, 'delete_prefix')->checkbox(['label' => 'Удалять префикс']) ?> | |
39 | + <?php if ( !$mode ) { | |
40 | + echo $form->field($model, 'action')->radioList([1 => 'Стандартная обработка', 0 => 'С разделителем'])->label(false); | |
41 | + echo $form->field($model, 'delimiter', ['inputOptions' => ['value' => ';']]); | |
42 | + | |
43 | + echo $form->field($model, 'delete_prefix')->checkbox(['label' => 'Удалять префикс']); | |
44 | + } | |
45 | + ?> | |
25 | 46 | |
26 | 47 | |
27 | 48 | <div class="form-group"> |
28 | - <?= Html::submitButton(Yii::t('app', 'Прочитать'), ['class' => 'btn btn-primary']) ?> | |
49 | + <?= Html::submitButton(Yii::t( 'app', $button_label ), ['class' => 'btn btn-primary']) ?> | |
29 | 50 | </div> |
30 | 51 | |
31 | 52 | <?php ActiveForm::end() ?> | ... | ... |
1 | +<?php | |
2 | +use yii\helpers\Html; | |
3 | +use yii\grid\GridView; | |
4 | +use yii\grid\SerialColumn; | |
5 | +use yii\grid\ActionColumn; | |
6 | +use yii\widgets\Pjax; | |
7 | + | |
8 | + | |
9 | +/* @var $this yii\web\View */ | |
10 | +/* @var $searchModel backend\models\CatalogSearch */ | |
11 | +/* @var $dataProvider yii\data\ActiveDataProvider */ | |
12 | + | |
13 | +$this->title = 'Проверка прайсов'; | |
14 | +$this->params['breadcrumbs'][] = $this->title; | |
15 | +Pjax::begin(); | |
16 | + | |
17 | +?> | |
18 | + <div class="catalog-index"> | |
19 | + | |
20 | + <h1><?= Html::encode($this->title) ?></h1> | |
21 | + | |
22 | + <?= GridView::widget( ['dataProvider' => $dataProvider, | |
23 | + 'columns' => [['class' => SerialColumn::className()], | |
24 | + [ | |
25 | + 'label' =>'Поставщик', | |
26 | + 'value' => function ($data) { | |
27 | + return $data->importer; | |
28 | + }, | |
29 | + ], | |
30 | + ['label' =>'Дата загрузки', | |
31 | + 'attribute' => 'upload_time' ], | |
32 | + | |
33 | + ['class' => ActionColumn::className(), | |
34 | + 'template'=>'{delete}', | |
35 | + 'buttons' => [ | |
36 | + 'delete' => function ($url, $model, $key) { | |
37 | + return Html::a('<span class="glyphicon glyphicon-remove"></span>', $url, [ | |
38 | + 'title' => Yii::t('yii', 'Удалить файл'), | |
39 | + 'data-confirm' => 'Вы уверены что хотите удалить этот файл?', | |
40 | + 'data-method' => 'post', | |
41 | + 'data-pjax' => '1', | |
42 | + ]); | |
43 | + }, | |
44 | + ], | |
45 | + ] | |
46 | + | |
47 | + ]] );?> | |
48 | + | |
49 | + | |
50 | + | |
51 | + </div> | |
52 | +<?php | |
53 | +Pjax::end(); | |
54 | +?> | |
0 | 55 | \ No newline at end of file | ... | ... |
common/config/bootstrap.php
... | ... | @@ -3,3 +3,5 @@ Yii::setAlias('common', dirname(__DIR__)); |
3 | 3 | Yii::setAlias('frontend', dirname(dirname(__DIR__)) . '/frontend'); |
4 | 4 | Yii::setAlias('backend', dirname(dirname(__DIR__)) . '/backend'); |
5 | 5 | Yii::setAlias('console', dirname(dirname(__DIR__)) . '/console'); |
6 | +Yii::setAlias('auto_upload', dirname(dirname(__DIR__)) . '/backend/uploads/auto'); | |
7 | +Yii::setAlias('manual_upload', dirname(dirname(__DIR__)) . '/backend/uploads/manual'); | ... | ... |
1 | +<?php | |
2 | + | |
3 | +use yii\db\Schema; | |
4 | +use yii\db\Migration; | |
5 | + | |
6 | +class m150915_125129_addDetails extends Migration | |
7 | +{ | |
8 | + public function up() | |
9 | + { | |
10 | + $this->execute('CREATE TABLE `details` ( | |
11 | + `ID` int(10) unsigned NOT NULL AUTO_INCREMENT, | |
12 | + `IMPORT_ID` int(6) unsigned NOT NULL, | |
13 | + `BRAND` varchar(100) NOT NULL, | |
14 | + `ARTICLE` varchar(100) NOT NULL, | |
15 | + `FULL_ARTICLE` varchar(150) NOT NULL, | |
16 | + `PRICE` float(15,2) unsigned NOT NULL, | |
17 | + `DESCR` varchar(200) NOT NULL, | |
18 | + `BOX` int(6) unsigned NOT NULL, | |
19 | + `ADD_BOX` int(6) unsigned NOT NULL DEFAULT 0, | |
20 | + `GROUP` varchar(200) NOT NULL DEFAULT \'\', | |
21 | + `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
22 | + PRIMARY KEY (`ARTICLE`,`BRAND`,`IMPORT_ID`), | |
23 | + UNIQUE KEY `ID_delete` (`ID`), | |
24 | + KEY `timestamp` (`timestamp`), | |
25 | + KEY `ARTICLE` (`ARTICLE`,`BRAND`,`BOX`), | |
26 | + KEY `BRAND` (`BRAND`,`ARTICLE`), | |
27 | + KEY `ARTICLE_2` (`ARTICLE`,`BRAND`,`ADD_BOX`), | |
28 | + KEY `IMPORT_ID` (`IMPORT_ID`,`ARTICLE`), | |
29 | + KEY `IMPORT_ID_2` (`IMPORT_ID`,`timestamp`) | |
30 | + ) ENGINE=InnoDB DEFAULT CHARSET=utf8'); | |
31 | + | |
32 | + } | |
33 | + | |
34 | + public function down() | |
35 | + { | |
36 | + $this->dropTable('{{%details}}'); | |
37 | + | |
38 | + } | |
39 | + | |
40 | +} | ... | ... |
console/migrations/m150922_094313_change_key_ImportFiles.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +use yii\db\Schema; | |
4 | +use yii\db\Migration; | |
5 | + | |
6 | +class m150922_094313_change_key_ImportFiles extends Migration | |
7 | +{ | |
8 | + //@todo вероятно что эта миграция ненужна - посмотреть ближе к концу проекта на ключи которые используются - остальные удалить. | |
9 | + public function up() | |
10 | + { | |
11 | + $this->dropIndex('importer_id', '{{%importer_files}}'); | |
12 | + $this->createIndex('importer_id', '{{%importer_files}}', 'importer_id, upload_time', false); | |
13 | + } | |
14 | + | |
15 | + public function down() | |
16 | + { | |
17 | + $this->dropIndex('importer_id', '{{%importer_files}}'); | |
18 | + $this->createIndex('importer_id', '{{%importer_files}}', 'importer_id, time_start', false); | |
19 | + } | |
20 | + | |
21 | + | |
22 | +} | ... | ... |
console/migrations/m150922_144040_change_Importer_dataPrice.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +use yii\db\Schema; | |
4 | +use yii\db\Migration; | |
5 | + | |
6 | +class m150922_144040_change_Importer_dataPrice extends Migration | |
7 | +{ | |
8 | + public function up() | |
9 | + { | |
10 | + $this->alterColumn('{{%importer}}','price_date_update','TIMESTAMP' ); | |
11 | + $this->createIndex('price_date', '{{%importer}}', 'price_date_update', false); | |
12 | + } | |
13 | + | |
14 | + public function down() | |
15 | + { | |
16 | + $this->alterColumn('{{%importer}}','price_date','varchar(15)' ); | |
17 | + $this->dropIndex('price_date', '{{%importer}}'); | |
18 | + } | |
19 | + | |
20 | + | |
21 | +} | ... | ... |
console/migrations/m150925_111922_add_foreign_key_ImportFiles.php
0 → 100644
1 | +<?php | |
2 | + | |
3 | +use yii\db\Schema; | |
4 | +use yii\db\Migration; | |
5 | + | |
6 | +class m150925_111922_add_foreign_key_ImportFiles extends Migration | |
7 | +{ | |
8 | + public function up() | |
9 | + { | |
10 | + $this->addForeignKey('importer_fk', '{{%importer_files}}', 'importer_id', '{{%importer}}', 'id'); | |
11 | + } | |
12 | + | |
13 | + public function down() | |
14 | + { | |
15 | + $this->dropForeignKey('importer_fk', '{{%importer_files}}'); | |
16 | + } | |
17 | + | |
18 | +} | ... | ... |