diff --git a/backend/controllers/CrossingUploadController.php b/backend/controllers/CrossingUploadController.php index 107d0ac..ca68b9f 100755 --- a/backend/controllers/CrossingUploadController.php +++ b/backend/controllers/CrossingUploadController.php @@ -73,7 +73,8 @@ class CrossingUploadController extends BaseController $model->file_path = Yii::getAlias('@temp_upload') . '/' . $file_name; $model->file->saveAs($model->file_path); //запускаем парсинг - $data = $model->readFile(); + $options['mode'] = 'crosses'; + $data = $model->readFile($options); // сохраняем в кеш отпарсенные даные $this->parserCacheHandler( 1, $data, $model ); } else { @@ -170,7 +171,6 @@ class CrossingUploadController extends BaseController protected function convertDataByConfiguration($data, $configuration) { - // доп. опции для парсера - удаление префикса в артикулах $options['mode'] = 'crosses'; $fields = []; @@ -196,7 +196,6 @@ class CrossingUploadController extends BaseController } return $data; - } protected function reverseCrosses($data) diff --git a/backend/controllers/ParserController.php b/backend/controllers/ParserController.php index 6d312db..b24a4dc 100755 --- a/backend/controllers/ParserController.php +++ b/backend/controllers/ParserController.php @@ -1,6 +1,7 @@ file_path = Yii::getAlias('@manual_upload') . '/' . $model->file->name; $model->file->saveAs($model->file_path); //запускаем парсинг - $data = $model->readFile(); + $options['mode'] = 'rg'; + $data = $model->readFile($options); // сохраняем в кеш отпарсенные даные $this->parserCacheHandler(1, $data, $model); } else { @@ -120,7 +121,7 @@ class RgGrupController extends BaseController $data = CustomArrayHelper::createAssocArray($data, $arr, 'attr_'); // в первой строке у нас заголовки - уберем - unset($data[0]); + unset($data[0]); //- закоментировать если в конфиге парсера указано о наличии заголовка // подготовим данные для записи в таблицу w_margins_groups $data = $this->convertDataByConfiguration($data, $configuration); diff --git a/common/components/parsers/CsvParser.php b/common/components/parsers/CsvParser.php index 1724fcf..1018068 100644 --- a/common/components/parsers/CsvParser.php +++ b/common/components/parsers/CsvParser.php @@ -40,33 +40,6 @@ class CsvParser extends TableParser $this->row = fgetcsv( $this->file, 0, $this->delimiter ); } - protected function isEmptyRow(){ - - $is_empty = false; - - if ($this->row === false || $this->row === NULL ) { - return true; - } - - $j = 0; - for ($i = 1; $i <= count( $this->row ); $i++) { - - if ( !isset( $this->row[ $i - 1 ] ) ) { - continue; - } - - if ( $this->isEmptyColumn( $this->row[$i - 1] ) ) { - $j++; - } - - if ( $j >= $this->min_column_quantity ) { - $is_empty = true; - break; - } - } - - return $is_empty; - } protected function isEmptyColumn( $val ){ return $val == ''; diff --git a/common/components/parsers/Parser.php b/common/components/parsers/Parser.php index 0c42ca3..87f0703 100644 --- a/common/components/parsers/Parser.php +++ b/common/components/parsers/Parser.php @@ -9,8 +9,6 @@ namespace common\components\parsers; //@todo - заменить read на parse -//@todo - xml - убрать из названий функций xml и array - это и так понятно - use common\components\CustomVarDamp; @@ -32,20 +30,8 @@ abstract class Parser /** @var array - массив с заголовком, * */ public $keys = NULL; - /** @var bool - имеет ли файл заголовок который будет установлен ключами возвращемого массива*/ - public $has_header_row = false; - /* - *если есть ключи, то колонки с пустыми значениями будут пропускаться (из ряда такие значения будут удаляться), - * например если в файле вторая колонка пустая то она будет удалена - * если есть $has_header_row - то первая значимая строка становится ключами, но пустые колонки не удаляются из ряда - * например если в файле вторая колонка пустая то ей будет назначен соответсвующий ключ (второй) из первой строки - * все описаное выше реализуется в дочернем семействе классов TableParser в методе filterRow() - * для xml происходит просто сопоставление переданных ключей с прочитанными - */ - - + public abstract function read(); public function setup() { @@ -54,7 +40,7 @@ abstract class Parser protected function setupConverter() { - if ( $this->has_header_row || $this->keys !== NULL ) { + if ( !empty( $this->keys ) ) { // если у файла есть заголовок, то в результате имеем ассоциативный массив $this->converter_conf['hasKey'] = 1; } @@ -67,12 +53,8 @@ abstract class Parser } } - - } - public abstract function read(); - /** * @param $arr * @return mixed @@ -80,16 +62,12 @@ abstract class Parser */ protected function convert( $arr ) { - if ($this->converter !== NULL) { $arr = $this->converter->convertByConfiguration( $arr, $this->converter_conf ); } - - return $arr; - } public final static function supportedExtension() @@ -99,13 +77,9 @@ abstract class Parser protected function cleanUp( ) { - unset( $this->file ); unset( $this->converter ); unset( $this->converter_conf ); - - } - } \ No newline at end of file diff --git a/common/components/parsers/TableParser.php b/common/components/parsers/TableParser.php index 7e85ad5..d084775 100644 --- a/common/components/parsers/TableParser.php +++ b/common/components/parsers/TableParser.php @@ -13,14 +13,19 @@ use common\components\CustomVarDamp; abstract class TableParser extends Parser { - - /** * @var array - текущий отпарсенный ряд + *если есть ключи, то колонки с пустыми значениями будут пропускаться (из ряда такие значения будут удаляться), + * например если в файле вторая колонка пустая то она будет удалена + * в остальных случаях парсятся все колонки (не проверяется - пустая ли колонка) и попадёт в итоговый массив */ protected $row = []; - /** @var int - первая строка с которой начинать парсить */ + /** @var int - первая строка с которой начинать парсить + * эта строка будет считаться первой значимой строкой + * если установлен аттрибут $has_header_row, + * тогда следующая строка будет считаться заголовком и будет пропущена + */ public $first_line = 0; /** @var int - последняя строка до которой парсить @@ -32,9 +37,11 @@ abstract class TableParser extends Parser /** @var bool - нужно ли искать автоматически первоую значисмую строку (не пустая строка) - * иначе первая строка будет взята из аттрибута $first_line */ - public $auto_detect_first_line = false; + * имеет ли файл заголовок в первой значимой строке + * true - первая значимая строка будет пропущена + */ + public $has_header_row = true; + /** @var int - количество значимых колонок, что бы определить первую значимую строку * используется при автоопределении первой строки*/ @@ -48,8 +55,6 @@ abstract class TableParser extends Parser protected $current_row_number = 0; - protected abstract function isEmptyRow(); - protected abstract function isEmptyColumn($column_value); protected abstract function readRow(); @@ -59,69 +64,71 @@ abstract class TableParser extends Parser public function read() { - if ($this->auto_detect_first_line) { - $this->shiftToFirstValuableLine(); - } + // получим первую значимую строку + $this->shiftToFirstValuableLine(); + + // первый проход, строка прочитана в shiftToFirstValuableLine + $first_circle = true; // будем считать количество пустых строк подряд - при достижении $empty_lines_quantity - считаем что это конец файла и выходим $empty_lines = 0; while ($empty_lines < $this->empty_lines_quantity) { - // прочтем строку из файла - $this->readRow(); - if ($this->isEmptyRow()) { - //счетчик пустых строк - $empty_lines++; - $this->current_row_number++; - continue; + // прочтем строку из файла, если это не первый проход + if (!$first_circle){ + $this->readRow(); } + $first_circle = false; + // уберем пустые колонки из ряда if ($this->keys === NULL) { $this->filterRow(); } + if ($this->isEmptyRow()) { + //счетчик пустых строк + $empty_lines++; + $this->current_row_number++; + continue; + } + // запустим конвертирование $this->adjustRowToSettings(); + // установим отпарсенную строку в итоговый массив результата + $this->setResult(); // строка не пустая, имеем прочитанный массив значений $this->current_row_number++; - // для первой строки утановим ключи из заголовка - if (!$this->setKeysFromHeader()) { - $this->setResult(); - } - - // если у нас установлен лимит, при его достижении прекращаем парсинг if ($this->isLastLine()) break; // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД $empty_lines = 0; - } } /** * определяет первую значимую строку, * считывается файл пока в нем не встретится строка с непустыми колонками - * в количестве указанном в атрибуте min_column_quantity - * в результате выполнения $current_row_number будет находится на последней незначимой строке + * или пока не дойдет до first_line + * пропускает заголовок если он указан */ protected function shiftToFirstValuableLine() { + // читаем пока не встретим значимую строку, или пока не дойдем до first_line do { - $this->current_row_number++; $this->readRow(); + } while ( $this->isEmptyRow() && ( $this->first_line < $this->current_row_number ) ); - } while ($this->isEmptyRow()); - - // @todo - сделать опционально - // код для того что бы парсить первую строку, закомментировано как предполагается что первая значимая строка это заголовок - // $this->current_row_number --; -// $this->file->seek( $this->current_row_number ); + // если указан заголовок, то его мы тоже пропускаем (читаем далее) + if( $this->has_header_row ) { + $this->current_row_number++; + $this->readRow(); + } } /** @@ -129,7 +136,6 @@ abstract class TableParser extends Parser */ protected function adjustRowToSettings() { - // если есть заголовок, то перед конвертацией его нужно назначить if ($this->keys !== NULL) { // adjust row to keys @@ -150,22 +156,43 @@ abstract class TableParser extends Parser } - protected function setKeysFromHeader() - { - if ($this->has_header_row) { - // в файле есть заголовок, но он еще не назначен - назначим - if ($this->keys === NULL) { - $this->keys = array_values($this->row); - return true; + protected function isEmptyRow(){ + + $is_empty = false; + + if ( empty( $this->row ) ) { + return true; + } + if ( count( $this->row ) < $this->min_column_quantity ) { + return true; + } + + $j = 0; + for ($i = 1; $i <= count( $this->row ); $i++) { + + if ( !isset( $this->row[ $i - 1 ] ) ) { + continue; + } + + if ( $this->isEmptyColumn( $this->row[$i - 1] ) ) { + $j++; + } + + if ( $j >= $this->min_column_quantity ) { + $is_empty = true; + break; } } - return false; + + return $is_empty; } + + protected function filterRow() { - // если есть заголовок - все значения нужны, не фильтруем - if ($this->has_header_row || !is_array($this->row)) { + // нет строки - нет фильтрации + if ( empty( $this->row ) ) { return; } $this->row = array_filter($this->row, function ($val) { diff --git a/common/components/parsers/XlsParser.php b/common/components/parsers/XlsParser.php index b30085e..77b18a7 100644 --- a/common/components/parsers/XlsParser.php +++ b/common/components/parsers/XlsParser.php @@ -66,36 +66,6 @@ class XlsParser extends TableParser } } - protected function isEmptyRow(){ - - $is_empty = false; - - if ( !$this->row ) { - return true; - } - if ( count( $this->row ) < $this->min_column_quantity ) { - return true; - } - - $j = 0; - for ($i = 1; $i <= count( $this->row ); $i++) { - - if ( !isset( $this->row[ $i - 1 ] ) ) { - continue; - } - - if ( $this->isEmptyColumn( $this->row[$i - 1] ) ) { - $j++; - } - - if ( $j >= $this->min_column_quantity ) { - $is_empty = true; - break; - } - } - - return $is_empty; - } protected function isEmptyColumn( $val ){ return $val == ''; diff --git a/common/components/parsers/XlsxParser.php b/common/components/parsers/XlsxParser.php index f54ceee..a194b62 100644 --- a/common/components/parsers/XlsxParser.php +++ b/common/components/parsers/XlsxParser.php @@ -175,58 +175,17 @@ class XlsxParser extends TableParser $value = (string)round( $value, $this->float_precision ); } - } else { $value = ''; } - // set $this->row[$i] = $value; - } -// // fill the row by empty values for keys that we are missed in previous step - // only for 'has_header_row = true' mode - if ( $this->has_header_row && $this->keys !== Null ) { - $extra_column = count( $this->keys ) - count( $this->row ); - if ( $extra_column ) { - foreach ( $this->keys as $key => $key ) { - - if ( isset( $this->row[$key] ) ) { - continue; - } - $this->row[$key] = ''; - } - } - } ksort( $this->row ); $this->current_node->next(); } - protected function isEmptyRow() - { - - $is_empty = false; - - if (!count($this->row)) { - return true; - } - - $j = 0; - for ($i = 1; $i <= count($this->row); $i++) { - - if (isset($this->row[$i - 1]) && $this->isEmptyColumn($this->row[$i - 1])) { - $j++; - } - - if ($j >= $this->min_column_quantity) { - $is_empty = true; - break; - } - } - - return $is_empty; - } protected function isEmptyColumn($val) { @@ -261,7 +220,6 @@ class XlsxParser extends TableParser } } - /** * @param $cell_address - string with address like A1, B1 ... * @return int - integer index @@ -281,17 +239,7 @@ class XlsxParser extends TableParser return $index; } -// @todo - переписать родительский метод в универсальной манере а не переопределять его - protected function setKeysFromHeader(){ - if ( $this->has_header_row ) { - if ($this->keys === NULL) { - $this->keys = $this->row; - return true; - } - } - return false; - } protected function cleanUp() { parent::cleanUp(); diff --git a/common/components/parsers/XmlParser.php b/common/components/parsers/XmlParser.php index 27d01ce..c5d45ba 100644 --- a/common/components/parsers/XmlParser.php +++ b/common/components/parsers/XmlParser.php @@ -15,15 +15,13 @@ class XmlParser extends Parser{ public function read() { - //$file = $this->file; - $result = $this->xmlToArray( ); + $result = $this->parseToArray( ); if ( isset($this->node) ) { $result = $result[ $this->node ]; } - $this->cleanUp(); return $result; } @@ -36,17 +34,15 @@ class XmlParser extends Parser{ * @throws Exception * @throws \Exception */ - protected function xmlToArray( ) { - + protected function parseToArray( ) { try { $xml = new \SimpleXMLElement( $this->file_path, 0, true ); //\common\components\CustomVarDamp::dumpAndDie($xml->children()->children()); - $result = $this->recursiveXMLToArray( $xml ); + $result = $this->recursiveParseToArray( $xml ); } catch(\Exception $ex) { throw $ex; } - return $result; } @@ -58,7 +54,7 @@ class XmlParser extends Parser{ * * @return mixed */ - protected function recursiveXMLToArray($xml) { + protected function recursiveParseToArray($xml) { if( $xml instanceof \SimpleXMLElement ) { $attributes = $xml->attributes(); @@ -77,7 +73,7 @@ class XmlParser extends Parser{ return (string) $previous_xml; // for CDATA foreach($xml as $key => $value) { - $row[$key] = $this->recursiveXMLToArray($value); + $row[$key] = $this->recursiveParseToArray($value); } if ( is_string($value) ) { // дошли до конца рекурсии @@ -90,7 +86,6 @@ class XmlParser extends Parser{ } - if( isset( $attribute_array ) ) $row['@'] = $attribute_array; // Attributes diff --git a/common/components/parsers/config.php b/common/components/parsers/config.php index 4f76711..70a712e 100755 --- a/common/components/parsers/config.php +++ b/common/components/parsers/config.php @@ -3,7 +3,6 @@ return [ 'csv' => ['web' => ['class' => 'common\components\parsers\CustomCsvParser', - 'auto_detect_first_line' => true, 'converter_conf' => [ 'class' => 'common\components\parsers\CustomConverter', 'configuration' => ["encode" => 'DESCR'], @@ -11,7 +10,6 @@ return [ ], 'console' => ['class' => 'common\components\parsers\CustomCsvParser', - 'auto_detect_first_line' => true, 'converter_conf' => [ 'class' => ' common\components\parsers\CustomConverter', 'configuration' => ["encode" => 'DESCR', @@ -22,7 +20,6 @@ return [ "multiply" => [], "article" => [], "details" => [] - ] ],], @@ -36,9 +33,7 @@ return [ "ADD_BOX" => 'В пути', "GROUP" => 'Группа RG' ], - 'crosses' => ['class' => 'common\components\parsers\CustomCsvParser', - 'auto_detect_first_line' => true, 'min_column_quantity' => 4, 'converter_conf' => [ 'class' => ' common\components\parsers\CustomConverter', @@ -60,7 +55,6 @@ return [ ['console' => ['class' => 'common\components\parsers\XmlParser', 'node' => 'Товар', - 'has_header_row' => true, 'keys' => [ "BRAND" => 'Производитель', "ARTICLE" => 'Код', @@ -80,20 +74,29 @@ return [ ['web' => ['class' => 'common\components\parsers\XlsxParser', 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/', - //'auto_detect_first_line' => true, - //'has_header_row' => true, + 'min_column_quantity' => 5, 'active_sheet' => 1, 'converter_conf' => [ 'class' => 'common\components\parsers\CustomConverter', 'configuration' => ["string" => []], ] ], + 'rg' => + ['class' => 'common\components\parsers\XlsxParser', + 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/', + 'min_column_quantity' => 4, + 'has_header_row' => false, // заголовок есть, но мы его выводим пользователю для наглядности (так у них на сайте было) и принудительно удаляем первую строку при записи + 'active_sheet' => 1, + 'converter_conf' => [ + 'class' => 'common\components\parsers\CustomConverter', + 'configuration' => ["string" => []], + ] + ], 'console' => ['class' => 'common\components\parsers\XlsxParser', 'path_for_extract_files' => \Yii::getAlias('@temp_upload') . '/xlsx/', - 'auto_detect_first_line' => true, 'active_sheet' => 1, - 'min_column_quantity' => 3, + 'min_column_quantity' => 5, 'converter_conf' => [ 'class' => ' common\components\parsers\CustomConverter', 'configuration' => ["encode" => 'DESCR', @@ -108,9 +111,8 @@ return [ ],], ], 'txt' => - [ 'web' => + ['web' => ['class' => 'common\components\parsers\CustomCsvParser', - 'auto_detect_first_line' => true, 'delimiter' => "\t", 'converter_conf' => [ 'class' => 'common\components\parsers\CustomConverter', @@ -118,22 +120,21 @@ return [ ] ], 'console' => - ['class' => 'common\components\parsers\CustomCsvParser', - 'auto_detect_first_line' => true, - 'delimiter' => "\t", - 'converter_conf' => [ - 'class' => ' common\components\parsers\CustomConverter', - 'configuration' => ["encode" => 'DESCR', - "string" => 'DESCR', - "float" => 'PRICE', - "brand" => 'BRAND', - "integer" => ['BOX', 'ADD_BOX'], - "multiply" => [], - "article" => [], - "details" => [] - ] + ['class' => 'common\components\parsers\CustomCsvParser', + 'delimiter' => "\t", + 'converter_conf' => [ + 'class' => ' common\components\parsers\CustomConverter', + 'configuration' => ["encode" => 'DESCR', + "string" => 'DESCR', + "float" => 'PRICE', + "brand" => 'BRAND', + "integer" => ['BOX', 'ADD_BOX'], + "multiply" => [], + "article" => [], + "details" => [] + ] + ], ], - ], 'basic_column' => [ Null => 'Пусто', "BRAND" => 'Бренд', @@ -148,7 +149,6 @@ return [ 'xls' => ['web' => ['class' => 'common\components\parsers\XlsParser', - 'auto_detect_first_line' => true, 'converter_conf' => [ 'class' => 'common\components\parsers\CustomConverter', 'configuration' => ["encode" => 'DESCR'], @@ -156,7 +156,6 @@ return [ ], 'console' => ['class' => 'common\components\parsers\XlsParser', - 'auto_detect_first_line' => true, 'converter_conf' => [ 'class' => ' common\components\parsers\CustomConverter', 'configuration' => ["encode" => 'DESCR', diff --git a/frontend/tmp/sess_ie9ugm14hq2ps14le8ffl5oa25 b/frontend/tmp/sess_ie9ugm14hq2ps14le8ffl5oa25 new file mode 100644 index 0000000..6292d6a --- /dev/null +++ b/frontend/tmp/sess_ie9ugm14hq2ps14le8ffl5oa25 @@ -0,0 +1 @@ +__flash|a:0:{}__captcha/site/captcha|s:7:"pasogib";__captcha/site/captchacount|i:1; \ No newline at end of file diff --git a/frontend/tmp/sess_v3s0rp29dndkjd2sm7fki4l8p0 b/frontend/tmp/sess_v3s0rp29dndkjd2sm7fki4l8p0 new file mode 100644 index 0000000..d37437e --- /dev/null +++ b/frontend/tmp/sess_v3s0rp29dndkjd2sm7fki4l8p0 @@ -0,0 +1 @@ +__flash|a:0:{}__captcha/site/captcha|s:7:"jibahiv";__captcha/site/captchacount|i:1; \ No newline at end of file -- libgit2 0.21.4