Blame view

vendor/yiisoft/multiparser/CsvParser.php 7.41 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
  /**
   * Class CsvParser
   * @package yii\multiparser
6215a30d   Mihail   add converter int...
12
   * @todo - перевести на анг. яз.
474f35bf   Mihail   add DynamicFormHe...
13
   */
6215a30d   Mihail   add converter int...
14
  class CsvParser extends Parser
999b9326   Mihail   add detectStartPo...
15
  {
40ff24a1   Mihail   refactor CsvParse...
16
17
      /** @var bool
      имеет ли файл заголовок который будет установлен ключами возвращемого массива*/
e55d56cc   Mihail   add draft version...
18
      public $hasHeaderRow = false;
40ff24a1   Mihail   refactor CsvParse...
19
20
      /** @var array - массив с заголовком,
       * если не указан и установлено свойство $hasHeaderRow - будет определен автоматически */
90ff40df   Mihail   fixed issue with ...
21
     // public $keys; - определен в родительском классе
1e991822   Mihail   csv parser with e...
22
  
40ff24a1   Mihail   refactor CsvParse...
23
      /** @var int - первая строка с которой начинать парсить */
e55d56cc   Mihail   add draft version...
24
      public $first_line = 0;
1e991822   Mihail   csv parser with e...
25
  
40ff24a1   Mihail   refactor CsvParse...
26
27
28
29
30
      /** @var int - последняя строка до которой  парсить
       * если не указана, то парсинг происходит до конца файла*/
      public $last_line = 0;
  
      /** @var int - первая колонка файла с которой начнется парсинг */
e55d56cc   Mihail   add draft version...
31
      public $first_column = 0;
b13b1c83   Mihail   final version par...
32
  
40ff24a1   Mihail   refactor CsvParse...
33
      /** @var string - разделитель csv */
e55d56cc   Mihail   add draft version...
34
      public $delimiter = ';';
40ff24a1   Mihail   refactor CsvParse...
35
36
37
38
39
40
41
42
  
      /** @var bool
      нужно ли искать автоматически первоую значисмую строку (не пустая строка)
       * иначе первая строка будет взята из аттрибута $first_line */
      public $auto_detect_first_line = false;
  
      /** @var int - количество значимых колонок, что бы определить первую значимую строку
       * используется при автоопределении первой строки*/
e55d56cc   Mihail   add draft version...
43
      public $min_column_quantity = 5;
dc10d651   Mihail   add value filter ...
44
  
6215a30d   Mihail   add converter int...
45
46
47
48
  //    /** @var array - конфигурация конвертера значений */
  //    public $converter_conf = [];
  //    /** @var array - конвертер созданный по конфигурации */
  //    public $converter = NULL;
d3cf6647   Mihail   add multiply pric...
49
50
      /** @var int - текущая строка */
      private $current_line = 0;
5c710262   Mihail   edit csv parser -...
51
  
474f35bf   Mihail   add DynamicFormHe...
52
  
40ff24a1   Mihail   refactor CsvParse...
53
      /**
74072a2a   Mihail   add first version...
54
       * метод устанвливает нужные настройки объекта SplFileObject, для работы с csv
40ff24a1   Mihail   refactor CsvParse...
55
       */
e55d56cc   Mihail   add draft version...
56
57
      public function setup()
      {
999b9326   Mihail   add detectStartPo...
58
59
60
          $this->file->setCsvControl($this->delimiter);
          $this->file->setFlags(\SplFileObject::READ_CSV);
          $this->file->setFlags(\SplFileObject::SKIP_EMPTY);
aa518ad3   Mihail   finishing with co...
61
  
40ff24a1   Mihail   refactor CsvParse...
62
63
          if ($this->auto_detect_first_line) {
              $this->shiftToFirstValuableLine();
e55d56cc   Mihail   add draft version...
64
          }
aa518ad3   Mihail   finishing with co...
65
  
6215a30d   Mihail   add converter int...
66
          parent::setup();
74072a2a   Mihail   add first version...
67
  
6215a30d   Mihail   add converter int...
68
      }
74072a2a   Mihail   add first version...
69
      /**
40ff24a1   Mihail   refactor CsvParse...
70
71
72
73
74
75
       * определяет первую значимую строку,
       * считывается файл пока в нем не встретится строка с непустыми колонками
       * в количестве указанном в атрибуте min_column_quantity
       * в результате выполнения курсор ресурса будет находится на последней незначимой строке
       */
      protected function shiftToFirstValuableLine()
e55d56cc   Mihail   add draft version...
76
      {
e55d56cc   Mihail   add draft version...
77
  
40ff24a1   Mihail   refactor CsvParse...
78
          $finish = false;
2cdc93f0   Mihail   add crud models f...
79
          while (!$finish ) {
d3cf6647   Mihail   add multiply pric...
80
81
              $this->current_line ++;
  
999b9326   Mihail   add detectStartPo...
82
              $j = 0;
93e39994   Mihail   fixed parser and ...
83
              $row = $this->file->fgetcsv();;
999b9326   Mihail   add detectStartPo...
84
85
              if ($row === false) {
                  continue;
e55d56cc   Mihail   add draft version...
86
              }
999b9326   Mihail   add detectStartPo...
87
  
999b9326   Mihail   add detectStartPo...
88
              for ($i = 1; $i <= count($row); $i++) {
0084d336   Administrator   Importers CRUD
89
             //     CustomVarDamp::dump($row[$i]);
999b9326   Mihail   add detectStartPo...
90
91
92
93
94
95
  
                  if ($row[$i - 1] <> '') {
                      $j++;
                  }
  
                  if ($j >= $this->min_column_quantity) {
40ff24a1   Mihail   refactor CsvParse...
96
                      break 2;
999b9326   Mihail   add detectStartPo...
97
                  }
e55d56cc   Mihail   add draft version...
98
99
              }
          }
2cdc93f0   Mihail   add crud models f...
100
101
102
103
          // @todo - сделать опционально
          // код для того что бы парсить первую строку, закомментировано как предполагается что первая значимая строка это заголовок
   //       $this->current_line --;
  //        $this->file->seek( $this->current_line );
e55d56cc   Mihail   add draft version...
104
      }
1e991822   Mihail   csv parser with e...
105
106
  
      /**
40ff24a1   Mihail   refactor CsvParse...
107
108
       * @return array - итоговый двумерный массив с результатом парсинга
       * метод считывает с открытого файла данные построчно
1e991822   Mihail   csv parser with e...
109
110
111
       */
      public function read()
      {
aa518ad3   Mihail   finishing with co...
112
  
1e991822   Mihail   csv parser with e...
113
          $return = [];
40ff24a1   Mihail   refactor CsvParse...
114
  
01746976   Mihail   fix errors with w...
115
116
117
118
          // будем считать количество пустых строк подряд - при трех подряд - считаем что это конец файла и выходим
          $empty_lines = 0;
          while ( $empty_lines < 3 ) {
              // прочтем строку из файла. Если там есть значения - то в ней массив, иначе - false
d3cf6647   Mihail   add multiply pric...
119
              $row = $this->readRow(  );
40ff24a1   Mihail   refactor CsvParse...
120
  
01746976   Mihail   fix errors with w...
121
122
123
124
125
126
              if ($row === false) {
                  //счетчик пустых строк
                  $empty_lines++;
                  continue;
              }
              // строка не пустая, имеем прочитанный массив значений
d3cf6647   Mihail   add multiply pric...
127
              $this->current_line++;
1e991822   Mihail   csv parser with e...
128
              if ($this->hasHeaderRow) {
93e39994   Mihail   fixed parser and ...
129
                  // в файле есть заголовок, но он еще не назначен, назначим
dc10d651   Mihail   add value filter ...
130
131
                  if ($this->keys === NULL) {
                      $this->keys = array_values($row);
1e991822   Mihail   csv parser with e...
132
                  }
1e991822   Mihail   csv parser with e...
133
              }
40ff24a1   Mihail   refactor CsvParse...
134
              // если у нас установлен лимит, при  его достижении прекращаем парсинг
d3cf6647   Mihail   add multiply pric...
135
              if (($this->last_line) && ($this->current_line > $this->last_line)) {
999b9326   Mihail   add detectStartPo...
136
137
                  break;
              }
01746976   Mihail   fix errors with w...
138
139
              // обнуляем счетчик, так как считаюся пустые строки ПОДРЯД
              $empty_lines = 0;
93e39994   Mihail   fixed parser and ...
140
141
  
              $return[] = $row;
1e991822   Mihail   csv parser with e...
142
143
          }
  
1e991822   Mihail   csv parser with e...
144
145
          return $return;
      }
95c167d6   Mihail   add managing with...
146
      
1e991822   Mihail   csv parser with e...
147
  
40ff24a1   Mihail   refactor CsvParse...
148
149
150
      /**
       * @return array - одномерный массив результата парсинга строки
       */
d3cf6647   Mihail   add multiply pric...
151
      protected function readRow(  )
1e991822   Mihail   csv parser with e...
152
      {
999b9326   Mihail   add detectStartPo...
153
          $row = $this->file->fgetcsv();
706a1491   Mihail   add form, model a...
154
  
74072a2a   Mihail   add first version...
155
          if (is_array($row)) {
706a1491   Mihail   add form, model a...
156
157
158
159
              // уберем нулевые колонки
              $row = array_filter($row, function($val){
                  return $val <> '';
              });
93e39994   Mihail   fixed parser and ...
160
161
162
163
              // если есть заголовок, то перед конвертацией его нужно назначить
              if ($this->hasHeaderRow && $this->keys !== NULL) {
  
                  if (count($this->keys) !== count($row)) {
95c167d6   Mihail   add managing with...
164
                      throw new \Exception("Ошибка парсинга файла в строке # {$this->current_line}. Не соответсвие числа ключевых колонок (заголовка) - числу колонок с данными", 0, 1, $this->file->getBasename(), $this->current_line);
93e39994   Mihail   fixed parser and ...
165
166
167
168
169
                  }
  
                  $row = array_combine($this->keys, $row);
              }
              // попытаемся конвертировать прочитанные значения согласно конфигурации котнвертера значений
74072a2a   Mihail   add first version...
170
              $row = $this->convert($row);
93e39994   Mihail   fixed parser and ...
171
172
              // обрежем массив к первой значимой колонке
              if ( $this->first_column ) {
40ff24a1   Mihail   refactor CsvParse...
173
  
74072a2a   Mihail   add first version...
174
                  $row = array_slice($row, $this->first_column);
40ff24a1   Mihail   refactor CsvParse...
175
  
74072a2a   Mihail   add first version...
176
              }
dfeb2d10   Mihail   edit universal cs...
177
          }
999b9326   Mihail   add detectStartPo...
178
179
          if (is_null($row))
              $row = false;
dc10d651   Mihail   add value filter ...
180
  
dfeb2d10   Mihail   edit universal cs...
181
          return $row;
1e991822   Mihail   csv parser with e...
182
183
184
  
      }
  
1e991822   Mihail   csv parser with e...
185
186
  
  }