Blame view

common/components/parsers/TableParser.php 8.42 KB
ad2e91f7   Mihail   move multyparser ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  <?php
  /**
   * Created by PhpStorm.
   * User: Tsurkanov
   * Date: 22.10.2015
   * Time: 15:53
   */
  
  namespace common\components\parsers;
  
  
  use common\components\CustomVarDamp;
  
  abstract class TableParser extends Parser
  {
ad2e91f7   Mihail   move multyparser ...
16
17
      /**
       * @var array - текущий отпарсенный ряд
2d4b1514   Mihail   adapted xls parser
18
19
20
       *если есть ключи, то колонки с пустыми значениями будут пропускаться (из ряда такие значения будут удаляться),
       * например если в файле вторая колонка пустая то она будет удалена
       * в остальных случаях парсятся все колонки (не проверяется - пустая ли колонка) и попадёт в итоговый массив
ad2e91f7   Mihail   move multyparser ...
21
22
23
       */
      protected $row = [];
  
2d4b1514   Mihail   adapted xls parser
24
25
26
27
28
      /** @var int - первая строка с которой начинать парсить
       * эта строка будет считаться первой значимой строкой
       * если установлен аттрибут $has_header_row,
       * тогда следующая строка будет считаться заголовком и будет пропущена
       */
ad2e91f7   Mihail   move multyparser ...
29
30
31
32
33
34
35
36
37
38
39
      public $first_line = 0;
  
      /** @var int - последняя строка до которой  парсить
       * если не указана, то парсинг происходит до конца файла*/
      public $last_line = 0;
  
      /** @var int - первая колонка файла с которой начнется парсинг */
      public $first_column = 0;
  
  
      /** @var bool
2d4b1514   Mihail   adapted xls parser
40
41
42
43
44
       * имеет ли файл заголовок в первой значимой строке
       * true - первая значимая строка будет пропущена
       */
      public $has_header_row = true;
  
ad2e91f7   Mihail   move multyparser ...
45
46
47
48
49
50
51
52
53
54
55
56
57
  
      /** @var int - количество значимых колонок, что бы определить первую значимую строку
       * используется при автоопределении первой строки*/
      public $min_column_quantity = 5;
      /** @var int - количество пустых строк, что бы определить конец файла,
       * такое количеество подряд пустых строк считается концом файла*/
      public $empty_lines_quantity = 3;
  
  
      /** @var int - номер текущей строки парсера */
      protected $current_row_number = 0;
  
  
ad2e91f7   Mihail   move multyparser ...
58
59
60
61
62
63
64
65
66
      protected abstract function isEmptyColumn($column_value);
  
      protected abstract function readRow();
  
      protected abstract function setResult();
  
  
      public function read()
      {
2d4b1514   Mihail   adapted xls parser
67
68
69
70
71
          // получим первую значимую строку
          $this->shiftToFirstValuableLine();
  
          // первый проход, строка прочитана в shiftToFirstValuableLine
          $first_circle = true;
ad2e91f7   Mihail   move multyparser ...
72
73
74
75
  
          // будем считать количество пустых строк подряд - при достижении $empty_lines_quantity - считаем что это конец файла и выходим
          $empty_lines = 0;
          while ($empty_lines < $this->empty_lines_quantity) {
ad2e91f7   Mihail   move multyparser ...
76
  
2d4b1514   Mihail   adapted xls parser
77
78
79
              // прочтем строку из файла, если это не первый проход
              if (!$first_circle){
                  $this->readRow();
ad2e91f7   Mihail   move multyparser ...
80
81
              }
  
2d4b1514   Mihail   adapted xls parser
82
83
              $first_circle = false;
  
ad2e91f7   Mihail   move multyparser ...
84
85
86
87
88
              // уберем пустые колонки из ряда
              if ($this->keys === NULL) {
                  $this->filterRow();
              }
  
2d4b1514   Mihail   adapted xls parser
89
90
91
92
93
94
              if ($this->isEmptyRow()) {
                  //счетчик пустых строк
                  $empty_lines++;
                  $this->current_row_number++;
                  continue;
              }
ad2e91f7   Mihail   move multyparser ...
95
  
2d4b1514   Mihail   adapted xls parser
96
              // запустим конвертирование
ad2e91f7   Mihail   move multyparser ...
97
98
              $this->adjustRowToSettings();
  
2d4b1514   Mihail   adapted xls parser
99
100
              // установим отпарсенную строку в итоговый массив результата
              $this->setResult();
ad2e91f7   Mihail   move multyparser ...
101
102
103
              // строка не пустая, имеем прочитанный массив значений
              $this->current_row_number++;
  
ad2e91f7   Mihail   move multyparser ...
104
105
106
107
108
109
              // если у нас установлен лимит, при  его достижении прекращаем парсинг
              if ($this->isLastLine())
                  break;
  
              // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД
              $empty_lines = 0;
ad2e91f7   Mihail   move multyparser ...
110
          }
ad2e91f7   Mihail   move multyparser ...
111
112
113
114
115
      }
  
      /**
       * определяет первую значимую строку,
       * считывается файл пока в нем не встретится строка с непустыми колонками
2d4b1514   Mihail   adapted xls parser
116
117
       * или пока не дойдет до first_line
       * пропускает заголовок если он указан
ad2e91f7   Mihail   move multyparser ...
118
119
120
       */
      protected function shiftToFirstValuableLine()
      {
2d4b1514   Mihail   adapted xls parser
121
          // читаем пока не встретим значимую строку, или пока не дойдем до first_line
ad2e91f7   Mihail   move multyparser ...
122
          do {
ad2e91f7   Mihail   move multyparser ...
123
124
              $this->current_row_number++;
              $this->readRow();
2d4b1514   Mihail   adapted xls parser
125
          } while ( $this->isEmptyRow() && ( $this->first_line < $this->current_row_number ) );
ad2e91f7   Mihail   move multyparser ...
126
  
2d4b1514   Mihail   adapted xls parser
127
128
129
130
131
          // если указан заголовок, то его мы тоже пропускаем (читаем далее)
          if( $this->has_header_row ) {
              $this->current_row_number++;
              $this->readRow();
          }
ad2e91f7   Mihail   move multyparser ...
132
133
134
135
136
137
138
      }
  
      /**
       * @return array - одномерный массив результата парсинга строки
       */
      protected function adjustRowToSettings()
      {
ad2e91f7   Mihail   move multyparser ...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
          // если есть заголовок, то перед конвертацией его нужно назначить
          if ($this->keys !== NULL) {
              // adjust row to keys
              $this->adjustRowToKeys();
              // назначим заголовок
              $this->row = array_combine($this->keys, $this->row);
          }
  
          // попытаемся конвертировать прочитанные значения согласно конфигурации котнвертера значений
          $this->row = $this->convert($this->row);
  
          // обрежем массив к первой значимой колонке
          if ($this->first_column) {
  
              $this->row = array_slice($this->row, $this->first_column);
  
          }
  
      }
  
2d4b1514   Mihail   adapted xls parser
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
      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;
ad2e91f7   Mihail   move multyparser ...
184
185
              }
          }
