Release 2.33.0 (#5438)
This commit is contained in:
@@ -12,6 +12,7 @@ namespace App\Export\Base;
|
||||
use App\Entity\ExportableItem;
|
||||
use App\Export\ExportFilename;
|
||||
use App\Export\Package\CellFormatter\DateStringFormatter;
|
||||
use App\Export\Package\CellFormatter\DurationPlainFormatter;
|
||||
use App\Export\Package\SpoutSpreadsheet;
|
||||
use App\Export\RendererInterface;
|
||||
use App\Export\TimesheetExportInterface;
|
||||
@@ -71,6 +72,7 @@ final class CsvRenderer implements RendererInterface, TimesheetExportInterface
|
||||
$spreadsheet->open($filename);
|
||||
|
||||
$this->spreadsheetRenderer->registerFormatter('date', new DateStringFormatter());
|
||||
$this->spreadsheetRenderer->registerFormatter('duration', new DurationPlainFormatter());
|
||||
$this->spreadsheetRenderer->writeSpreadsheet($spreadsheet, $exportItems, $query);
|
||||
|
||||
return new \SplFileInfo($filename);
|
||||
|
||||
@@ -105,7 +105,7 @@ final class SpreadsheetRenderer
|
||||
$formula = null;
|
||||
if (\in_array($column->getName(), $totalColumns)) {
|
||||
$columnName = $columnNames[$totalColumn - 1];
|
||||
$formula = \sprintf('=SUM(%s2:%s%s)', $columnName, $columnName, $currentRow);
|
||||
$formula = \sprintf('=SUBTOTAL(9,%s2:%s%s)', $columnName, $columnName, $currentRow);
|
||||
}
|
||||
$totalRow[] = $formula;
|
||||
$totalColumn++;
|
||||
|
||||
15
src/Export/Package/CellFormatter/CellWithFormatInterface.php
Normal file
15
src/Export/Package/CellFormatter/CellWithFormatInterface.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
interface CellWithFormatInterface
|
||||
{
|
||||
public function getFormat(): string;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
final class DateFormatter implements CellFormatterInterface
|
||||
final class DateFormatter implements CellFormatterInterface, CellWithFormatInterface
|
||||
{
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
@@ -23,4 +23,9 @@ final class DateFormatter implements CellFormatterInterface
|
||||
|
||||
throw new \InvalidArgumentException('Only DateTimeInterface can be formatted');
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return 'yyyy-mm-dd';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,23 +9,34 @@
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
use App\Utils\Duration;
|
||||
|
||||
final class DurationFormatter implements CellFormatterInterface
|
||||
final class DurationFormatter implements CellFormatterInterface, CellWithFormatInterface
|
||||
{
|
||||
private Duration $duration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->duration = new Duration();
|
||||
}
|
||||
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
return $this->duration->format((int) $value);
|
||||
if (!is_numeric($value) || (int) $value === 0) {
|
||||
return new \DateInterval('PT0S');
|
||||
}
|
||||
|
||||
return $this->duration->format(0);
|
||||
$value = (int) $value;
|
||||
|
||||
$seconds = abs($value);
|
||||
$hours = intdiv($seconds, 3600);
|
||||
$seconds %= 3600;
|
||||
$minutes = intdiv($seconds, 60);
|
||||
$seconds %= 60;
|
||||
|
||||
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
|
||||
$interval = new \DateInterval($intervalSpec);
|
||||
|
||||
if ($value < 0) {
|
||||
$interval->invert = 1;
|
||||
}
|
||||
|
||||
return $interval;
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return '[hh]:mm:ss';
|
||||
}
|
||||
}
|
||||
|
||||
37
src/Export/Package/CellFormatter/DurationPlainFormatter.php
Normal file
37
src/Export/Package/CellFormatter/DurationPlainFormatter.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
final class DurationPlainFormatter implements CellFormatterInterface
|
||||
{
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_numeric($value) || (int) $value === 0) {
|
||||
return '0:00:00';
|
||||
}
|
||||
|
||||
$value = (int) $value;
|
||||
|
||||
$seconds = abs($value);
|
||||
$hours = intdiv($seconds, 3600);
|
||||
$seconds %= 3600;
|
||||
$minutes = intdiv($seconds, 60);
|
||||
$seconds %= 60;
|
||||
|
||||
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
|
||||
$interval = new \DateInterval($intervalSpec);
|
||||
|
||||
if ($value < 0) {
|
||||
$interval->invert = 1;
|
||||
}
|
||||
|
||||
return $interval->format('%r%h:%I:%S');
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ namespace App\Export\Package;
|
||||
|
||||
use App\Entity\ExportableItem;
|
||||
use App\Export\Package\CellFormatter\CellFormatterInterface;
|
||||
use App\Export\Package\CellFormatter\CellWithFormatInterface;
|
||||
|
||||
class Column
|
||||
{
|
||||
@@ -71,4 +72,13 @@ class Column
|
||||
{
|
||||
return $this->header ?? $this->name;
|
||||
}
|
||||
|
||||
public function getFormat(): ?string
|
||||
{
|
||||
if ($this->formatter instanceof CellWithFormatInterface) {
|
||||
return $this->formatter->getFormat();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
{
|
||||
private Style $dateStyle;
|
||||
/** @var array<int, Style|null> */
|
||||
private array $styles = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly WriterInterface $writer,
|
||||
@@ -34,7 +35,6 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
)
|
||||
{
|
||||
$this->writer->setCreator(Constants::SOFTWARE);
|
||||
$this->dateStyle = (new Style())->setFormat('yyyy-mm-dd');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,9 +48,15 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
}
|
||||
|
||||
$tmp = [];
|
||||
$i = 0;
|
||||
foreach ($columns as $column) {
|
||||
$title = $this->translator->trans($column->getHeader());
|
||||
$tmp[] = Cell::fromValue($title);
|
||||
$style = null;
|
||||
if ($column->getFormat() !== null) {
|
||||
$style = (new Style())->setFormat($column->getFormat());
|
||||
}
|
||||
$this->styles[$i++] = $style;
|
||||
}
|
||||
|
||||
$style = new Style();
|
||||
@@ -100,12 +106,9 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
}
|
||||
|
||||
$tmp = [];
|
||||
$i = 0;
|
||||
foreach ($columns as $column) {
|
||||
if ($column instanceof \DateTimeInterface) {
|
||||
$tmp[] = Cell::fromValue($column, $this->dateStyle);
|
||||
} else {
|
||||
$tmp[] = Cell::fromValue($column); // @phpstan-ignore argument.type
|
||||
}
|
||||
$tmp[] = Cell::fromValue($column, $this->styles[$i++]); // @phpstan-ignore argument.type
|
||||
}
|
||||
|
||||
$this->writer->addRow(new Row($tmp, $style));
|
||||
|
||||
Reference in New Issue
Block a user