From 44182311ad8fad403767cb9117b430e9b234e684 Mon Sep 17 00:00:00 2001 From: Birgir Haraldsson Date: Mon, 2 Jun 2025 17:40:06 +0200 Subject: [PATCH 1/5] Add simple strftime formatter test --- tests/LocalizedStrftimeFormatterTest.php | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/LocalizedStrftimeFormatterTest.php diff --git a/tests/LocalizedStrftimeFormatterTest.php b/tests/LocalizedStrftimeFormatterTest.php new file mode 100644 index 0000000..8b9f981 --- /dev/null +++ b/tests/LocalizedStrftimeFormatterTest.php @@ -0,0 +1,25 @@ +assertSame('mánudagur 21. ágúst 2023 kl. 16:26 Test', $formatter->format($date)); + } + + public function testEnglishFormat(): void + { + $formatter = new LocalizedStrftimeFormatter('en_GB', '%A %c Test'); + + $date = new DateTimeImmutable('2023-08-21 16:26:14'); + + $this->assertSame('Monday 21 August 2023 at 16:26 Test', $formatter->format($date)); + } +} From 49c492a3a90bd03cb702b1c1440ef11995c01acc Mon Sep 17 00:00:00 2001 From: Birgir Haraldsson Date: Mon, 2 Jun 2025 17:58:44 +0200 Subject: [PATCH 2/5] Add test to show global function call --- tests/LocalizedStrftimeFormatterTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/LocalizedStrftimeFormatterTest.php b/tests/LocalizedStrftimeFormatterTest.php index 8b9f981..3b980fc 100644 --- a/tests/LocalizedStrftimeFormatterTest.php +++ b/tests/LocalizedStrftimeFormatterTest.php @@ -22,4 +22,17 @@ public function testEnglishFormat(): void $this->assertSame('Monday 21 August 2023 at 16:26 Test', $formatter->format($date)); } + + public function testGlobalFunctionCalls(): void + { + $formatter = new LocalizedStrftimeFormatter('is_IS', '%Y'); + + $date = new DateTimeImmutable('2023-08-21 16:26:14'); + + $this->assertSame('2023', $formatter->format($date)); + } +} + +function Y() { + throw new \RuntimeException('Should not be called'); } From 28787ee04eed07c22ef962c9d0395cdebe130db1 Mon Sep 17 00:00:00 2001 From: Birgir Haraldsson Date: Mon, 2 Jun 2025 18:01:49 +0200 Subject: [PATCH 3/5] Fix unwanted calls to global function in strftime format Because we provide all the callables, and no replacement contains an array, we can safely say that all callables are not strings. --- src/LocalizedStrftimeFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LocalizedStrftimeFormatter.php b/src/LocalizedStrftimeFormatter.php index 4e0f5e6..cb74e73 100644 --- a/src/LocalizedStrftimeFormatter.php +++ b/src/LocalizedStrftimeFormatter.php @@ -152,7 +152,7 @@ private function strftime(string $format, DateTimeImmutable $timestamp, string $ $replace = $translationTable[$pattern]; - if (is_callable($replace)) { + if (!is_string($replace) && is_callable($replace)) { $result = $replace($timestamp, $pattern); } else { From 326c12c705be41ef772a82ad914178f4b4c74954 Mon Sep 17 00:00:00 2001 From: Birgir Haraldsson Date: Tue, 3 Jun 2025 07:32:28 +0200 Subject: [PATCH 4/5] Simplify strftime formatting condition --- src/LocalizedStrftimeFormatter.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LocalizedStrftimeFormatter.php b/src/LocalizedStrftimeFormatter.php index cb74e73..e09847a 100644 --- a/src/LocalizedStrftimeFormatter.php +++ b/src/LocalizedStrftimeFormatter.php @@ -152,11 +152,11 @@ private function strftime(string $format, DateTimeImmutable $timestamp, string $ $replace = $translationTable[$pattern]; - if (!is_string($replace) && is_callable($replace)) { - $result = $replace($timestamp, $pattern); + if (is_string($replace)) { + $result = $timestamp->format($replace); } else { - $result = $timestamp->format($replace); + $result = $replace($timestamp, $pattern); } switch ($prefix) { From 84e0dc4eecc1a8f5b7601672ee31013cee67fd18 Mon Sep 17 00:00:00 2001 From: Birgir Haraldsson Date: Tue, 3 Jun 2025 12:41:39 +0200 Subject: [PATCH 5/5] Refactor prefix handling in strftime formatter using `match` This solves the phpstan problem by forcing the return type of the lambda function to a string. --- src/LocalizedStrftimeFormatter.php | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/LocalizedStrftimeFormatter.php b/src/LocalizedStrftimeFormatter.php index e09847a..1cd61cc 100644 --- a/src/LocalizedStrftimeFormatter.php +++ b/src/LocalizedStrftimeFormatter.php @@ -159,17 +159,11 @@ private function strftime(string $format, DateTimeImmutable $timestamp, string $ $result = $replace($timestamp, $pattern); } - switch ($prefix) { - case '_': - // replace leading zeros with spaces but keep last char if also zero - return preg_replace('/\G0(?=.)/', ' ', $result); - case '#': - case '-': - // remove leading zeros but keep last char if also zero - return preg_replace('/^0+(?=.)/', '', $result); - } - - return $result; + return match ($prefix) { + '_' => (string)preg_replace('/\G0(?=.)/', ' ', $result), + '#', '-' => (string)preg_replace('/^0+(?=.)/', '', $result), + default => $result, + }; }, $format); return str_replace('%%', '%', $out);