Blame view

lib/TableParser.php 8.41 KB
8e128526   Mihail   add xlsx parser
1
2
3
4
5
6
7
8
  <?php
  /**
   * Created by PhpStorm.
   * User: Tsurkanov
   * Date: 22.10.2015
   * Time: 15:53
   */
  
d0261fd1   Mihail   fixed namespace i...
9
  namespace yii\multiparser;
8e128526   Mihail   add xlsx parser
10
11
  
  
ec440fb6   Mihail   add supported ext...
12
13
  use common\components\CustomVarDamp;
  
a684f314   Mihail   add adjustRowToKe...
14
15
  abstract class TableParser extends Parser
  {
8e128526   Mihail   add xlsx parser
16
17
      /**
       * @var array - текущий отпарсенный ряд
a3b2aa93   Mihail   change meaning of...
18
19
20
       *если есть ключи, то колонки с пустыми значениями будут пропускаться (из ряда такие значения будут удаляться),
       * например если в файле вторая колонка пустая то она будет удалена
       * в остальных случаях парсятся все колонки (не проверяется - пустая ли колонка) и попадёт в итоговый массив
8e128526   Mihail   add xlsx parser
21
22
23
       */
      protected $row = [];
  
a3b2aa93   Mihail   change meaning of...
24
25
26
27
28
      /** @var int - первая строка с которой начинать парсить
       * эта строка будет считаться первой значимой строкой
       * если установлен аттрибут $has_header_row,
       * тогда следующая строка будет считаться заголовком и будет пропущена
       */
8e128526   Mihail   add xlsx parser
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
a3b2aa93   Mihail   change meaning of...
40
41
42
43
44
       * имеет ли файл заголовок в первой значимой строке
       * true - первая значимая строка будет пропущена
       */
      public $has_header_row = true;
  
8e128526   Mihail   add xlsx parser
45
46
47
48
49
  
      /** @var int - количество значимых колонок, что бы определить первую значимую строку
       * используется при автоопределении первой строки*/
      public $min_column_quantity = 5;
      /** @var int - количество пустых строк, что бы определить конец файла,
a684f314   Mihail   add adjustRowToKe...
50
       * такое количеество подряд пустых строк считается концом файла*/
8e128526   Mihail   add xlsx parser
51
52
53
54
55
56
57
      public $empty_lines_quantity = 3;
  
  
      /** @var int - номер текущей строки парсера */
      protected $current_row_number = 0;
  
  
8e128526   Mihail   add xlsx parser
58
59
60
61
      protected abstract function isEmptyColumn($column_value);
  
      protected abstract function readRow();
  
d1fac7a9   Mihail   add parsing sheet...
62
63
      protected abstract function setResult();
  
8e128526   Mihail   add xlsx parser
64
65
66
  
      public function read()
      {
a3b2aa93   Mihail   change meaning of...
67
68
69
70
71
          // получим первую значимую строку
          $this->shiftToFirstValuableLine();
  
          // первый проход, строка прочитана в shiftToFirstValuableLine
          $first_circle = true;
8e128526   Mihail   add xlsx parser
72
73
74
  
          // будем считать количество пустых строк подряд - при достижении $empty_lines_quantity - считаем что это конец файла и выходим
          $empty_lines = 0;
a684f314   Mihail   add adjustRowToKe...
75
          while ($empty_lines < $this->empty_lines_quantity) {
8e128526   Mihail   add xlsx parser
76
  
a3b2aa93   Mihail   change meaning of...
77
78
79
              // прочтем строку из файла, если это не первый проход
              if (!$first_circle){
                  $this->readRow();
8e128526   Mihail   add xlsx parser
80
81
              }
  
a3b2aa93   Mihail   change meaning of...
82
83
              $first_circle = false;
  
58f734e6   Mihail   fixed issue with ...
84
              // уберем пустые колонки из ряда
a684f314   Mihail   add adjustRowToKe...
85
86
87
88
              if ($this->keys === NULL) {
                  $this->filterRow();
              }
  
a3b2aa93   Mihail   change meaning of...
89
90
91
92
93
94
              if ($this->isEmptyRow()) {
                  //счетчик пустых строк
                  $empty_lines++;
                  $this->current_row_number++;
                  continue;
              }
58f734e6   Mihail   fixed issue with ...
95
  
a3b2aa93   Mihail   change meaning of...
96
              // запустим конвертирование
a684f314   Mihail   add adjustRowToKe...
97
              $this->adjustRowToSettings();
8e128526   Mihail   add xlsx parser
98
  
a3b2aa93   Mihail   change meaning of...
99
100
              // установим отпарсенную строку в итоговый массив результата
              $this->setResult();
8e128526   Mihail   add xlsx parser
101
102
103
              // строка не пустая, имеем прочитанный массив значений
              $this->current_row_number++;
  
8e128526   Mihail   add xlsx parser
104
              // если у нас установлен лимит, при  его достижении прекращаем парсинг
a684f314   Mihail   add adjustRowToKe...
105
              if ($this->isLastLine())
8e128526   Mihail   add xlsx parser
106
107
108
109
                  break;
  
              // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД
              $empty_lines = 0;
8e128526   Mihail   add xlsx parser
110
          }
8e128526   Mihail   add xlsx parser
111
      }
a684f314   Mihail   add adjustRowToKe...
112
  
8e128526   Mihail   add xlsx parser
113
114
115
      /**
       * определяет первую значимую строку,
       * считывается файл пока в нем не встретится строка с непустыми колонками
a3b2aa93   Mihail   change meaning of...
116
117
       * или пока не дойдет до first_line
       * пропускает заголовок если он указан
8e128526   Mihail   add xlsx parser
118
119
120
       */
      protected function shiftToFirstValuableLine()
      {
a3b2aa93   Mihail   change meaning of...
121
          // читаем пока не встретим значимую строку, или пока не дойдем до first_line
a684f314   Mihail   add adjustRowToKe...
122
          do {
f6e54131   Mihail   fixed keys and he...
123
              $this->current_row_number++;
8e128526   Mihail   add xlsx parser
124
              $this->readRow();
a3b2aa93   Mihail   change meaning of...
125
          } while ( $this->isEmptyRow() && ( $this->first_line < $this->current_row_number ) );
8e128526   Mihail   add xlsx parser
126
  
a3b2aa93   Mihail   change meaning of...
127
128
129
130
131
          // если указан заголовок, то его мы тоже пропускаем (читаем далее)
          if( $this->has_header_row ) {
              $this->current_row_number++;
              $this->readRow();
          }
8e128526   Mihail   add xlsx parser
132
133
134
135
136
      }
  
      /**
       * @return array - одномерный массив результата парсинга строки
       */
a684f314   Mihail   add adjustRowToKe...
137
      protected function adjustRowToSettings()
8e128526   Mihail   add xlsx parser
138
      {
a684f314   Mihail   add adjustRowToKe...
139
140
141
142
143
144
145
          // если есть заголовок, то перед конвертацией его нужно назначить
          if ($this->keys !== NULL) {
              // adjust row to keys
              $this->adjustRowToKeys();
              // назначим заголовок
              $this->row = array_combine($this->keys, $this->row);
          }
8e128526   Mihail   add xlsx parser
146
  
a684f314   Mihail   add adjustRowToKe...
147
148
          // попытаемся конвертировать прочитанные значения согласно конфигурации котнвертера значений
          $this->row = $this->convert($this->row);
8e128526   Mihail   add xlsx parser
149
  
a684f314   Mihail   add adjustRowToKe...
150
151
          // обрежем массив к первой значимой колонке
          if ($this->first_column) {
8e128526   Mihail   add xlsx parser
152
  
a684f314   Mihail   add adjustRowToKe...
153
              $this->row = array_slice($this->row, $this->first_column);
8e128526   Mihail   add xlsx parser
154
  
a684f314   Mihail   add adjustRowToKe...
155
          }
8e128526   Mihail   add xlsx parser
156
157
158
  
      }
  
a3b2aa93   Mihail   change meaning of...
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;
8e128526   Mihail   add xlsx parser
184
185
              }
          }
