diff --git a/lib/CsvParser.php b/lib/CsvParser.php index ee7356e..d959f86 100644 --- a/lib/CsvParser.php +++ b/lib/CsvParser.php @@ -17,7 +17,7 @@ class CsvParser extends TableParser /** - * метод устанвливает нужные настройки объекта SplFileObject, для работы с csv + * метод устанавливает настройки конвертера */ public function setup() { @@ -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/lib/Parser.php b/lib/Parser.php index 5cd4d04..27e35c1 100644 --- a/lib/Parser.php +++ b/lib/Parser.php @@ -9,8 +9,6 @@ namespace yii\multiparser; //@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,32 +62,24 @@ 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() { - return ['csv','xml','xlsx','txt']; + return ['csv','xml','xlsx','txt','xls']; } protected function cleanUp( ) { - unset( $this->file ); unset( $this->converter ); unset( $this->converter_conf ); - - } - } \ No newline at end of file diff --git a/lib/TableParser.php b/lib/TableParser.php index 9ae45e6..54d957e 100644 --- a/lib/TableParser.php +++ b/lib/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/lib/XlsParser.php b/lib/XlsParser.php index b30085e..fdb01f9 100644 --- a/lib/XlsParser.php +++ b/lib/XlsParser.php @@ -2,7 +2,7 @@ /** */ -namespace common\components\parsers; +namespace yii\multiparser; /** * Class XlsParser @@ -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/lib/XlsxParser.php b/lib/XlsxParser.php index bd0afd0..820779c 100644 --- a/lib/XlsxParser.php +++ b/lib/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/lib/XmlParser.php b/lib/XmlParser.php index a4a665b..80ddca3 100644 --- a/lib/XmlParser.php +++ b/lib/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 -- libgit2 0.21.4