Documentation/Index/MigratePHPExcelToPhpSpreadsheet: AdditionalAnalyticsImportService.inc

Plik AdditionalAnalyticsImportService.inc, 11.5 KB (dodany przez TS, 3 years temu)
xx
Line 
1<?php
2require_once(MOD_PATH.'Dictionaries/VatNote/beans/AdditionalAnalyticsBean.inc');
3
4use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
5use PhpOffice\PhpSpreadsheet\IOFactory;
6
7/**
8 * AdditionalAnalyticsImportService
9 *
10 * @author Tomasz Świenty
11 * @version 2.0
12 * @copyright Copyright (c) eDokumenty
13 */
14final class AdditionalAnalyticsImportService {
15
16
17    const AVAILABLE_EXT = ['xls', 'xlsx', 'xlsm', 'xltx', 'xltm', 'xlt', 'xml', 'ods', 'ots'];
18
19
20    /**
21     * @var string[]
22     */
23    private static $colsMap = [
24        'A' => 'segmnt',
25        'B' => 'dscrpt',
26        'C' => 'year__',
27        'D' => 'projid',
28        'E' => 'acorid',
29    ];
30
31
32    /**
33     * @var array
34     */
35    private static $cache = [];
36
37
38    /**
39     * @param string $file
40     *
41     * @return bool
42     * @throws Exception
43     */
44    public static function checkFileExtension(string $file): bool {
45
46        $info = pathinfo($file);
47        if (!in_array($info['extension'], self::AVAILABLE_EXT)) {
48            throw new Exception(sprintf(Translator::translate('Nieobsługiwane rozszerzenie pliku %s. Obsługiwane rozszerzenia to %s'), htmlspecialchars($info['extension'], ENT_QUOTES, 'UTF-8'), implode(', ', self::AVAILABLE_EXT)));
49        }
50
51        return TRUE;
52
53    }
54
55
56    /**
57     * @param string           $file
58     * @param array            $options
59     * @param ProgressBar|null $progressBar
60     *
61     * @return int
62     * @throws CustomErrorException
63     * @throws UserRightsException
64     * @throws \PhpOffice\PhpSpreadsheet\Exception
65     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
66     * @throws Exception
67     */
68    public static function importFromFile(string $file, array $options = [], ?ProgressBar $progressBar = NULL): int {
69
70        if (!UserRights::checkSysAcc('bswfms.settings.level1')) {
71            throw new UserRightsException(NULL, 'bswfms.settings.level1');
72        }
73
74        if (!isset($options['adantp'])) {
75            throw new CustomErrorException(Translator::translate('Brak klucza adantp - typ dodatkowej analityki'));
76        }
77
78        set_time_limit(0);
79        ini_set('memory_limit', MAX_MEMORY_LIMIT);
80
81        $reader = IOFactory::createReaderForFile($file);
82        $reader->setReadDataOnly(FALSE);
83
84        $spreadsheet = $reader->load($file);
85
86        $worksheet = $spreadsheet->getActiveSheet();
87
88        $highestRow = $worksheet->getHighestRow();
89        $highestColumnIndex = Coordinate::columnIndexFromString(array_key_last(self::$colsMap));
90
91        $db = PgManager::getInstance();
92
93        // !!!!!!!!!!!!!!!!!!!!!!!!
94        $db->commit();
95        $db->begin();
96        // !!!!!!!!!!!!!!!!!!!!!!!!
97
98        $counter = 0;
99        $progress = 0;
100
101        ErrorHandler::tryBegin();
102        $columnsLetterIndexMap = [];
103
104        try {
105            if ($progressBar) {
106                $progressBar->setMax(100);
107                $progressBar->setProgress(0);
108            }
109
110            // dla każdego wiersza poczynając od drugiego (pierwszy to nazwy kolumny)
111            for ($row = 2; $row <= $highestRow; ++$row) {
112                $progress++;
113
114                if ($progressBar) {
115                    $progressBar->setProgress((int)Number::mul(Number::div($progress, $highestRow, 2), 100, 2));
116                }
117
118                $dataMap = array_flip(self::$colsMap);
119
120                $entry = [];
121
122                // pobierz dane z komórek
123                for ($columnIndex = 1; $columnIndex <= $highestColumnIndex; ++$columnIndex) {
124                    if (!isset($columnsLetterIndexMap[$columnIndex])) {
125                        $columnsLetterIndexMap[$columnIndex] = Coordinate::stringFromColumnIndex($columnIndex);
126                    }
127
128                    $entry[strtoupper($columnsLetterIndexMap[$columnIndex])] = $worksheet->getCellByColumnAndRow($columnIndex, $row)->getFormattedValue();
129                }
130
131                $excelGridCoordinates = ':'.$row;
132
133                try {
134                    $entry = array_filter($entry);
135                    if (!$entry) {
136                        continue;
137                    }
138
139                    array_walk($dataMap, function(&$value, &$key) use ($entry) {
140                        if (isset($entry[$value])) {
141                            $value = $entry[$value];
142                        } else {
143                            $value = NULL;
144                        }
145                    });
146
147                    try {
148                        foreach ($dataMap as $k => $v) {
149                            $excelGridCoordinates = array_search($k, self::$colsMap).':'.$row;
150
151                            $dataMap[$k] = self::mapData($k, $v, $options);
152                            self::validate($k, $dataMap);
153                        }
154                    } catch (Exception $exception) {
155                        $db->rollback();
156                        throw $exception;
157                    }
158
159                } catch (Exception $exception) {
160                    throw new Exception(sprintf(Translator::translate('Wystąpił błąd w komórce %s: <br><br> %s'), '<b>'.$excelGridCoordinates.'</b>', $exception->getMessage()), 0, $exception);
161                }
162
163                $bean = new AdditionalAnalyticsBean();
164                $bean->data = array_merge($bean->data, $dataMap);
165                $bean->set('adantp', $options['adantp']);
166
167                $additionalAnalyticID = $bean->save();
168
169                if (!$additionalAnalyticID) {
170                    throw new Exception(Translator::translate('Wystąpił błąd podczas zapisywania rekordu'));
171                }
172
173                $counter++;
174            }
175        } catch (Exception $exception) {
176            $db->rollback();
177            throw $exception;
178        }
179        ErrorHandler::tryEnd();
180
181        if ($progressBar) {
182            $progressBar->setProgress(100);
183        }
184
185        $db->commit();
186
187        return $counter;
188
189    }
190
191
192    private static function validate($k, $data) {
193
194        $value = array_key_exists($k, $data) ? $data[$k] : NULL;
195
196        if ($k == 'segmnt') {
197            if (bs_empty_str($value)) {
198                throw new Exception(Translator::translate('Brak wartości dla pola Numer konta'));
199            }
200        }
201
202        if ($k == 'year__') {
203            if (bs_empty_str($value)) {
204                throw new Exception(Translator::translate('Brak wartości dla pola Rok obrachunkowy'));
205            }
206        }
207
208    }
209
210
211    /**
212     * @param $dbColumnName
213     * @param $value
214     * @param array $options
215     * @return mixed|string
216     * @throws Exception
217     */
218    private static function mapData($dbColumnName, $value, $options = []) {
219
220        $value = trim($value);
221
222        switch ($dbColumnName) {
223            case 'projid':
224                if (!$value) {
225                    if (isset($options['projid'])) {
226                        $value = $options['projid'];
227                    }
228
229                    break;
230                }
231
232                if (isset(self::$cache['projid'][$value])) {
233                    $value = self::$cache['projid'][$value];
234                } else {
235                    if (filter_var($value, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]) !== FALSE) {
236                        $out = PgManager::getInstance()->query('SELECT projid FROM projects WHERE ent_id = '.LoggedUser::getEntityID().' AND is_del IS NOT TRUE AND projid::TEXT = \''.pg_escape_string($value).'\'', FALSE, PGSQL_ASSOC);
237                        if (!isset($out[0]['usr_id'])) {
238                            throw new Exception(sprintf(Translator::translate('Projekt o identyfikatorze %s nie został znaleziony w systemie (może być usunięty)'), htmlspecialchars($value, ENT_QUOTES, 'UTF-8')));
239                        }
240
241                        self::$cache['projid'][$value] = $out[0]['projid'];
242                        $value = self::$cache['projid'][$value];
243                    } else {
244                        // szukam użytkownika systemu
245                        $sqlFilter = '(projnm ~* E\'^'.Strings::sql_regex_prepare($value).'$\' OR dscrpt ~* E\'^'.Strings::sql_regex_prepare($value).'$\' OR number ~* E\'^'.Strings::sql_regex_prepare($value).'$\')';
246                        if (mb_strpos($value, ' ') === FALSE) {
247                            $sqlFilter = 'number ~* E\'^'.Strings::sql_regex_prepare($value).'$\'';
248                        }
249
250                        $out = PgManager::getInstance()->query('SELECT projid FROM projects WHERE ent_id = '.LoggedUser::getEntityID().' AND is_del IS NOT TRUE AND '.$sqlFilter.'', FALSE, PGSQL_ASSOC);
251                        if (!isset($out[0]['projid'])) {
252                            throw new Exception(sprintf(Translator::translate('Projekt o nazwie (lub numerze) %s nie został znaleziony w systemie. <br> Wyczyść komórki zawierające błędną frazę lub wprowadź projekt do systemu.'), htmlspecialchars($value, ENT_QUOTES, 'UTF-8')));
253                        }
254
255                        if (count($out) > 1) {
256                            throw new Exception(sprintf(Translator::translate('Znaleziono więcej niż 1 dopasowań do frazy projekt %s'), htmlspecialchars($value, ENT_QUOTES, 'UTF-8')));
257                        }
258
259                        self::$cache['projid'][$value] = $out[0]['projid'];
260                        $value = self::$cache['projid'][$value];
261                    }
262                }
263
264                if (isset($options['projid']) AND filter_var($options['projid'], FILTER_VALIDATE_INT) AND ($options['projid'] != $value)) {
265                    $out = PgManager::getInstance()->query('SELECT projid, COALESCE(number||\' \'||projnm, projnm) AS projnm FROM projects WHERE projid IN ('.$options['projid'].', '.$value.')', FALSE, PgManager::PGSQL_ASSOC_EX, 0, 'projid');
266                    throw new Exception(sprintf(Translator::translate('Domyślna wartość dla pola Projekt (%s) nie jest ta sama co podana w arkuszu (%s). <br><br> Domyślna wartość została pobrana z panela filtrów. <br><br> Zmień Projekt na panelu filtrów lub w arkuszu.'), '<span class="quotes">'.htmlspecialchars($out[$options['projid']]['projnm'], ENT_QUOTES, 'UTF-8').'</span>', '<span class="quotes">'.htmlspecialchars($out[$value]['projnm'], ENT_QUOTES, 'UTF-8').'</span>'));
267                }
268
269                break;
270
271            case 'year__':
272                if (!$value) {
273                    if (isset($options['year__'])) {
274                        $value = $options['year__'];
275                    }
276
277                    break;
278                }
279
280                if ($value) {
281                    if (!DatingService::isValid($value.'-01-01')) {
282                        throw new Exception(sprintf(Translator::translate('Nieprawidłowa wartość dla pola Rok obrachunkowy %s. Oczekiwana wartość w formacie YYYY.'), htmlspecialchars($value, ENT_QUOTES, 'UTF-8')));
283                    }
284
285                    if (isset($options['year__']) AND filter_var($options['year__'], FILTER_VALIDATE_INT) AND ($options['year__'] != $value)) {
286                        throw new Exception(sprintf(Translator::translate('Domyślna wartość dla pola Rok obrachunkowu (%s) nie jest ta sama co podana w arkuszu (%s). <br><br> Domyślna wartość została pobrana z panela filtrów. <br><br> Zmień Rok obrachunkowy na panelu filtrów lub w arkuszu.'), htmlspecialchars($options['year__'], ENT_QUOTES, 'UTF-8'), htmlspecialchars($value, ENT_QUOTES, 'UTF-8')));
287                    }
288                }
289
290                break;
291
292            case 'acorid':
293                if (!$value) {
294                    if (isset($options['acorid'])) {
295                        $value = $options['acorid'];
296                    }
297
298                    break;
299                }
300        }
301
302        return $value;
303
304    }
305
306}