Commit 8cb5acbf30799eac04cf8dff13eb5e92e30ac181

Authored by Mihail
1 parent 8663be10

add exaples template for csv files

examples/ParserController.php 0 → 100644
  1 +<?php
  2 +namespace backend\controllers;
  3 +
  4 +use backend\models\UploadFileParsingForm;
  5 +use Yii;
  6 +use yii\base\ErrorException;
  7 +use yii\data\ArrayDataProvider;
  8 +use yii\helpers\VarDumper;
  9 +use yii\multiparser\DynamicFormHelper;
  10 +use yii\web\Controller;
  11 +use yii\web\UploadedFile;
  12 +
  13 +
  14 +/**
  15 + * Site controller
  16 + */
  17 +class ParserController extends Controller
  18 +{
  19 + /**
  20 + * @var - string
  21 + * file parsing extension
  22 + */
  23 + protected $file_extension;
  24 +
  25 + public function actionIndex($mode = 0)
  26 + {
  27 + $model = new UploadFileParsingForm();
  28 + return $this->render('index', ['model' => $model]);
  29 + }
  30 +
  31 + public function actionRead()
  32 + {
  33 + $model = new UploadFileParsingForm();
  34 + $data = [];
  35 + $mode = '';
  36 + if ($model->load(\Yii::$app->request->post())) {
  37 + if (!$model->file_type) {
  38 + $model->file = UploadedFile::getInstance($model, 'file');
  39 + }
  40 + if ($model->validate()) {
  41 + // get the extension of user chosen file
  42 + $this->file_extension = $this->getFileExtensionFromModel($model);
  43 +
  44 + if ($model->file_type) {
  45 + $model->file_path = dirname(dirname(__DIR__)) . '/tests/_data/template.' . $this->file_extension;
  46 + $mode = 'template';
  47 + } else {
  48 + $mode = 'custom';
  49 + $model->file_path = dirname(dirname(__DIR__)) . '/tests/_data/custom_template.' . $this->file_extension;
  50 + $model->file->saveAs($model->file_path);
  51 + }
  52 +
  53 + // run parsing
  54 + $data = $model->readFile(['mode' => $mode]);
  55 +
  56 + if ($mode == 'custom' && file_exists($model->file_path)) {
  57 + unlink($model->file_path);
  58 + }
  59 + // safe parse data to cache
  60 + Yii::$app->getCache()->set('parser_data', json_encode($data), 300);
  61 +
  62 + } else {
  63 + // handle with error validation form
  64 + $errors_str = 'Error upload form';
  65 + foreach ($model->getErrors() as $error) {
  66 + $errors_str .= ' ' . implode(array_values($error));
  67 + }
  68 +
  69 + throw new ErrorException($errors_str);
  70 + }
  71 +
  72 + } elseif (Yii::$app->getCache()->get('parser_data')) {
  73 + // it's a get request, so retrive data from cache
  74 + $data = json_decode(Yii::$app->getCache()->get('parser_data'), true);
  75 + }
  76 +
  77 + return $this->renderResultView($data, $mode);
  78 + }
  79 +
  80 + public function getFileExtensionFromModel($model)
  81 + {
  82 + switch ($model->file_type) {
  83 + case 0:
  84 + return $model->file->extension;
  85 + case 1:
  86 + return 'csv';
  87 + case 2:
  88 + return 'xml';
  89 + case 3:
  90 + return 'xlsx';
  91 + default:
  92 + return 'csv';
  93 + }
  94 +
  95 + }
  96 +
  97 + public function renderResultView($data )
  98 + {
  99 + $provider = new ArrayDataProvider([
  100 + 'allModels' => $data,
  101 + 'pagination' => [
  102 + 'pageSize' => 10,
  103 + ],
  104 + ]);
  105 + // если отпарсенные данные - ассоциативный массив, то пользователю нечего выбирать
  106 + $assoc_data_arr = $this->is_assoc($data[0]);
  107 +
  108 + if ( $assoc_data_arr ) {
  109 +
  110 + // $mode == 'template' or xml file
  111 + // парсинг с файла по шаблону
  112 + // согласно конфигурационного файла у нас колонкам назначены ключи
  113 + // то есть результат - ассоциативный массив, у пользователя нечего спрашивать
  114 + // данные отконвертированы согласно настройкам и готовы к записи в БД (или к дальнейшей обработке)
  115 +
  116 + return $this->render('results',
  117 + ['model' => $data,
  118 + // список колонок для выбора
  119 + 'dataProvider' => $provider]);
  120 +
  121 + } else {
  122 + // $mode == 'custom' and not xml
  123 + // для произвольного файла создадим страницу предпросмотра
  124 + // с возможностью выбора соответсвий колонок с отпарсенными данными
  125 + //колонки для выбора возьмем из конфигурационного файла - опция - 'basic_column'
  126 +
  127 + // создадим динамическую модель на столько реквизитов сколько колонок в отпарсенном файле
  128 + // в ней пользователь произведет свой выбор
  129 + $last_index = end(array_flip($data[0]));
  130 + $header_counts = $last_index + 1; // - количество колонок выбора формы предпросмотра
  131 + $header_model = DynamicFormHelper::CreateDynamicModel($header_counts);
  132 +
  133 + // колонки для выбора возьмем из конфигурационного файла
  134 + $basicColumns = Yii::$app->multiparser->getConfiguration($this->file_extension, 'basic_column');;
  135 +
  136 + return $this->render('results',
  137 + ['model' => $data,
  138 + 'header_model' => $header_model,
  139 + // список колонок для выбора
  140 + 'basic_column' => $basicColumns,
  141 + 'dataProvider' => $provider]);
  142 + }
  143 +
  144 + }
  145 +
  146 + private function is_assoc(array $array)
  147 + {
  148 + // Keys of the array
  149 + $keys = array_keys($array);
  150 +
  151 + // If the array keys of the keys match the keys, then the array must
  152 + // not be associative (e.g. the keys array looked like {0:0, 1:1...}).
  153 + return array_keys($keys) !== $keys;
  154 + }
  155 +
  156 +}
