Blame view

vendor/yiisoft/multiparser/CsvParser.php 7.99 KB
1e991822   Mihail   csv parser with e...
1
2
  <?php
  /**
1e991822   Mihail   csv parser with e...
3
  
40ff24a1   Mihail   refactor CsvParse...
4
   */
036717a1   Mihail   add error excepti...
5
  namespace yii\multiparser;
93e39994   Mihail   fixed parser and ...
6
  use common\components\CustomVarDamp;
dc10d651   Mihail   add value filter ...
7
  
1e991822   Mihail   csv parser with e...
8
  
474f35bf   Mihail   add DynamicFormHe...
9
10
11
12
  /**
   * Class CsvParser
   * @package yii\multiparser
   */
37656b1f   Mihail   add parser interf...
13
  class CsvParser implements ParserInterface
999b9326   Mihail   add detectStartPo...
14
  {
1e991822   Mihail   csv parser with e...
15
  
1e991822   Mihail   csv parser with e...
16
  
40ff24a1   Mihail   refactor CsvParse...
17
18
      /** @var bool
      имеет ли файл заголовок который будет установлен ключами возвращемого массива*/
e55d56cc   Mihail   add draft version...
19
      public $hasHeaderRow = false;
40ff24a1   Mihail   refactor CsvParse...
20
21
22
      /** @var array - массив с заголовком,
       * если не указан и установлено свойство $hasHeaderRow - будет определен автоматически */
      public $keys;
1e991822   Mihail   csv parser with e...
23
  
40ff24a1   Mihail   refactor CsvParse...
24
      /** @var экземляр SplFileObject читаемого файла */
e55d56cc   Mihail   add draft version...
25
      public $file;
1e991822   Mihail   csv parser with e...
26
  
40ff24a1   Mihail   refactor CsvParse...
27
      /** @var int - первая строка с которой начинать парсить */
e55d56cc   Mihail   add draft version...
28
      public $first_line = 0;
1e991822   Mihail   csv parser with e...
29
  
40ff24a1   Mihail   refactor CsvParse...
30
31
32
33
34
      /** @var int - последняя строка до которой  парсить
       * если не указана, то парсинг происходит до конца файла*/
      public $last_line = 0;
  
      /** @var int - первая колонка файла с которой начнется парсинг */
e55d56cc   Mihail   add draft version...
35
      public $first_column = 0;
b13b1c83   Mihail   final version par...
36
  
40ff24a1   Mihail   refactor CsvParse...
37
      /** @var string - разделитель csv */
e55d56cc   Mihail   add draft version...
38
      public $delimiter = ';';
40ff24a1   Mihail   refactor CsvParse...
39
40
41
42
43
44
45
46
  
      /** @var bool
      нужно ли искать автоматически первоую значисмую строку (не пустая строка)
       * иначе первая строка будет взята из аттрибута $first_line */
      public $auto_detect_first_line = false;
  
      /** @var int - количество значимых колонок, что бы определить первую значимую строку
       * используется при автоопределении первой строки*/
e55d56cc   Mihail   add draft version...
47
      public $min_column_quantity = 5;
dc10d651   Mihail   add value filter ...
48
  
74072a2a   Mihail   add first version...
49
50
51
52
      /** @var array - конфигурация конвертера значений */
      public $converter_conf = [];
      /** @var array - конвертер созданный по конфигурации */
      public $converter = NULL;
5c710262   Mihail   edit csv parser -...
53
  
474f35bf   Mihail   add DynamicFormHe...
54
  
40ff24a1   Mihail   refactor CsvParse...
55
      /**
74072a2a   Mihail   add first version...
56
       * метод устанвливает нужные настройки объекта SplFileObject, для работы с csv
40ff24a1   Mihail   refactor CsvParse...
57
       */
e55d56cc   Mihail   add draft version...
58
59
      public function setup()
      {
999b9326   Mihail   add detectStartPo...
60
61
62
          $this->file->setCsvControl($this->delimiter);
          $this->file->setFlags(\SplFileObject::READ_CSV);
          $this->file->setFlags(\SplFileObject::SKIP_EMPTY);
aa518ad3   Mihail   finishing with co...
63
  
40ff24a1   Mihail   refactor CsvParse...
64
65
          if ($this->auto_detect_first_line) {
              $this->shiftToFirstValuableLine();
e55d56cc   Mihail   add draft version...
66
          }
74072a2a   Mihail   add first version...
67
68
          $this->setupConverter();
  
1e991822   Mihail   csv parser with e...
69
70
      }
  
40ff24a1   Mihail   refactor CsvParse...
71
      /**
74072a2a   Mihail   add first version...
72
73
74
75
76
       * устанавливает конвертер значений согласно конфигурационным настройкам
       */
      public function setupConverter()
      {
          if (!count($this->converter_conf)) {
d21c5c5f   Mihail   XMLparser - read ...
77
              $this->converter = new Converter();
74072a2a   Mihail   add first version...
78
79
80
81
              if ($this->hasHeaderRow) {
                  // если у файла есть заголовок, то в результате имеем ассоциативный массив
                  $this->converter_conf['hasKey'] = 1;
              }
8894c93a   Mihail   add Importers fil...
82
              //$this->converter->configuration = $this->converter_conf;
aa518ad3   Mihail   finishing with co...
83
  
74072a2a   Mihail   add first version...
84
85
86
87
88
          }
      }
  
  
      /**
40ff24a1   Mihail   refactor CsvParse...
89
90
91
92
93
94
       * определяет первую значимую строку,
       * считывается файл пока в нем не встретится строка с непустыми колонками
       * в количестве указанном в атрибуте min_column_quantity
       * в результате выполнения курсор ресурса будет находится на последней незначимой строке
       */
      protected function shiftToFirstValuableLine()
e55d56cc   Mihail   add draft version...
95
      {
e55d56cc   Mihail   add draft version...
96
  
40ff24a1   Mihail   refactor CsvParse...
97
98
99
          $finish = false;
  
          while (!$finish) {
999b9326   Mihail   add detectStartPo...
100
              $j = 0;
93e39994   Mihail   fixed parser and ...
101
              $row = $this->file->fgetcsv();;
999b9326   Mihail   add detectStartPo...
102
103
              if ($row === false) {
                  continue;
e55d56cc   Mihail   add draft version...
104
              }
999b9326   Mihail   add detectStartPo...
105
  
999b9326   Mihail   add detectStartPo...
106
107
108
109
110
111
112
              for ($i = 1; $i <= count($row); $i++) {
  
                  if ($row[$i - 1] <> '') {
                      $j++;
                  }
  
                  if ($j >= $this->min_column_quantity) {
40ff24a1   Mihail   refactor CsvParse...
113
                      break 2;
999b9326   Mihail   add detectStartPo...
114
                  }
e55d56cc   Mihail   add draft version...
115
116
              }
          }
e55d56cc   Mihail   add draft version...
117
      }
1e991822   Mihail   csv parser with e...
118
119
  
      /**
40ff24a1   Mihail   refactor CsvParse...
120
121
       * @return array - итоговый двумерный массив с результатом парсинга
       * метод считывает с открытого файла данные построчно
1e991822   Mihail   csv parser with e...
122
123
124
       */
      public function read()
      {
aa518ad3   Mihail   finishing with co...
125
  
1e991822   Mihail   csv parser with e...
126
          $return = [];
40ff24a1   Mihail   refactor CsvParse...
127
128
  
          $current_line = 0;
01746976   Mihail   fix errors with w...
129
130
131
132
          // будем считать количество пустых строк подряд - при трех подряд - считаем что это конец файла и выходим
          $empty_lines = 0;
          while ( $empty_lines < 3 ) {
              // прочтем строку из файла. Если там есть значения - то в ней массив, иначе - false
93e39994   Mihail   fixed parser and ...
133
              $row = $this->readRow( $current_line );
40ff24a1   Mihail   refactor CsvParse...
134
  
01746976   Mihail   fix errors with w...
135
136
137
138
139
140
              if ($row === false) {
                  //счетчик пустых строк
                  $empty_lines++;
                  continue;
              }
              // строка не пустая, имеем прочитанный массив значений
40ff24a1   Mihail   refactor CsvParse...
141
              $current_line++;
1e991822   Mihail   csv parser with e...
142
              if ($this->hasHeaderRow) {
93e39994   Mihail   fixed parser and ...
143
                  // в файле есть заголовок, но он еще не назначен, назначим
dc10d651   Mihail   add value filter ...
144
145
                  if ($this->keys === NULL) {
                      $this->keys = array_values($row);
1e991822   Mihail   csv parser with e...
146
                  }
1e991822   Mihail   csv parser with e...
147
              }
40ff24a1   Mihail   refactor CsvParse...
148
149
              // если у нас установлен лимит, при  его достижении прекращаем парсинг
              if (($this->last_line) && ($current_line > $this->last_line)) {
999b9326   Mihail   add detectStartPo...
150
151
                  break;
              }
01746976   Mihail   fix errors with w...
152
153
              // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД
              $empty_lines = 0;
93e39994   Mihail   fixed parser and ...
154
155
  
              $return[] = $row;
1e991822   Mihail   csv parser with e...
156
157
158
          }
  
          $this->closeHandler();
1e991822   Mihail   csv parser with e...
159
160
161
          return $return;
      }
  
2957209c   Mihail   csv parser - add ...
162
  
dfeb2d10   Mihail   edit universal cs...
163
      protected function closeHandler()
1e991822   Mihail   csv parser with e...
164
      {
2957209c   Mihail   csv parser - add ...
165
          $this->file = NULL;
1e991822   Mihail   csv parser with e...
166
167
      }
  
40ff24a1   Mihail   refactor CsvParse...
168
169
170
      /**
       * @return array - одномерный массив результата парсинга строки
       */
93e39994   Mihail   fixed parser and ...
171
      protected function readRow( $current_line )
1e991822   Mihail   csv parser with e...
172
      {
999b9326   Mihail   add detectStartPo...
173
          $row = $this->file->fgetcsv();
74072a2a   Mihail   add first version...
174
          if (is_array($row)) {
93e39994   Mihail   fixed parser and ...
175
176
177
178
179
180
181
182
183
184
185
              // если есть заголовок, то перед конвертацией его нужно назначить
              if ($this->hasHeaderRow && $this->keys !== NULL) {
  
                  if (count($this->keys) !== count($row)) {
  //
                      throw new \ErrorException("Ошибка парсинга файла в строке # {$current_line}. Не соответсвие числа ключевых колонок (заголовка) - числу колонок с данными", 0, 1, $this->file->getBasename(), $current_line);
                  }
  
                  $row = array_combine($this->keys, $row);
              }
              // попытаемся конвертировать прочитанные значения согласно конфигурации котнвертера значений
74072a2a   Mihail   add first version...
186
              $row = $this->convert($row);
93e39994   Mihail   fixed parser and ...
187
188
              // обрежем массив к первой значимой колонке
              if ( $this->first_column ) {
40ff24a1   Mihail   refactor CsvParse...
189
  
74072a2a   Mihail   add first version...
190
                  $row = array_slice($row, $this->first_column);
40ff24a1   Mihail   refactor CsvParse...
191
  
74072a2a   Mihail   add first version...
192
              }
dfeb2d10   Mihail   edit universal cs...
193
          }
999b9326   Mihail   add detectStartPo...
194
195
          if (is_null($row))
              $row = false;
dc10d651   Mihail   add value filter ...
196
  
dfeb2d10   Mihail   edit universal cs...
197
          return $row;
1e991822   Mihail   csv parser with e...
198
199
200
  
      }
  
74072a2a   Mihail   add first version...
201
202
203
204
205
206
207
208
209
210
      /**
       * @param $arr
       * @return mixed
       * преобразовует значения прочитанного массива в нужные типы, согласно конфигурации конвертера
       */
      protected function convert($arr)
      {
          $result = $arr;
          $converter = $this->converter;
  
74072a2a   Mihail   add first version...
211
212
          if (!is_null($converter)) {
  
8894c93a   Mihail   add Importers fil...
213
              $result = $converter->convertByConfiguration( $arr, $this->converter_conf );
74072a2a   Mihail   add first version...
214
215
216
217
218
219
220
  
          }
  
          return $result;
  
      }
  
1e991822   Mihail   csv parser with e...
221
222
  
  }