webmoney/backend/app/Services/Import/ExcelParser.php

165 lines
5.2 KiB
PHP

<?php
namespace App\Services\Import;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;
class ExcelParser implements FileParserInterface
{
protected static array $supportedExtensions = ['xlsx', 'xls'];
/**
* Parse the Excel file and return all data
*/
public function parse(string $filePath, array $options = []): array
{
$headerRow = $options['header_row'] ?? 0;
$dataStartRow = $options['data_start_row'] ?? 1;
$spreadsheet = IOFactory::load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$data = [];
$headers = [];
foreach ($worksheet->getRowIterator() as $rowIndex => $row) {
$rowData = [];
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$value = $cell->getCalculatedValue();
// Tratar valores de data do Excel
if (\PhpOffice\PhpSpreadsheet\Shared\Date::isDateTime($cell)) {
try {
$dateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
$value = $dateValue->format('d/m/Y');
} catch (\Exception $e) {
// Manter valor original se não conseguir converter
}
}
$rowData[] = $value;
}
// Linha de cabeçalho (1-indexed no PhpSpreadsheet)
if ($rowIndex === $headerRow + 1) {
$headers = $rowData;
continue;
}
// Pular linhas antes dos dados
if ($rowIndex < $dataStartRow + 1) {
continue;
}
// Verificar se a linha não está completamente vazia
$nonEmpty = array_filter($rowData, fn($v) => $v !== null && $v !== '');
if (!empty($nonEmpty)) {
$data[] = $rowData;
}
}
return [
'headers' => $headers,
'data' => $data,
'total_rows' => count($data),
];
}
/**
* Get headers from the Excel file
*/
public function getHeaders(string $filePath, array $options = []): array
{
$headerRow = $options['header_row'] ?? 0;
$spreadsheet = IOFactory::load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$headers = [];
$row = $worksheet->getRowIterator($headerRow + 1, $headerRow + 1)->current();
if ($row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$headers[] = $cell->getCalculatedValue();
}
}
// Remover valores nulos do final
while (!empty($headers) && (end($headers) === null || end($headers) === '')) {
array_pop($headers);
}
return $headers;
}
/**
* Get preview data (first N rows)
*/
public function getPreview(string $filePath, int $rows = 10, array $options = []): array
{
$spreadsheet = IOFactory::load($filePath);
$worksheet = $spreadsheet->getActiveSheet();
$preview = [];
$rowCount = 0;
foreach ($worksheet->getRowIterator() as $row) {
if ($rowCount >= $rows) {
break;
}
$rowData = [];
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(false);
foreach ($cellIterator as $cell) {
$value = $cell->getCalculatedValue();
// Tratar valores de data do Excel
if (\PhpOffice\PhpSpreadsheet\Shared\Date::isDateTime($cell)) {
try {
$dateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value);
$value = $dateValue->format('d/m/Y');
} catch (\Exception $e) {
// Manter valor original
}
}
$rowData[] = $value;
}
// Remover valores nulos do final
while (!empty($rowData) && (end($rowData) === null || end($rowData) === '')) {
array_pop($rowData);
}
$preview[] = [
'row_index' => $rowCount,
'data' => $rowData,
];
$rowCount++;
}
// Contar total de linhas
$totalRows = $worksheet->getHighestRow();
return [
'preview' => $preview,
'total_rows' => $totalRows,
'columns_count' => !empty($preview) ? count($preview[0]['data']) : 0,
];
}
/**
* Check if parser supports the extension
*/
public static function supports(string $extension): bool
{
return in_array(strtolower($extension), self::$supportedExtensions);
}
}