2d4b1514   Mihail   adapted xls parser
186
187
  
          return $is_empty;
ad2e91f7   Mihail   move multyparser ...
188
189
      }
  
2d4b1514   Mihail   adapted xls parser
190
191
  
  
ad2e91f7   Mihail   move multyparser ...
192
193
      protected function filterRow()
      {
2d4b1514   Mihail   adapted xls parser
194
195
          // нет строки - нет фильтрации
          if ( empty( $this->row ) ) {
ad2e91f7   Mihail   move multyparser ...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
              return;
          }
          $this->row = array_filter($this->row, function ($val) {
              return !$this->isEmptyColumn($val);
          });
      }
  
      protected function isLastLine()
      {
  
          if (($this->last_line) && ($this->current_row_number > $this->last_line)) {
              return true;
          }
          return false;
      }
  
      protected function adjustRowToKeys()
      {
          //уберем из ряда те колонки которых нет в ключах
          $this->row = array_intersect_key($this->row, $this->keys);
  
          $keys_count = count($this->keys);
          $column_count = count($this->row);
          if ($keys_count != $column_count) {
              // найдем колонки которых нет в ряде но есть ключах
              $arr_diff = array_diff_key($this->keys, $this->row);
              foreach ($arr_diff as $key => $value) {
                  // колонки которых нет в ряде но есть ключах, добавим их с пустым значением
                  $this->row[$key] = '';
              }
          }
      }
  
  }