a3b2aa93   Mihail   change meaning of...
186
187
  
          return $is_empty;
8e128526   Mihail   add xlsx parser
188
189
      }
  
a3b2aa93   Mihail   change meaning of...
190
191
  
  
a684f314   Mihail   add adjustRowToKe...
192
193
      protected function filterRow()
      {
a3b2aa93   Mihail   change meaning of...
194
195
          // нет строки - нет фильтрации
          if ( empty( $this->row ) ) {
d1fac7a9   Mihail   add parsing sheet...
196
197
              return;
          }
a684f314   Mihail   add adjustRowToKe...
198
          $this->row = array_filter($this->row, function ($val) {
8e128526   Mihail   add xlsx parser
199
200
              return !$this->isEmptyColumn($val);
          });
8e128526   Mihail   add xlsx parser
201
202
      }
  
a684f314   Mihail   add adjustRowToKe...
203
204
      protected function isLastLine()
      {
8e128526   Mihail   add xlsx parser
205
  
a684f314   Mihail   add adjustRowToKe...
206
          if (($this->last_line) && ($this->current_row_number > $this->last_line)) {
8e128526   Mihail   add xlsx parser
207
208
209
210
211
              return true;
          }
          return false;
      }
  
a684f314   Mihail   add adjustRowToKe...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
      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] = '';
              }
          }
      }
  
8e128526   Mihail   add xlsx parser
229
  }