Release 2.0.2 (#3856)

* allow to overwrite global spreadsheet styles
* bump version
* fix deprecations in vcard download
* bump composer packages
* added help page for all registered locales
* fix menu id's, cleanup times route, fix configurable homepage redirect
* format duration without leading zero in hours (unify javascript with php behavior)
* fix active records in all screen sizes
* improved responsiveness in XS
* fixed invoice number for customer null fields
* fix javascript respects multiple recent-activity dropdowns
* show recent activities on small screens
* fix user-profile layout column in XS
* fix search is always marked as active
This commit is contained in:
Kevin Papst
2023-02-21 19:21:49 +01:00
committed by GitHub
parent e474087257
commit 25469113fd
61 changed files with 821 additions and 580 deletions

View File

@@ -23,6 +23,7 @@ use App\Repository\Query\TimesheetQuery;
use App\Twig\LocaleFormatExtensions;
use App\Utils\StringHelper;
use DateTime;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@@ -37,7 +38,7 @@ use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
* @internal means no BC promise whatsoever!
*/
abstract class AbstractSpreadsheetRenderer
{
@@ -50,12 +51,17 @@ abstract class AbstractSpreadsheetRenderer
// Part 1 = positive; Part 2 = negative; Part 3 = zero; Part 4 = Text
public const RATE_FORMAT_DEFAULT = '#.##0,00 [$%1$s];-#.##0,00 [$%1$s]';
public const RATE_FORMAT_LEFT = '_("%1$s"* #,##0.00_);_("%1$s"* -#,##0.00;_("%1$s"* "-"??_);_(@_)';
public const RATE_FORMAT = self::RATE_FORMAT_LEFT;
public const RATE_FORMAT_RIGHT = '_(* "%1$s" #,##0.00_);_(* "%1$s" -#,##0.00;_(* "%1$s" "-"??_);_(@_)';
/**
* @internal used in html to excel exporter
*/
public const RATE_FORMAT_NO_CURRENCY = '#,##0.00;-#,##0.00';
/**
* @see self:RATE_FORMAT_*
*/
protected string $rateFormat = self::RATE_FORMAT_LEFT;
protected string $durationFormat = self::DURATION_FORMAT;
protected int $durationBase = 86400;
/**
@@ -117,10 +123,10 @@ abstract class AbstractSpreadsheetRenderer
return $this->voter->isGranted('view_rate_other_timesheet');
}
protected function setFormattedDateTime(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedDateTime(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -128,20 +134,20 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
// TODO why is that format hardcoded and does not depend on the users locale?
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::DATETIME_FORMAT);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::DATETIME_FORMAT);
}
protected function setFormattedTime(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedTime(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -149,19 +155,19 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
}
protected function setFormattedDate(Worksheet $sheet, $column, $row, ?DateTime $date): void
protected function setFormattedDate(Worksheet $sheet, int $column, int $row, ?DateTime $date): void
{
if (null === $date) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -169,48 +175,48 @@ abstract class AbstractSpreadsheetRenderer
$excelDate = Date::PHPToExcel($date);
if ($excelDate === false) {
$sheet->setCellValueByColumnAndRow($column, $row, $date);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $date);
return;
}
$sheet->setCellValueByColumnAndRow($column, $row, $excelDate);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $excelDate);
// TODO why is that format hardcoded and does not depend on the users locale?
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
}
protected function setDurationTotal(Worksheet $sheet, $column, $row, $startCoordinate, $endCoordinate): void
protected function setDurationTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$style = $sheet->getStyleByColumnAndRow($column, $row);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($column, $row));
$style->getNumberFormat()->setFormatCode($this->durationFormat);
}
protected function setDuration(Worksheet $sheet, $column, $row, $duration): void
protected function setDuration(Worksheet $sheet, int $column, int $row, ?int $duration): void
{
if (null === $duration) {
$duration = 0;
}
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode($this->durationFormat);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode($this->durationFormat);
}
protected function setRateTotal(Worksheet $sheet, $column, $row, $startCoordinate, $endCoordinate): void
protected function setRateTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
}
protected function setRateStyle(Worksheet $sheet, $column, $row, $rate, $currency): void
protected function setRateStyle(Worksheet $sheet, int $column, int $row, ?string $currency): void
{
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(
sprintf(self::RATE_FORMAT_LEFT, $currency)
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(
sprintf($this->rateFormat, $currency ?? '')
);
}
protected function setRate(Worksheet $sheet, $column, $row, $rate, $currency): void
protected function setRate(Worksheet $sheet, int $column, int $row, ?float $rate, ?string $currency): void
{
$sheet->setCellValueByColumnAndRow($column, $row, $rate);
$this->setRateStyle($sheet, $column, $row, $rate, $currency);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $rate ?? 0);
$this->setRateStyle($sheet, $column, $row, $currency);
}
/**
@@ -227,8 +233,8 @@ abstract class AbstractSpreadsheetRenderer
/**
* @param ExportableItem[] $exportItems
* @param TimesheetQuery $query
* @param array $columns
* @return array
* @param array<string, array<string, callable|int|float|false|null>> $columns
* @return array<string, array<string, callable|int|float|false|null>>
*/
protected function getColumns(array $exportItems, TimesheetQuery $query, array $columns): array
{
@@ -289,7 +295,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getUser()) {
$user = $entity->getUser()->getDisplayName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $user);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $user);
};
}
@@ -300,12 +306,12 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getUser()) {
$username = $entity->getUser()->getUserIdentifier();
}
$sheet->setCellValueByColumnAndRow($column, $row, $username);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $username);
};
}
if (!isset($columns['username']['header'])) {
$columns['username']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('name'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('name'));
return 1;
};
@@ -318,7 +324,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customer = $entity->getProject()->getCustomer()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customer);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customer);
};
}
@@ -328,7 +334,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$project = $entity->getProject()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $project);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $project);
};
}
@@ -338,7 +344,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getActivity()) {
$activity = $entity->getActivity()->getName();
}
$sheet->setCellValueByColumnAndRow($column, $row, $activity);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $activity);
};
}
@@ -352,7 +358,7 @@ abstract class AbstractSpreadsheetRenderer
$isColumnFormatted = false;
$columns['description']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) use (&$isColumnFormatted, $maxWidth, $wrapText, $sanitizeText) {
$cell = $sheet->getCellByColumnAndRow($column, $row);
$cell = $sheet->getCell(CellAddress::fromColumnAndRow($column, $row));
$desc = $entity->getDescription();
if ($sanitizeText && null !== $desc) {
@@ -379,20 +385,20 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['exported']) && !isset($columns['exported']['render'])) {
$columns['exported']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$exported = $entity->isExported() ? 'yes' : 'no';
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans($exported));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans($exported));
};
}
if (isset($columns['billable']) && !isset($columns['billable']['render'])) {
$columns['billable']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$exported = $entity->isBillable() ? 'yes' : 'no';
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans($exported));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans($exported));
};
}
if (isset($columns['tags']) && !isset($columns['tags']['render'])) {
$columns['tags']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, implode(',', $entity->getTagsAsArray()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), implode(',', $entity->getTagsAsArray()));
};
}
@@ -422,7 +428,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['timesheet-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($timesheetMetaFields): int {
foreach ($timesheetMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($timesheetMetaFields);
@@ -434,7 +440,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $metaField) {
$metaFieldValue = $metaField->getValue();
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($timesheetMetaFields);
@@ -450,7 +456,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['customer-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($customerMetaFields): int {
foreach ($customerMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($customerMetaFields);
@@ -464,7 +470,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($customerMetaFields);
@@ -477,7 +483,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['project-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($projectMetaFields): int {
foreach ($projectMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($projectMetaFields);
@@ -491,7 +497,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($projectMetaFields);
@@ -504,7 +510,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['activity-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($activityMetaFields): int {
foreach ($activityMetaFields as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($activityMetaFields);
@@ -518,7 +524,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($activityMetaFields);
@@ -533,7 +539,7 @@ abstract class AbstractSpreadsheetRenderer
$columns['user-meta'] = [
'header' => function (Worksheet $sheet, $row, $column) use ($userPreferences): int {
foreach ($userPreferences as $metaField) {
$sheet->setCellValueByColumnAndRow($column++, $row, $this->translator->trans($metaField->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $this->translator->trans($metaField->getLabel()));
}
return \count($userPreferences);
@@ -547,7 +553,7 @@ abstract class AbstractSpreadsheetRenderer
$metaFieldValue = $metaField->getValue();
}
}
$sheet->setCellValueByColumnAndRow($column++, $row, $metaFieldValue);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column++, $row), $metaFieldValue);
}
return \count($userPreferences);
@@ -557,20 +563,20 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['type']) && !isset($columns['type']['render'])) {
$columns['type']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, $entity->getType());
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $entity->getType());
};
}
if (isset($columns['category']) && !isset($columns['category']['render'])) {
$columns['category']['render'] = function (Worksheet $sheet, int $row, int $column, ExportableItem $entity) {
$sheet->setCellValueByColumnAndRow($column, $row, $entity->getCategory());
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $entity->getCategory());
};
}
if (isset($columns['customer_number'])) {
if (!isset($columns['customer_number']['header'])) {
$columns['customer_number']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('number'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('number'));
return 1;
};
@@ -582,7 +588,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customerId = $entity->getProject()->getCustomer()->getNumber();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customerId);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customerId);
};
}
}
@@ -590,7 +596,7 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['customer_vat']) && !isset($columns['customer_vat']['render'])) {
if (!isset($columns['customer_vat']['header'])) {
$columns['customer_vat']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('vat_id'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('vat_id'));
return 1;
};
@@ -602,7 +608,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$customerVat = $entity->getProject()->getCustomer()->getVatId();
}
$sheet->setCellValueByColumnAndRow($column, $row, $customerVat);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $customerVat);
};
}
}
@@ -610,7 +616,7 @@ abstract class AbstractSpreadsheetRenderer
if (isset($columns['order_number']) && !isset($columns['order_number']['render'])) {
if (!isset($columns['order_number']['header'])) {
$columns['order_number']['header'] = function (Worksheet $sheet, $row, $column): int {
$sheet->setCellValueByColumnAndRow($column, $row, $this->translator->trans('orderNumber'));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $this->translator->trans('orderNumber'));
return 1;
};
@@ -622,7 +628,7 @@ abstract class AbstractSpreadsheetRenderer
if (null !== $entity->getProject()) {
$orderNumber = $entity->getProject()->getOrderNumber();
}
$sheet->setCellValueByColumnAndRow($column, $row, $orderNumber);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $orderNumber);
};
}
}
@@ -663,10 +669,13 @@ abstract class AbstractSpreadsheetRenderer
foreach ($columns as $label => $settings) {
if (isset($settings['header'])) {
if (!\is_callable($settings['header'])) {
throw new \RuntimeException('Invalid header renderer given for: ' . $label);
}
$amount = $settings['header']($sheet, $recordsHeaderRow, $recordsHeaderColumn);
$recordsHeaderColumn += $amount;
} else {
$sheet->setCellValueByColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow, $this->translator->trans($label));
$sheet->setCellValue(CellAddress::fromColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow), $this->translator->trans($label));
}
}
@@ -689,11 +698,11 @@ abstract class AbstractSpreadsheetRenderer
}
if (!\array_key_exists('render', $settings) || !\is_callable($settings['render'])) {
throw new \RuntimeException(sprintf('Missing renderer for export column %s', $label));
throw new \RuntimeException(sprintf('Missing or invalid renderer for export column %s', $label));
}
$amount = $settings['render']($sheet, $entryHeaderRow, $entryHeaderColumn, $exportItem);
$entryHeaderColumn += (null === $amount) ? 1 : $amount;
$entryHeaderColumn += (null === $amount) ? 1 : (int) $amount;
}
$entryHeaderRow++;
@@ -701,28 +710,28 @@ abstract class AbstractSpreadsheetRenderer
if ($this->isTotalRowSupported()) {
if (null !== $durationColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($durationColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($durationColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($durationColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($durationColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setDurationTotal($sheet, $durationColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($durationColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($durationColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}
if (null !== $rateColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($rateColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($rateColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($rateColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($rateColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setRateTotal($sheet, $rateColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($rateColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($rateColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}
if (null !== $internalRateColumn) {
$startCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, 2)->getCoordinate();
$endCoordinate = $sheet->getCellByColumnAndRow($internalRateColumn, $entryHeaderRow - 1)->getCoordinate();
$startCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($internalRateColumn, 2))->getCoordinate();
$endCoordinate = $sheet->getCell(CellAddress::fromColumnAndRow($internalRateColumn, $entryHeaderRow - 1))->getCoordinate();
$this->setRateTotal($sheet, $internalRateColumn, $entryHeaderRow, $startCoordinate, $endCoordinate);
$style = $sheet->getStyleByColumnAndRow($internalRateColumn, $entryHeaderRow);
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($internalRateColumn, $entryHeaderRow));
$style->getBorders()->getTop()->setBorderStyle(Border::BORDER_THIN);
$style->getFont()->setBold(true);
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Base;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
@@ -54,16 +55,17 @@ class CsvRenderer extends AbstractSpreadsheetRenderer
return 'csv';
}
protected function setDuration(Worksheet $sheet, $column, $row, $duration): void
protected function setDuration(Worksheet $sheet, int $column, int $row, ?int $duration): void
{
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=%s', $duration));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s', $duration ?? 0));
}
protected function setRateStyle(Worksheet $sheet, $column, $row, $rate, $currency): void
protected function setRate(Worksheet $sheet, int $column, int $row, ?float $rate, ?string $currency): void
{
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $rate);
if ($rate === 0.00) {
return;
}
parent::setRateStyle($sheet, $column, $row, $rate, $currency);
$this->setRateStyle($sheet, $column, $row, $currency);
}
}

View File

@@ -45,6 +45,16 @@ class XlsxRenderer extends AbstractSpreadsheetRenderer
throw new \Exception('Could not open temporary file');
}
$this->applyStyles($spreadsheet);
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save($filename);
return $filename;
}
protected function applyStyles(Spreadsheet $spreadsheet): void
{
// Store expensive calculations for later
$sheet = $spreadsheet->getActiveSheet();
$highestRow = $sheet->getHighestRow();
@@ -75,11 +85,6 @@ class XlsxRenderer extends AbstractSpreadsheetRenderer
->getAlignment()
->setVertical(Alignment::VERTICAL_TOP)
->setHorizontal(Alignment::HORIZONTAL_LEFT);
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->save($filename);
return $filename;
}
public function getId(): string

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
final class ArrayFormatter implements CellFormatterInterface
@@ -16,7 +17,7 @@ final class ArrayFormatter implements CellFormatterInterface
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -25,6 +26,6 @@ final class ArrayFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only array is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, implode(';', $value));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), implode(';', $value));
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
final class BooleanFormatter implements CellFormatterInterface
@@ -16,7 +17,7 @@ final class BooleanFormatter implements CellFormatterInterface
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -25,6 +26,6 @@ final class BooleanFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only boolean is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, $value);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), $value);
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
@@ -18,7 +19,7 @@ final class DateFormatter implements CellFormatterInterface
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -27,7 +28,7 @@ final class DateFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only DateTime is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, Date::PHPToExcel($value));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), Date::PHPToExcel($value));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_DATE_YYYYMMDD2);
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
@@ -19,7 +20,7 @@ final class DateTimeFormatter implements CellFormatterInterface
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -28,7 +29,7 @@ final class DateTimeFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only DateTime is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, Date::PHPToExcel($value));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), Date::PHPToExcel($value));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::DATETIME_FORMAT);
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
final class DurationFormatter implements CellFormatterInterface
@@ -25,7 +26,7 @@ final class DurationFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only int is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, sprintf('=%s/86400', $value));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::DURATION_FORMAT);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s/86400', $value));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::DURATION_FORMAT);
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Export\Spreadsheet\CellFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
@@ -19,7 +20,7 @@ final class TimeFormatter implements CellFormatterInterface
public function setFormattedValue(Worksheet $sheet, int $column, int $row, $value): void
{
if (null === $value) {
$sheet->setCellValueByColumnAndRow($column, $row, '');
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), '');
return;
}
@@ -28,7 +29,7 @@ final class TimeFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only DateTime is supported');
}
$sheet->setCellValueByColumnAndRow($column, $row, Date::PHPToExcel($value));
$sheet->getStyleByColumnAndRow($column, $row)->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), Date::PHPToExcel($value));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::TIME_FORMAT);
}
}

