Skip to content

Commit 8a54b6e

Browse files
minor symfony#61556 [Intl] Add metadata about currencies' validity dates (Crovitche-1623, nicolas-grekas)
This PR was merged into the 6.4 branch. Discussion ---------- [Intl] Add metadata about currencies' validity dates | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | no | New feature? | no | Deprecations? | no | Issues | - | License | MIT This backports intl data from symfony#61431 to 6.4 This also syncs the ICU compilation scripts with 7.4. This allows generating ICU data once on 6.4 and not have to care about running that again on higher branches. Commits ------- 4a85bb3 Sync intl scripts 243f8f9 [Intl] Add metadata about currencies' validtity dates
2 parents 56e7101 + 4a85bb3 commit 8a54b6e

File tree

224 files changed

+2874
-88
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

224 files changed

+2874
-88
lines changed

.github/expected-missing-return-types.diff

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2328,21 +2328,21 @@ diff --git a/src/Symfony/Component/Console/EventListener/ErrorListener.php b/src
23282328
diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php
23292329
--- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php
23302330
+++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php
2331-
@@ -87,5 +87,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
2331+
@@ -88,5 +88,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
23322332
* @return void
23332333
*/
23342334
- public function setDecorated(bool $decorated)
23352335
+ public function setDecorated(bool $decorated): void
23362336
{
23372337
$this->decorated = $decorated;
2338-
@@ -100,5 +100,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
2338+
@@ -101,5 +101,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
23392339
* @return void
23402340
*/
23412341
- public function setStyle(string $name, OutputFormatterStyleInterface $style)
23422342
+ public function setStyle(string $name, OutputFormatterStyleInterface $style): void
23432343
{
23442344
$this->styles[strtolower($name)] = $style;
2345-
@@ -127,5 +127,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
2345+
@@ -128,5 +128,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface
23462346
* @return string
23472347
*/
23482348
- public function formatAndWrap(?string $message, int $width)
@@ -2488,21 +2488,21 @@ diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Compo
24882488
+ public function setHelperSet(?HelperSet $helperSet = null): void
24892489
{
24902490
if (1 > \func_num_args()) {
2491-
@@ -97,5 +97,5 @@ abstract class Helper implements HelperInterface
2491+
@@ -101,5 +101,5 @@ abstract class Helper implements HelperInterface
24922492
* @return string
24932493
*/
24942494
- public static function formatTime(int|float $secs, int $precision = 1)
24952495
+ public static function formatTime(int|float $secs, int $precision = 1): string
24962496
{
24972497
$secs = (int) floor($secs);
2498-
@@ -140,5 +140,5 @@ abstract class Helper implements HelperInterface
2498+
@@ -144,5 +144,5 @@ abstract class Helper implements HelperInterface
24992499
* @return string
25002500
*/
25012501
- public static function formatMemory(int $memory)
25022502
+ public static function formatMemory(int $memory): string
25032503
{
25042504
if ($memory >= 1024 * 1024 * 1024) {
2505-
@@ -160,5 +160,5 @@ abstract class Helper implements HelperInterface
2505+
@@ -164,5 +164,5 @@ abstract class Helper implements HelperInterface
25062506
* @return string
25072507
*/
25082508
- public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string)
@@ -8905,24 +8905,6 @@ diff --git a/src/Symfony/Component/HttpKernel/TerminableInterface.php b/src/Symf
89058905
- public function terminate(Request $request, Response $response);
89068906
+ public function terminate(Request $request, Response $response): void;
89078907
}
8908-
diff --git a/src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php b/src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php
8909-
--- a/src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php
8910-
+++ b/src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php
8911-
@@ -27,4 +27,4 @@ interface BundleCompilerInterface
8912-
* @return void
8913-
*/
8914-
- public function compile(string $sourcePath, string $targetDir);
8915-
+ public function compile(string $sourcePath, string $targetDir): void;
8916-
}
8917-
diff --git a/src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php b/src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php
8918-
--- a/src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php
8919-
+++ b/src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php
8920-
@@ -24,4 +24,4 @@ interface BundleWriterInterface
8921-
* @return void
8922-
*/
8923-
- public function write(string $path, string $locale, mixed $data);
8924-
+ public function write(string $path, string $locale, mixed $data): void;
8925-
}
89268908
diff --git a/src/Symfony/Component/Intl/Transliterator/EmojiTransliterator.php b/src/Symfony/Component/Intl/Transliterator/EmojiTransliterator.php
89278909
--- a/src/Symfony/Component/Intl/Transliterator/EmojiTransliterator.php
89288910
+++ b/src/Symfony/Component/Intl/Transliterator/EmojiTransliterator.php
@@ -9465,28 +9447,28 @@ diff --git a/src/Symfony/Component/Lock/Store/MemcachedStore.php b/src/Symfony/C
94659447
diff --git a/src/Symfony/Component/Lock/Store/MongoDbStore.php b/src/Symfony/Component/Lock/Store/MongoDbStore.php
94669448
--- a/src/Symfony/Component/Lock/Store/MongoDbStore.php
94679449
+++ b/src/Symfony/Component/Lock/Store/MongoDbStore.php
9468-
@@ -209,5 +209,5 @@ class MongoDbStore implements PersistingStoreInterface
9450+
@@ -213,5 +213,5 @@ class MongoDbStore implements PersistingStoreInterface
94699451
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
94709452
*/
94719453
- public function createTtlIndex(int $expireAfterSeconds = 0)
94729454
+ public function createTtlIndex(int $expireAfterSeconds = 0): void
94739455
{
94749456
$server = $this->getManager()->selectServer();
9475-
@@ -231,5 +231,5 @@ class MongoDbStore implements PersistingStoreInterface
9457+
@@ -235,5 +235,5 @@ class MongoDbStore implements PersistingStoreInterface
94769458
* @throws LockExpiredException when save is called on an expired lock
94779459
*/
94789460
- public function save(Key $key)
94799461
+ public function save(Key $key): void
94809462
{
94819463
$key->reduceLifetime($this->initialTtl);
9482-
@@ -257,5 +257,5 @@ class MongoDbStore implements PersistingStoreInterface
9464+
@@ -261,5 +261,5 @@ class MongoDbStore implements PersistingStoreInterface
94839465
* @throws LockExpiredException
94849466
*/
94859467
- public function putOffExpiration(Key $key, float $ttl)
94869468
+ public function putOffExpiration(Key $key, float $ttl): void
94879469
{
94889470
$key->reduceLifetime($ttl);
9489-
@@ -276,5 +276,5 @@ class MongoDbStore implements PersistingStoreInterface
9471+
@@ -280,5 +280,5 @@ class MongoDbStore implements PersistingStoreInterface
94909472
* @return void
94919473
*/
94929474
- public function delete(Key $key)

src/Symfony/Component/Intl/Data/Bundle/Compiler/BundleCompilerInterface.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@ interface BundleCompilerInterface
2323
/**
2424
* Compiles a resource bundle at the given source to the given target
2525
* directory.
26-
*
27-
* @return void
2826
*/
29-
public function compile(string $sourcePath, string $targetDir);
27+
public function compile(string $sourcePath, string $targetDir): void;
3028
}

src/Symfony/Component/Intl/Data/Bundle/Reader/BufferedBundleReader.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
*/
2121
class BufferedBundleReader implements BundleReaderInterface
2222
{
23-
private BundleReaderInterface $reader;
2423
/** @var RingBuffer<string, mixed> */
2524
private RingBuffer $buffer;
2625

27-
public function __construct(BundleReaderInterface $reader, int $bufferSize)
28-
{
29-
$this->reader = $reader;
26+
public function __construct(
27+
private BundleReaderInterface $reader,
28+
int $bufferSize,
29+
) {
3030
$this->buffer = new RingBuffer($bufferSize);
3131
}
3232

src/Symfony/Component/Intl/Data/Bundle/Reader/BundleEntryReader.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
*/
2929
class BundleEntryReader implements BundleEntryReaderInterface
3030
{
31-
private BundleReaderInterface $reader;
32-
3331
/**
3432
* A mapping of locale aliases to locales.
3533
*/
@@ -38,9 +36,9 @@ class BundleEntryReader implements BundleEntryReaderInterface
3836
/**
3937
* Creates an entry reader based on the given resource bundle reader.
4038
*/
41-
public function __construct(BundleReaderInterface $reader)
42-
{
43-
$this->reader = $reader;
39+
public function __construct(
40+
private BundleReaderInterface $reader,
41+
) {
4442
}
4543

4644
/**

src/Symfony/Component/Intl/Data/Bundle/Writer/BundleWriterInterface.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,5 @@
2020
*/
2121
interface BundleWriterInterface
2222
{
23-
/**
24-
* @return void
25-
*/
26-
public function write(string $path, string $locale, mixed $data);
23+
public function write(string $path, string $locale, mixed $data): void;
2724
}

src/Symfony/Component/Intl/Data/Bundle/Writer/PhpBundleWriter.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ class PhpBundleWriter implements BundleWriterInterface
2525
public function write(string $path, string $locale, mixed $data): void
2626
{
2727
$template = <<<'TEMPLATE'
28-
<?php
28+
<?php
2929
30-
return %s;
30+
return %s;
3131

32-
TEMPLATE;
32+
TEMPLATE;
3333

3434
if ($data instanceof \Traversable) {
3535
$data = iterator_to_array($data);

src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,10 @@
2727
*/
2828
abstract class AbstractDataGenerator
2929
{
30-
private BundleCompilerInterface $compiler;
31-
private string $dirName;
32-
33-
public function __construct(BundleCompilerInterface $compiler, string $dirName)
34-
{
35-
$this->compiler = $compiler;
36-
$this->dirName = $dirName;
30+
public function __construct(
31+
private BundleCompilerInterface $compiler,
32+
private string $dirName,
33+
) {
3734
}
3835

3936
public function generateData(GeneratorConfig $config): void

src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ protected function generateDataForMeta(BundleEntryReaderInterface $reader, strin
102102
$data = [
103103
'Currencies' => $this->currencyCodes,
104104
'Meta' => $this->generateCurrencyMeta($supplementalDataBundle),
105+
'Map' => $this->generateCurrencyMap($supplementalDataBundle),
105106
'Alpha3ToNumeric' => $this->generateAlpha3ToNumericMapping($numericCodesBundle, $this->currencyCodes),
106107
];
107108

@@ -127,6 +128,70 @@ private function generateCurrencyMeta(ArrayAccessibleResourceBundle $supplementa
127128
return iterator_to_array($supplementalDataBundle['CurrencyMeta']);
128129
}
129130

131+
/**
132+
* @return array<string, array>
133+
*/
134+
private function generateCurrencyMap(mixed $supplementalDataBundle): array
135+
{
136+
/**
137+
* @var list<string, list<string, array{from?: string, to?: string, tender?: false}>> $regionsData
138+
*/
139+
$regionsData = [];
140+
141+
foreach ($supplementalDataBundle['CurrencyMap'] as $regionId => $region) {
142+
foreach ($region as $metadata) {
143+
/**
144+
* Note 1: The "to" property (if present) is always greater than "from".
145+
* Note 2: The "to" property may be missing if the currency is still in use.
146+
* Note 3: The "tender" property indicates whether the country legally recognizes the currency within
147+
* its borders. This property is explicitly set to `false` only if that is not the case;
148+
* otherwise, it is `true` by default.
149+
* Note 4: The "from" and "to" dates are not stored as strings; they are stored as a pair of integers.
150+
* Note 5: The "to" property may be missing if "tender" is set to `false`.
151+
*
152+
* @var array{
153+
* from?: array{0: int, 1: int},
154+
* to?: array{0: int, 2: int},
155+
* tender?: bool,
156+
* id: string
157+
* } $metadata
158+
*/
159+
$metadata = iterator_to_array($metadata);
160+
161+
$id = $metadata['id'];
162+
163+
unset($metadata['id']);
164+
165+
if (\array_key_exists($id, self::DENYLIST)) {
166+
continue;
167+
}
168+
169+
if (\array_key_exists('from', $metadata)) {
170+
$metadata['from'] = self::icuPairToDate($metadata['from']);
171+
}
172+
173+
if (\array_key_exists('to', $metadata)) {
174+
$metadata['to'] = self::icuPairToDate($metadata['to']);
175+
}
176+
177+
if (\array_key_exists('tender', $metadata)) {
178+
$metadata['tender'] = filter_var($metadata['tender'], \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE);
179+
180+
if (null === $metadata['tender']) {
181+
throw new \RuntimeException('Unexpected boolean value for tender attribute.');
182+
}
183+
}
184+
185+
$regionsData[$regionId][$id] = $metadata;
186+
}
187+
188+
// Do not exclude countries with no currencies or excluded currencies (e.g. Antartica)
189+
$regionsData[$regionId] ??= [];
190+
}
191+
192+
return $regionsData;
193+
}
194+
130195
private function generateAlpha3ToNumericMapping(ArrayAccessibleResourceBundle $numericCodesBundle, array $currencyCodes): array
131196
{
132197
$alpha3ToNumericMapping = iterator_to_array($numericCodesBundle['codeMap']);
@@ -156,4 +221,41 @@ private function generateNumericToAlpha3Mapping(array $alpha3ToNumericMapping):
156221

157222
return $numericToAlpha3Mapping;
158223
}
224+
225+
/**
226+
* Decodes ICU "date pair" into a DateTimeImmutable (UTC).
227+
*
228+
* ICU stores UDate = milliseconds since 1970-01-01T00:00:00Z in a signed 64-bit.
229+
*
230+
* @param array{0: int, 1: int} $pair
231+
*/
232+
private static function icuPairToDate(array $pair): string
233+
{
234+
[$highBits32, $lowBits32] = $pair;
235+
236+
// Recompose a 64-bit unsigned integer from two 32-bit chunks.
237+
$unsigned64 = ((($highBits32 & 0xFFFFFFFF) << 32) | ($lowBits32 & 0xFFFFFFFF));
238+
239+
// Convert to signed 64-bit (two's complement) if sign bit is set.
240+
if ($unsigned64 >= (1 << 63)) {
241+
$unsigned64 -= (1 << 64);
242+
}
243+
244+
// Split into seconds and milliseconds.
245+
$seconds = intdiv($unsigned64, 1000);
246+
$millisecondsRemainder = $unsigned64 - $seconds * 1000;
247+
248+
// Normalize negative millisecond remainders (e.g., for pre-1970 values)
249+
if (0 > $millisecondsRemainder) {
250+
--$seconds;
251+
}
252+
253+
$datetime = \DateTimeImmutable::createFromFormat('U', $seconds, new \DateTimeZone('Etc/UTC'));
254+
255+
if (false === $datetime) {
256+
throw new \RuntimeException('Unable to parse ICU milliseconds pair.');
257+
}
258+
259+
return $datetime->format('Y-m-d');
260+
}
159261
}

src/Symfony/Component/Intl/Data/Generator/GeneratorConfig.php

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,15 @@
2222
*/
2323
class GeneratorConfig
2424
{
25-
private string $sourceDir;
26-
private string $icuVersion;
27-
2825
/**
2926
* @var BundleWriterInterface[]
3027
*/
3128
private array $bundleWriters = [];
3229

33-
public function __construct(string $sourceDir, string $icuVersion)
34-
{
35-
$this->sourceDir = $sourceDir;
36-
$this->icuVersion = $icuVersion;
30+
public function __construct(
31+
private string $sourceDir,
32+
private string $icuVersion,
33+
) {
3734
}
3835

3936
/**

0 commit comments

Comments
 (0)