Files
citrus-cms/app/Services/RegisterCreator/ExcelHandler.php
T
2026-04-28 21:14:25 +03:00

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();
}
}