201 lines
5.8 KiB
PHP
201 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Services\RegisterCreator;
|
|
|
|
use PhpOffice\PhpSpreadsheet\IOFactory;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Exception;
|
|
|
|
class ExcelHandler
|
|
{
|
|
private Spreadsheet $spreadsheet;
|
|
private Worksheet $sheet;
|
|
private string $templatePath;
|
|
|
|
/**
|
|
* Load Excel template
|
|
*/
|
|
public function loadTemplate(string $templatePath): self
|
|
{
|
|
$this->templatePath = $templatePath;
|
|
$fullPath = storage_path('documents/' . $templatePath);
|
|
|
|
if (!file_exists($fullPath)) {
|
|
throw new Exception("Excel template not found: {$fullPath}");
|
|
}
|
|
|
|
Log::debug('Loading Excel template', ['path' => $fullPath]);
|
|
|
|
$this->spreadsheet = IOFactory::load($fullPath);
|
|
$this->sheet = $this->spreadsheet->getActiveSheet();
|
|
|
|
Log::debug('Excel template loaded', [
|
|
'type' => get_class($this->spreadsheet),
|
|
'sheet_name' => $this->sheet->getTitle()
|
|
]);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get spreadsheet instance
|
|
*/
|
|
public function getSpreadsheet(): Spreadsheet
|
|
{
|
|
return $this->spreadsheet;
|
|
}
|
|
|
|
/**
|
|
* Get active sheet
|
|
*/
|
|
public function getSheet(): Worksheet
|
|
{
|
|
return $this->sheet;
|
|
}
|
|
|
|
/**
|
|
* Replace placeholders in Excel sheet
|
|
*/
|
|
public function replacePlaceholders(array $replacements): self
|
|
{
|
|
Log::debug('Replacing placeholders in Excel', [
|
|
'count' => count($replacements)
|
|
]);
|
|
|
|
foreach ($this->sheet->getRowIterator() as $row) {
|
|
foreach ($row->getCellIterator() as $cell) {
|
|
$cellValue = $cell->getValue();
|
|
|
|
// Handle RichText objects
|
|
if ($cellValue instanceof \PhpOffice\PhpSpreadsheet\RichText\RichText) {
|
|
$cellValue = $cellValue->getPlainText();
|
|
}
|
|
|
|
// Convert to string for processing
|
|
$cellValueStr = (string)$cellValue;
|
|
|
|
if (!empty($cellValueStr)) {
|
|
$originalValue = $cellValueStr;
|
|
|
|
foreach ($replacements as $placeholder => $replacement) {
|
|
if (strpos($cellValueStr, $placeholder) !== false) {
|
|
$cellValueStr = str_replace($placeholder, $replacement, $cellValueStr);
|
|
}
|
|
}
|
|
|
|
// Only update if value changed
|
|
if ($cellValueStr !== $originalValue) {
|
|
$cell->setValue($cellValueStr);
|
|
|
|
Log::debug('Placeholder replaced', [
|
|
'cell' => $cell->getCoordinate(),
|
|
'original' => $originalValue,
|
|
'new' => $cellValueStr
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Save Excel file
|
|
*/
|
|
public function save(string $outputPath, bool $override = true): string
|
|
{
|
|
$fullPath = storage_path('documents/' . $outputPath);
|
|
|
|
// Create directory if not exists
|
|
$directory = dirname($fullPath);
|
|
if (!file_exists($directory)) {
|
|
mkdir($directory, 0777, true);
|
|
Log::debug('Created directory', ['path' => $directory]);
|
|
}
|
|
|
|
// Check override setting
|
|
if (!$override && file_exists($fullPath)) {
|
|
$fullPath = $this->generateUniqueFilename($fullPath);
|
|
$outputPath = str_replace(storage_path('documents/'), '', $fullPath);
|
|
Log::debug('File exists and override is false, using unique name', [
|
|
'path' => $fullPath
|
|
]);
|
|
}
|
|
|
|
// Check write permissions
|
|
if (!is_writable($directory)) {
|
|
throw new Exception("Directory is not writable: {$directory}");
|
|
}
|
|
|
|
Log::debug('Saving Excel file', [
|
|
'path' => $fullPath,
|
|
'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . ' MB'
|
|
]);
|
|
|
|
$writer = IOFactory::createWriter($this->spreadsheet, 'Xlsx');
|
|
$writer->save($fullPath);
|
|
|
|
Log::debug('Excel file saved successfully', [
|
|
'size' => filesize($fullPath) . ' bytes'
|
|
]);
|
|
|
|
return $outputPath;
|
|
}
|
|
|
|
/**
|
|
* Remove template row from sheet
|
|
*/
|
|
public function removeTemplateRow(int $templateRow): self
|
|
{
|
|
$this->sheet->removeRow($templateRow);
|
|
Log::debug('Template row removed', ['row' => $templateRow]);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Generate unique filename if file exists
|
|
*/
|
|
private function generateUniqueFilename(string $filePath): string
|
|
{
|
|
$counter = 1;
|
|
$pathInfo = pathinfo($filePath);
|
|
|
|
do {
|
|
$newFileName = $pathInfo['dirname'] . '/' .
|
|
$pathInfo['filename'] . '_' . $counter . '.' .
|
|
$pathInfo['extension'];
|
|
$counter++;
|
|
} while (file_exists($newFileName));
|
|
|
|
return $newFileName;
|
|
}
|
|
|
|
/**
|
|
* Cleanup resources
|
|
*/
|
|
public function cleanup(): void
|
|
{
|
|
if (isset($this->spreadsheet)) {
|
|
$this->spreadsheet->disconnectWorksheets();
|
|
unset($this->spreadsheet);
|
|
gc_collect_cycles();
|
|
|
|
Log::debug('Excel resources cleaned up');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
public function __destruct()
|
|
{
|
|
$this->cleanup();
|
|
}
|
|
}
|
|
|
|
|