... ...
examples/UploadFileParsingForm.php 0 → 100644
  1 +<?php
  2 +namespace backend\models;
  3 +
  4 +use yii\base\ErrorException;
  5 +use yii\base\Model;
  6 +use yii\web\UploadedFile;
  7 +use Yii;
  8 +use common\components\CustomVarDamp;
  9 +
  10 +/**
  11 + * UploadForm is the model behind the upload form.
  12 + */
  13 +class UploadFileParsingForm extends Model
  14 +{
  15 + /**
  16 + * @var UploadedFile file attribute
  17 + */
  18 + // chosen file
  19 + public $file;
  20 + // file path after save
  21 + public $file_path;
  22 + // 0 - custom file (user should choose in $file field)
  23 + // 1 - csv template file from data/template.csv
  24 + // 2 - xml template file from data/template.xml
  25 + // 3 - xlsx template file from data/template.xlsx
  26 + public $file_type = 0;
  27 +
  28 +
  29 + public function rules()
  30 + {
  31 + $client_func = <<< JS
  32 + function(attribute, value) {
  33 + return $('input[name=UploadFileParsingForm[file_type]]').val() == '0';
  34 + }
  35 +JS;
  36 + return [
  37 + ['file_type', 'in', 'range' => range( 0, 3 ) ],
  38 + ['file', 'required', 'when' => function(){
  39 + return !$this->file_type;
  40 + } , 'whenClient' => $client_func],
  41 + [['file'], 'file', 'extensions' => ['csv', 'xlsx', 'xml'], 'checkExtensionByMimeType' => false ],
  42 + ['file_path', 'safe'],
  43 +
  44 + ];
  45 + }
  46 +
  47 + public function attributeLabels()
  48 + {
  49 + return [
  50 + 'file' => Yii::t('app', 'Custom file'),
  51 + ];
  52 + }
  53 +
  54 + public function readFile( $options = [] ){
  55 +
  56 + $data = Yii::$app->multiparser->parse( $this->file_path, $options );
  57 +
  58 + if( !is_array( $data ) || count($data) == 0 ){
  59 + throw new ErrorException("Reading error from file - {$this->file_path}");
  60 + }
  61 +
  62 + if( !$this->file_path && file_exists( $this->file_path ) )
  63 + unlink( $this->file_path );
  64 +
  65 + return $data;
  66 + }
  67 +
  68 +
  69 +
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
examples/config.php 0 → 100644
  1 +<?php
  2 +return [
  3 + 'csv' =>
  4 + ['custom' =>
  5 + ['class' => 'yii\multiparser\CsvParser',
  6 + 'converter_conf' => [
  7 + 'class' => 'yii\multiparser\Converter',
  8 + 'configuration' => ["encode" => []],
  9 + ]
  10 + ],
  11 + 'template' =>
  12 + ['class' => 'yii\multiparser\CsvParser',
  13 + 'keys' => [
  14 + 0 => 'Description',
  15 + 1 => 'Article',
  16 + 2 => 'Price',
  17 + 3 => 'Brand',
  18 + 4 => 'Count',
  19 + ],
  20 + 'converter_conf' => [
  21 + 'class' => 'yii\multiparser\Converter',
  22 + 'configuration' => ["encode" => 'Description',
  23 + "string" => ['Description', 'Brand'],
  24 + "float" => 'Price',
  25 + "integer" => 'Count'
  26 + ]
  27 + ],],
  28 +
  29 + 'basic_column' => [
  30 + Null => 'null',
  31 + "Description" => 'Название',
  32 + "Article" => 'Артикул',
  33 + "Price" => 'Цена',
  34 + "Brand" => 'Производитель',
  35 + "Count" => 'Количество',
  36 + ],
  37 + ],
  38 + 'xml' =>
  39 + ['custom' =>
  40 + ['class' => 'yii\multiparser\XmlParser',
  41 + 'converter_conf' => [
  42 + 'class' => 'yii\multiparser\Converter',
  43 + 'configuration' => ["encode" => []],
  44 + ]
  45 + ],
  46 + 'template' =>
  47 + ['class' => 'yii\multiparser\XmlParser',
  48 + 'node' => 'Товар',
  49 + 'has_header_row' => false,
  50 + 'keys' => [
  51 + "BRAND" => 'Производитель',
  52 + "ARTICLE" => 'Код',
  53 + "PRICE" => 'Розница',
  54 + "DESCR" => 'Наименование',
  55 + "BOX" => 'Колво',
  56 + "ADD_BOX" => 'Ожидаемое',
  57 + "GROUP" => 'Группа'
  58 + ],
  59 + 'converter_conf' => [
  60 + 'class' => 'yii\multiparser\Converter',
  61 + 'configuration' => [
  62 + 'converter_conf' => [
  63 + 'class' => 'yii\multiparser\Converter',
  64 + 'configuration' => ["encode" => 'DESCR',
  65 + "string" => ['DESCR', 'BRAND'],
  66 + "float" => 'PRICE',
  67 + "integer" => ['BOX', 'ADD_BOX'],
  68 + ],
  69 + ],
  70 + ],
  71 + ],
  72 + ],
  73 + 'basic_column' => [
  74 + Null => 'null',
  75 + "BRAND" => 'Производитель',
  76 + "ARTICLE" => 'Код',
  77 + "PRICE" => 'Розница',
  78 + "DESCR" => 'Наименование',
  79 + "BOX" => 'Колво',
  80 + "ADD_BOX" => 'Ожидаемое',
  81 + "GROUP" => 'Группа'
  82 + ],
  83 + ],
  84 + 'xlsx' =>
  85 + ['web' =>
  86 + ['class' => 'common\components\parsers\XlsxParser',
  87 + // 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/',
  88 + //'auto_detect_first_line' => true,
  89 + //'has_header_row' => true,
  90 + 'active_sheet' => 1,
  91 + 'converter_conf' => [
  92 + 'class' => 'common\components\parsers\CustomConverter',
  93 + 'configuration' => ["string" => []],
  94 + ]
  95 + ],
  96 + ]
  97 +];
  98 +
... ...
examples/parser/index.php 0 → 100644
  1 +<?php
  2 +use yii\widgets\ActiveForm;
  3 +use yii\helpers\Html;
  4 +use yii\helpers\ArrayHelper;
  5 +
  6 +?>
  7 +<div class="row">
  8 + <div class="col-lg-5">
  9 + <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data',],'action'=>['parser/read']]);
  10 + ?>
  11 + <h3>Choose file to parse</h3>
  12 +
  13 + <?= $form->field($model, 'file')->fileInput() ?>
  14 +
  15 + <?= $form->field($model, 'file_type')->radioList([0 => 'Custom file', 1 => 'csv template', 2 => 'xml template', 3 => 'xlsx template'])->label(false);
  16 + ?>
  17 +
  18 + <div class="form-group">
  19 + <?= Html::submitButton('Read', ['class' => 'btn btn-primary']) ?>
  20 + </div>
  21 +
  22 + <?php ActiveForm::end();
  23 + ?>
  24 + </div>
  25 +</div>
  26 +
... ...
examples/parser/results.php 0 → 100644
  1 +<?php
  2 +
  3 +use yii\helpers\Html;
  4 +use yii\multiparser\DynamicFormHelper;
  5 +use yii\widgets\ActiveForm;
  6 +
  7 +
  8 +/* @var $this yii\web\View */
  9 +/* @var $searchModel backend\models\CatalogSearch */
  10 +/* @var $dataProvider yii\data\ActiveDataProvider */
  11 +
  12 +$this->title = 'Results';
  13 +$this->params['breadcrumbs'][] = $this->title;
  14 +?>
  15 +<div class="catalog-index">
  16 +
  17 + <h1><?= Html::encode($this->title) ?></h1>
  18 + <?php
  19 +
  20 + $form = ActiveForm::begin(['action' => 'write']);
  21 +
  22 + if (empty( $header_model )) {
  23 + // выведем просто массив без колонок выбора
  24 + echo \yii\grid\GridView::widget([
  25 + 'dataProvider' => $dataProvider,
  26 + // 'layout'=>"{pager}\n{items}",
  27 +
  28 + ]);
  29 +
  30 + } else {
  31 + echo DynamicFormHelper::CreateGridWithDropDownListHeader($dataProvider, $form, $header_model, $basic_column);
  32 + }
  33 + ?>
  34 +
  35 + <?php ActiveForm::end() ?>
  36 + <?= Html::a('Return', ['parser/index'], ['class' => 'btn btn-primary', 'name' => 'Return',]) ?>
  37 +
  38 +</div>
0 39 \ No newline at end of file
... ...