fix php 8.1 deprecations (#3648)

* show session maxlifetime in doctor
* rephrase compatibility in release notes
* bump version
This commit is contained in:
Kevin Papst
2022-11-24 13:12:18 +01:00
committed by GitHub
parent 2aa5eccc7c
commit 94a6b99c57
20 changed files with 125 additions and 57 deletions

View File

@@ -36,8 +36,11 @@ template: |
[Upgrade Kimai](https://www.kimai.org/documentation/updates.html) - [Install Kimai](https://www.kimai.org/documentation/installation.html) - [Docker](https://tobybatch.github.io/kimai2/)
**PHP Version compatibility:**
- PHP 7.3 is [end-of-life](https://www.php.net/supported-versions.php): please update now
- PHP 7.4 is almost EOL, PHP 8 and PHP 8.1 are supported
- PHP 7.3 is [end-of-life](https://www.php.net/supported-versions.php)
- PHP 7.4 is [end-of-life](https://www.php.net/supported-versions.php) in a few days!
- PHP 8.0 and PHP 8.1 are supported
**Next release will be PHP 8 ONLY, as [announced one year ago](https://www.kimai.org/blog/2021/sunsetting-php-7/).**
$CHANGES

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '1.29.0';
public const VERSION = '1.29.1';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 12900;
public const VERSION_ID = 12901;
/**
* The current release status, either "stable" or "dev"
*/

View File

@@ -268,6 +268,7 @@ class DoctorController extends AbstractController
'post_max_size',
'sys_temp_dir',
'date.timezone',
'session.gc_maxlifetime',
];
$settings = [];

View File

@@ -35,7 +35,12 @@ final class InvoiceDocument
public function getFilename(): string
{
return $this->file->getRealPath();
$path = $this->file->getRealPath();
if ($path === false) {
throw new \Exception('Invoice template got deleted from filesystem');
}
return $path;
}
public function getFileExtension(): string
@@ -45,6 +50,11 @@ final class InvoiceDocument
public function getLastChange(): int
{
return $this->file->getMTime();
$modified = $this->file->getMTime();
if ($modified === false) {
throw new \Exception('Invoice template got deleted from filesystem');
}
return $modified;
}
}

View File

@@ -53,7 +53,8 @@ class RedirectToLocaleSubscriber implements EventSubscriberInterface
// Ignore requests from referrers with the same HTTP host in order to prevent
// changing language for users who possibly already selected it for this application.
if (0 === stripos($request->headers->get('referer'), $request->getSchemeAndHttpHost())) {
$referer = $request->headers->get('referer');
if ($referer !== null && 0 === stripos($referer, $request->getSchemeAndHttpHost())) {
return;
}

View File

@@ -68,6 +68,9 @@ abstract class AbstractSpreadsheetRenderer extends AbstractRenderer
foreach ($row->getCellIterator() as $cell) {
$value = $cell->getValue();
$replacer = null;
if ($value === null) {
continue;
}
$firstReplacerPos = stripos($value, '${');
if ($firstReplacerPos === false) {
continue;
@@ -134,7 +137,7 @@ abstract class AbstractSpreadsheetRenderer extends AbstractRenderer
$cellCounter = 0;
foreach ($row->getCellIterator() as $cell) {
$value = $cell->getValue();
if (stripos($value, '${entry.') !== false) {
if ($value !== null && stripos($value, '${entry.') !== false) {
$startRow = $row->getRowIndex();
$worksheet->insertNewRowBefore($startRow + 1, $invoiceItemCount - 1);
break 2;

View File

@@ -11,6 +11,7 @@ namespace App\Invoice;
use App\Configuration\LanguageFormattings;
use App\Constants;
use App\Entity\Customer;
use App\Entity\Invoice;
use App\Entity\InvoiceDocument;
use App\Event\InvoiceCreatedEvent;
@@ -580,7 +581,22 @@ final class ServiceInvoice
}
uasort($customerEntries, function ($a, $b) {
return strcmp($a['customer']->getName(), $b['customer']->getName());
$customerA = $a['customer'] ?? null;
$customerB = $b['customer'] ?? null;
$nameA = ($customerA instanceof Customer) ? $customerA->getName() : null;
$nameB = ($customerB instanceof Customer) ? $customerB->getName() : null;
if ($nameA === null && $nameB === null) {
$result = 0;
} elseif ($nameA === null && $nameB !== null) {
$result = 1;
} elseif ($nameA !== null && $nameB === null) {
$result = -1;
} else {
$result = strcmp($nameA, $nameB);
}
return $result;
});
foreach ($customerEntries as $id => $settings) {

View File

@@ -296,6 +296,7 @@ class TimesheetCountedStatistic implements \JsonSerializable
$this->recordRateExported = $recordRate;
}
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return [

View File

@@ -45,33 +45,45 @@ final class LocaleHelper
/**
* Transforms seconds into a decimal formatted duration string.
*
* @param int $seconds
* @param int|null $seconds
* @return string
*/
public function durationDecimal(int $seconds)
public function durationDecimal(?int $seconds): string
{
if ($seconds === null) {
$seconds = 0;
}
$value = round($seconds / 3600, 2);
return $this->getDurationFormatter()->format((float) $value);
return $this->getDurationFormatter()->format($value);
}
/**
* Only used in twig filter |amount and invoice templates
*
* @param string|float $amount
* @param string|float|null $amount
* @return bool|false|string
*/
public function amount($amount)
{
if ($amount === null) {
$amount = 0.00;
}
return $this->getNumberFormatter()->format($amount);
}
/**
* @param string $currency
* @param string|null $currency
* @return string
*/
public function currency($currency)
public function currency(?string $currency)
{
if ($currency === null) {
return '';
}
try {
return Currencies::getSymbol(strtoupper($currency), $this->locale);
} catch (\Exception $ex) {
@@ -109,7 +121,7 @@ final class LocaleHelper
}
/**
* @param int|float $amount
* @param int|float|null $amount
* @param string|null $currency
* @param bool $withCurrency
* @return string
@@ -120,6 +132,10 @@ final class LocaleHelper
$withCurrency = false;
}
if ($amount === null) {
$amount = 0;
}
if (false === $withCurrency) {
return $this->getMoneyFormatter($withCurrency)->format($amount, NumberFormatter::TYPE_DEFAULT);
}

View File

@@ -25,13 +25,21 @@ class DateTimeFormatValidator extends ConstraintValidator
throw new UnexpectedTypeException($constraint, __NAMESPACE__ . '\DateTimeFormat');
}
if ($value === null) {
return;
}
$valid = true;
if (!\is_string($value)) {
$valid = false;
} else {
try {
$test = new \DateTime($value);
} catch (\Exception $ex) {
$valid = false;
}
}
if (false === $valid) {
$this->context->buildViolation('The given value is not a valid datetime format.')

View File

@@ -28,4 +28,27 @@ class InvoiceDocumentTest extends TestCase
self::assertEquals('default.html.twig', $sut->getName());
self::assertIsInt($sut->getLastChange());
}
public function testThrowsOnDeletedFile()
{
$catchedException = false;
$dir = realpath(__DIR__ . '/../../templates/invoice/renderer');
$file = tempnam($dir, 'invoice-renderer');
if ($file !== false) {
touch($file);
$sut = new InvoiceDocument(new \SplFileInfo($file));
unlink($file);
try {
// names are cached by SplFileInfo, so we need to trigger a function that does access the file
$sut->getLastChange();
} catch (\Exception $exception) {
$catchedException = true;
}
}
self::assertTrue($catchedException, 'Invoice document did not throw exception');
}
}

View File

@@ -27,13 +27,11 @@ class DocxRendererTest extends TestCase
$sut = $this->getAbstractRenderer(DocxRenderer::class);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertTrue($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
}
public function testRender()

View File

@@ -31,13 +31,10 @@ class JsonRendererTest extends KernelTestCase
$sut = new JsonRenderer($env);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('text.txt.twig')));
$this->assertTrue($sut->supports($this->getInvoiceDocument('javascript.json.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('xml.xml.twig')));

View File

@@ -29,12 +29,10 @@ class OdsRendererTest extends TestCase
$sut = $this->getAbstractRenderer(OdsRenderer::class);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertTrue($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
}

View File

@@ -48,11 +48,9 @@ class PdfRendererTest extends KernelTestCase
$this->assertTrue($sut->supports($this->getInvoiceDocument('default.pdf.twig', true)));
$this->assertTrue($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
}
public function testRender()

View File

@@ -31,13 +31,11 @@ class TextRendererTest extends KernelTestCase
$sut = new TextRenderer($env);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
$this->assertTrue($sut->supports($this->getInvoiceDocument('text.txt.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('xml.xml.twig')));

View File

@@ -33,11 +33,9 @@ class TwigRendererTest extends KernelTestCase
$this->assertTrue($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertTrue($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
}
public function testRender()

View File

@@ -30,13 +30,11 @@ class XlsxRendererTest extends TestCase
$sut = $this->getAbstractRenderer(XlsxRenderer::class);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertTrue($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
}
public function getTestModel()

View File

@@ -31,14 +31,12 @@ class XmlRendererTest extends KernelTestCase
$sut = new XmlRenderer($env);
$this->assertFalse($sut->supports($this->getInvoiceDocument('default.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('freelancer.pdf.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('timesheet.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('foo.html.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('company.docx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('export.csv')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('spreadsheet.xlsx', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('open-spreadsheet.ods', true)));
$this->assertFalse($sut->supports($this->getInvoiceDocument('text.txt.twig')));
$this->assertFalse($sut->supports($this->getInvoiceDocument('javascript.json.twig')));
$this->assertTrue($sut->supports($this->getInvoiceDocument('xml.xml.twig')));

View File

@@ -69,7 +69,10 @@ class DurationValidatorTest extends ConstraintValidatorTestCase
{
$constraint = new Duration();
$this->validator->validate($input, $constraint);
$this->validator->validate(strtoupper($input), $constraint);
if ($input !== null) {
$input = strtoupper($input);
}
$this->validator->validate($input, $constraint);
$this->assertNoViolation();
}