View File

@@ -16,6 +16,7 @@ use App\Export\Spreadsheet\CellFormatter\DateFormatter;
use App\Export\Spreadsheet\CellFormatter\DateTimeFormatter;
use App\Export\Spreadsheet\CellFormatter\DurationFormatter;
use App\Export\Spreadsheet\CellFormatter\TimeFormatter;
use PhpOffice\PhpSpreadsheet\Cell\CellAddress;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -65,7 +66,7 @@ class SpreadsheetExporter
$recordsHeaderRow = 1;
foreach ($columns as $settings) {
$sheet->setCellValueByColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow, $this->translator->trans($settings->getLabel()));
$sheet->setCellValue(CellAddress::fromColumnAndRow($recordsHeaderColumn++, $recordsHeaderRow), $this->translator->trans($settings->getLabel()));
}
$entryHeaderRow = $recordsHeaderRow + 1;
@@ -77,7 +78,7 @@ class SpreadsheetExporter
$value = \call_user_func($settings->getAccessor(), $entry);
if (!\array_key_exists($settings->getType(), $this->formatter)) {
$sheet->setCellValueByColumnAndRow($entryHeaderColumn, $entryHeaderRow, $value);
$sheet->setCellValue(CellAddress::fromColumnAndRow($entryHeaderColumn, $entryHeaderRow), $value);
} else {
$formatter = $this->formatter[$settings->getType()];
$formatter->setFormattedValue($sheet, $entryHeaderColumn, $entryHeaderRow, $value);