PHPExcel больше не поддерживается, переходите на PhpOffice\PhpSpreadsheet
<?php
namespace Enso;
use PhpOffice\PhpSpreadsheet;
use InvalidArgumentException;
use DateTimeImmutable;
/**
* Класс для работы с xlsx файлами.
*/
class XlsxFile
{
private $dataDir;
private $path;
private $placeholders;
private $spreadsheet;
public function __construct(string $path)
{
$this->dataDir = realpath(__DIR__ . '/../data') . DIRECTORY_SEPARATOR;
$this->path = realpath($path);
// Загружает метки ячеек
$cacheFile = $this->dataDir . 'cache.json';
if (file_exists($cacheFile)) {
$this->placeholders = json_decode(file_get_contents($cacheFile), true);
} else {
$this->placeholders = $this->extractPlaceholders();
file_put_contents($cacheFile, json_encode($this->placeholders));
}
PhpSpreadsheet\Calculation\Functions::setReturnDateType(
PhpSpreadsheet\Calculation\Functions::RETURNDATE_PHP_OBJECT
);
// Загружает заполненный xlsx файл
$reader = new PhpSpreadsheet\Reader\Xlsx();
$reader->setReadDataOnly(false);
$reader->setReadEmptyCells(true);
$this->spreadsheet = $reader->load($this->path);
}
/**
* Извлекает метки ячеек из пустой xlsx файла.
*/
private function extractPlaceholders(): array
{
$blankFile = $this->dataDir . 'dummy.xlsx';
$reader = new PhpSpreadsheet\Reader\Xlsx();
$reader->setReadDataOnly(true);
$reader->setReadEmptyCells(false);
$spreadsheet = $reader->load($blankFile);
unset($reader);
$placeholders = [];
foreach ($spreadsheet->getAllSheets() as $sheetId => $sheet) {
foreach ($sheet->getRowIterator() as $row) {
$cells = $row->getCellIterator();
$cells->setIterateOnlyExistingCells(true);
foreach ($cells as $cell) {
$value = trim($cell->getValue());
if ($value[0] === '{' && $value[-1] === '}') {
$key = substr($value, 1, -1);
$placeholders[$key] = ['sheet' => $sheetId, 'cell' => $cell->getCoordinate()];
}
}
}
}
return $placeholders;
}
/**
* Проверяет наличие метки в шаблоне.
*/
public function hasPlaceholder(string $placeholder): bool
{
return isset($this->placeholders[$placeholder]);
}
/**
* Возвращает ячейку по её метке.
*/
public function getCell(string $placeholder)
{
if (!$this->hasPlaceholder($placeholder)) {
throw new InvalidArgumentException(
'Метка {' . $placeholder . '} не задана в файле ' . $this->dataDir . 'dummy.xlsx'
);
}
return $this->spreadsheet
->getSheet($this->placeholders[$placeholder]['sheet'])
->getCell($this->placeholders[$placeholder]['cell']);
}
/**
* Возвращает значение ячейки по её метке.
*/
public function getCellValue(string $placeholder)
{
return $this->getCell($placeholder)->getValue();
}
/**
* Задает значение ячейки по её метке.
*/
public function setCellValue(string $placeholder, $value)
{
if (is_bool($value)) {
$value = $value ? 'да' : 'нет';
} elseif (is_string($value)) {
$value = trim($value);
}
$this->getCell($placeholder)->setValue($value);
}
/**
* Задает значения ячеек колонки по её метке. Метка ставится в первую ячейку колонки.
*/
public function setColumnCellValues(string $placeholder, array $values)
{
$cell = $this->getCell($placeholder);
$cell->getWorksheet()->fromArray(array_chunk($values, 1), null, $cell->getCoordinate());
}
/**
* Задает значения ячеек колонок по их меткам.
*/
public function setColumnsCellValues(string $placeholderPrefix, array $values)
{
$keys = array_keys(current($values));
foreach ($keys as $key) {
$placeholder = $placeholderPrefix . $key;
if ($this->hasPlaceholder($placeholder)) {
$colValues = array_column($values, $key);
$this->setColumnCellValues($placeholder, $colValues);
}
}
}
/**
* Перезаписывает файл.
*/
public function save()
{
$writer = new PhpSpreadsheet\Writer\Xlsx($this->spreadsheet);
$writer->save($this->path);
}
}