nhance-enrollment/app/Helpers/ExcelMergeHelper.php

150 lines
5.9 KiB
PHP
Executable File

<?php
namespace App\Helpers;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use Exception;
class ExcelMergeHelper {
/**
* Main merge function with auto-retry
*
* @param array $filePaths Array of file paths with optional sheets to merge.
* @param string $outputPath Path to save the merged Excel file.
* @return string|null Returns output path on success, null on failure.
*/
public static function mergeExcelFiles(array $filePaths, string $outputPath): ?string
{
try {
log_message('debug', 'Attempting merge with original file order');
return self::processFiles($filePaths, $outputPath);
} catch (Exception $e) {
log_message('error', 'First attempt failed: ' . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine());
log_message('debug', 'Retrying with reversed file order');
// Reverse the file order and try again
$reversedFiles = array_reverse($filePaths);
try {
return self::processFiles($reversedFiles, $outputPath);
} catch (Exception $e2) {
log_message('error', 'Both attempts failed. Last error: ' . $e2->getMessage() . ' in ' . $e2->getFile() . ' on line ' . $e2->getLine());
return null;
}
}
}
/**
* Process files to merge spreadsheets
*
* @param array $filePaths
* @param string $outputPath
* @return string
* @throws Exception
*/
private static function processFiles(array $filePaths, string $outputPath): string
{
log_message('debug', 'Starting Excel merge process');
log_message('debug', 'Files to process: ' . json_encode($filePaths));
if (empty($filePaths)) {
throw new Exception("No files provided to merge");
}
// Initialize an empty merged spreadsheet
$mergedSpreadsheet = new Spreadsheet();
$mergedSpreadsheet->removeSheetByIndex(0); // Remove the default empty sheet
// Process the base file
$firstFile = array_shift($filePaths);
self::processSingleFile($firstFile, $mergedSpreadsheet);
// Process remaining files
foreach ($filePaths as $index => $fileInfo) {
self::processSingleFile($fileInfo, $mergedSpreadsheet, $index);
}
// Save the merged file
log_message('debug', "Saving merged file to: {$outputPath}");
$writer = IOFactory::createWriter($mergedSpreadsheet, 'Xlsx');
$writer->setPreCalculateFormulas(false);
$writer->save($outputPath);
// Clean up
$mergedSpreadsheet->disconnectWorksheets();
unset($mergedSpreadsheet);
gc_collect_cycles();
log_message('debug', 'Excel merge process completed successfully');
return $outputPath;
}
/**
* Process a single file to merge its sheets into the merged spreadsheet
*
* @param array $fileInfo
* @param Spreadsheet $mergedSpreadsheet
* @param int|null $index
* @throws Exception
*/
private static function processSingleFile(array $fileInfo, Spreadsheet $mergedSpreadsheet, int $index = null)
{
if (!isset($fileInfo['file_path']) || !file_exists($fileInfo['file_path'])) {
$path = $fileInfo['file_path'] ?? 'undefined';
log_message('error', "File " . ($index ?? 'base') . ": Invalid or missing file path: {$path}");
return;
}
log_message('debug', "Processing file " . ($index ?? 'base') . ": " . $fileInfo['file_path']);
try {
// Load the source spreadsheet
$sourceSpreadsheet = IOFactory::load($fileInfo['file_path']);
// Get all worksheets
$worksheets = $sourceSpreadsheet->getAllSheets();
$totalSheets = count($worksheets);
log_message('debug', "Total sheets in file: " . $totalSheets);
$sheetsToMerge = $fileInfo['sheets'] ?? [];
// Process each worksheet
foreach ($worksheets as $sheetIndex => $worksheet) {
if (empty($sheetsToMerge) || in_array($sheetIndex, $sheetsToMerge)) {
try {
$sheetName = $worksheet->getTitle();
log_message('debug', "Processing sheet: {$sheetName}");
// Generate unique sheet name before cloning
$newName = $sheetName;
$counter = 1;
while (in_array($newName, $mergedSpreadsheet->getSheetNames())) {
$newName = $sheetName . "_" . $counter++;
log_message('debug', "Sheet name already exists. Trying new name: {$newName}");
}
// Clone the worksheet and set the new name
$clonedSheet = clone $worksheet;
$clonedSheet->setTitle($newName);
// Add as external sheet
$mergedSpreadsheet->addExternalSheet($clonedSheet);
log_message('debug', "Successfully added sheet: {$newName}");
} catch (Exception $e) {
log_message('error', "Error processing sheet {$sheetName} as new name {$newName}: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine());
}
}
}
// Clean up source spreadsheet
$sourceSpreadsheet->disconnectWorksheets();
unset($sourceSpreadsheet);
gc_collect_cycles();
} catch (Exception $e) {
log_message('error', "Error processing file {$fileInfo['file_path']}: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine());
}
}
}