getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine()); // echo "First attempt failed: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine() . "\n"; log_message('debug', 'Retrying with reversed file order'); // echo "Retrying with reversed file order\n"; // 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()); // echo "Both attempts failed. Last error: " . $e2->getMessage() . ' in ' . $e2->getFile() . ' on line ' . $e2->getLine() . "\n"; 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'); // echo "Starting Excel merge process\n"; log_message('debug', 'Files to process: ' . json_encode($filePaths)); // echo "Files to process: " . json_encode($filePaths) . "\n"; 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}"); // echo "Saving merged file to: {$outputPath}\n"; $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'); // echo "Excel merge process completed successfully\n"; 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}"); // echo "File " . ($index ?? 'base') . ": Invalid or missing file path: {$path}\n"; return; } log_message('debug', "Processing file " . ($index ?? 'base') . ": " . $fileInfo['file_path']); // echo "Processing file " . ($index ?? 'base') . ": " . $fileInfo['file_path'] . "\n"; 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); // echo "Total sheets in file: " . $totalSheets . "\n"; $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}"); // echo "Processing sheet: {$sheetName}\n"; // 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}"); // // echo "Sheet name already exists. Trying new name: {$newName}\n"; // } if (in_array($newName, $mergedSpreadsheet->getSheetNames())) { $newName = $sheetName . '_' . $counter++; $worksheet->setTitle($newName); } // Clone the worksheet and set the new name // $clonedSheet = clone $worksheet; // $clonedSheet->setTitle($newName); // Add as external sheet $mergedSpreadsheet->addExternalSheet($worksheet); log_message('debug', "Successfully added sheet: {$newName}"); // echo "Successfully added sheet: {$newName}\n"; } catch (Exception $e) { log_message('error', "Error processing sheet {$sheetName} as new name {$newName}: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine()); // echo "Error processing sheet {$sheetName} as new name {$newName}: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine() . "\n"; } } } // 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()); // echo "Error processing file {$fileInfo['file_path']}: " . $e->getMessage() . ' in ' . $e->getFile() . ' on line ' . $e->getLine() . "\n"; } } }