diff --git a/composer.json b/composer.json index 3b04f38..1ce18d9 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,6 @@ "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", - "icanboogie/common": "^6.0", "icanboogie/accessor": "^6.0" }, "require-dev": { diff --git a/generator/src/Command/GenerateCurrency.php b/generator/src/Command/GenerateCurrency.php index 2814b19..1592683 100644 --- a/generator/src/Command/GenerateCurrency.php +++ b/generator/src/Command/GenerateCurrency.php @@ -28,7 +28,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @var string[] $codes * * @link https://github.com/unicode-org/cldr-json/blob/45.0.0/cldr-json/cldr-numbers-full/main/en-001/currencies.json - * @phpstan-ignore-next-line */ $codes = array_keys($this->repository->locale_for('en-001')['currencies']); @@ -41,7 +40,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int * }> $fractions * * @link https://github.com/unicode-org/cldr-json/blob/45.0.0/cldr-json/cldr-core/supplemental/currencyData.json - * @phpstan-ignore-next-line */ $fractions = $this->repository->supplemental['currencyData']['fractions']; diff --git a/generator/src/Command/GenerateSequenceCompanion.php b/generator/src/Command/GenerateSequenceCompanion.php index 632d382..526dab2 100644 --- a/generator/src/Command/GenerateSequenceCompanion.php +++ b/generator/src/Command/GenerateSequenceCompanion.php @@ -21,7 +21,6 @@ public function __construct( protected function execute(InputInterface $input, OutputInterface $output): int { - // @phpstan-ignore-next-line $units = $this->repository->locale_for('en-001')['units']['long']; $methods = []; diff --git a/generator/src/Command/GenerateTerritoryCode.php b/generator/src/Command/GenerateTerritoryCode.php index cdccfcf..e807248 100644 --- a/generator/src/Command/GenerateTerritoryCode.php +++ b/generator/src/Command/GenerateTerritoryCode.php @@ -27,7 +27,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int * @var string[] $codes * * @link https://github.com/unicode-org/cldr-json/blob/45.0.0/cldr-json/cldr-localenames-full/main/en-001/territories.json - * @phpstan-ignore-next-line */ $codes = array_keys($this->repository->locale_for('en-001')['territories']); $codes = array_values(array_filter($codes, fn($code) => !str_contains($code, '-alt'))); diff --git a/generator/src/Command/GenerateUnitsCompanion.php b/generator/src/Command/GenerateUnitsCompanion.php index cf0e45f..ed82c53 100644 --- a/generator/src/Command/GenerateUnitsCompanion.php +++ b/generator/src/Command/GenerateUnitsCompanion.php @@ -21,7 +21,6 @@ public function __construct( protected function execute(InputInterface $input, OutputInterface $output): int { - // @phpstan-ignore-next-line $units = $this->repository->locale_for('en-001')['units']['long']; $properties = []; $methods = []; diff --git a/src/AbstractSectionCollection.php b/src/AbstractSectionCollection.php index e2b25cb..de29b67 100644 --- a/src/AbstractSectionCollection.php +++ b/src/AbstractSectionCollection.php @@ -3,10 +3,12 @@ namespace ICanBoogie\CLDR; use ArrayAccess; -use ICanBoogie\OffsetNotDefined; +use LogicException; /** - * @implements ArrayAccess + * @template TKey of array-key + * + * @implements ArrayAccess */ abstract class AbstractSectionCollection implements ArrayAccess { @@ -17,7 +19,7 @@ public function __construct( ) { } - abstract public function offsetExists($offset): bool; + abstract public function offsetExists(mixed $offset): bool; /** * @var array @@ -28,17 +30,14 @@ abstract public function offsetExists($offset): bool; private array $sections = []; /** - * @param string $offset - * - * @throws OffsetNotDefined + * @throws LogicException * @throws ResourceNotFound */ - #[\ReturnTypeWillChange] // @phpstan-ignore-line - public function offsetGet( - $offset - ) { + #[\ReturnTypeWillChange] + public function offsetGet(mixed $offset) + { if (!$this->offsetExists($offset)) { - throw new OffsetNotDefined(offset: $offset, container: $this); + throw new LogicException("Offset '$offset' does not exist"); } return $this->sections[$offset] ??= $this->repository->fetch( diff --git a/src/Cache/CacheCollection.php b/src/Cache/CacheCollection.php index d1c351d..c4b8dfe 100644 --- a/src/Cache/CacheCollection.php +++ b/src/Cache/CacheCollection.php @@ -5,7 +5,7 @@ use ICanBoogie\CLDR\Cache; /** - * A collection of {@link Cache} instances. + * A collection of {@see Cache} instances. */ final class CacheCollection implements Cache { diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index 9c4d9e5..c82ac7f 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -2,7 +2,7 @@ namespace ICanBoogie\CLDR; -use ICanBoogie\OffsetNotWritable; +use LogicException; /** * A trait for classes implementing collection. @@ -13,20 +13,18 @@ trait CollectionTrait * @param string $offset * @param mixed $value * - * @throw OffsetNotWritable in attempt to set the offset. + * @throw LogicException in an attempt to set the offset. */ - public function offsetSet($offset, $value): void + public function offsetSet(mixed $offset, mixed $value): void { - throw new OffsetNotWritable(offset: $offset, container: $this); + throw new LogicException("Offset '$offset' is not writable"); } /** - * @param string $offset - * - * @throw OffsetNotWritable in attempt to unset the offset. + * @throw LogicException in an attempt to unset the offset. */ - public function offsetUnset($offset): void + public function offsetUnset(mixed $offset): void { - throw new OffsetNotWritable(offset: $offset, container: $this); + throw new LogicException("Offset '$offset' is not writable"); } } diff --git a/src/ContextTransforms.php b/src/ContextTransforms.php index 7677131..6554e6f 100644 --- a/src/ContextTransforms.php +++ b/src/ContextTransforms.php @@ -8,7 +8,7 @@ use function mb_substr; /** - * @see http://unicode.org/reports/tr35/tr35-general.html#contextTransformUsage_type_attribute_values + * @link https://unicode.org/reports/tr35/tr35-general.html#contextTransformUsage_type_attribute_values */ final class ContextTransforms { diff --git a/src/DateFormatPattern.php b/src/DateFormatPatternParser.php similarity index 82% rename from src/DateFormatPattern.php rename to src/DateFormatPatternParser.php index 9f16b0a..c37e280 100644 --- a/src/DateFormatPattern.php +++ b/src/DateFormatPatternParser.php @@ -5,32 +5,36 @@ /** * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#Date_Format_Patterns */ -final class DateFormatPattern +final class DateFormatPatternParser { private const QUOTE = "'"; /** + * Parses a date format pattern. + * * @param string $pattern - * A date format pattern; for example, "yyyy.MM.dd G 'at' HH:mm:ss zzz". + * A date format pattern; for example, "hh 'o''clock' a, zzzz". * * @return array * Where _value_ is either a literal or an array where `0` is a pattern character and `1` its length. */ - public static function tokenize(string $pattern): array + public static function parse(string $pattern): array { static $cache = []; - return $cache[$pattern] ??= self::do_tokenize($pattern); + return $cache[$pattern] ??= self::do_parse($pattern); } /** + * Parses a date format pattern. + * * @param string $pattern - * A date format pattern; for example, "yyyy.MM.dd G 'at' HH:mm:ss zzz". + * A date format pattern; for example, "hh 'o''clock' a, zzzz". * * @return array * Where _value_ is either a literal or an array where `0` is a pattern character and `1` its length. */ - private static function do_tokenize(string $pattern): array + private static function do_parse(string $pattern): array { $tokens = []; $is_literal = false; diff --git a/src/DateTimeAccessor.php b/src/DateTimeAccessor.php index 35a7e0d..c56d0bf 100644 --- a/src/DateTimeAccessor.php +++ b/src/DateTimeAccessor.php @@ -8,54 +8,47 @@ /** * @property-read int $timestamp Unix timestamp. * @property-read int $year Year. - * @property-read int $month Month of the year. - * @property-read int $day Day of the month. - * @property-read int $hour Hour of the day. - * @property-read int $minute Minute of the hour. - * @property-read int $second Second of the minute. - * @property-read int $quarter Quarter of the year. - * @property-read int $week Week of the year. - * @property-read int $weekday Day of the week. + * @property-read int<1, 12> $month Month of the year. + * @property-read int<1, 31> $day Day of the month. + * @property-read int<0, 23> $hour Hour of the day. + * @property-read int<1, 59> $minute Minute of the hour. + * @property-read int<1, 59> $second Second of the minute. + * @property-read int<1, 4> $quarter Quarter of the year. + * @property-read int<1, 53> $week Week of the year. + * @property-read int<1, 7> $weekday Day of the week. * @property-read int $year_day Day of the year. - * - * @method string format(string $format) */ class DateTimeAccessor { public function __construct( - private readonly DateTimeInterface $datetime + public readonly DateTimeInterface $delegate ) { } - /** - * @return mixed - */ - public function __get(string $property) + public function __get(string $property): int { - $dt = $this->datetime; + $f = $this->delegate->format(...); return match ($property) { - 'year' => (int)$dt->format('Y'), - 'month' => (int)$dt->format('m'), - 'day' => (int)$dt->format('d'), - 'hour' => (int)$dt->format('H'), - 'minute' => (int)$dt->format('i'), - 'second' => (int)$dt->format('s'), + 'year' => (int)$f('Y'), + 'month' => (int)$f('m'), + 'day' => (int)$f('d'), + 'hour' => (int)$f('H'), + 'minute' => (int)$f('i'), + 'second' => (int)$f('s'), 'quarter' => (int)floor(($this->month - 1) / 3) + 1, - 'week' => (int)$dt->format('W'), - 'year_day' => (int)$dt->format('z') + 1, - 'weekday' => (int)$dt->format('w') ?: 7, + 'week' => (int)$f('W'), + 'year_day' => (int)$f('z') + 1, + 'weekday' => (int)$f('w') ?: 7, default => throw new LogicException("Undefined property: $property"), }; } /** - * @param mixed[] $params - * - * @return mixed + * @see DateTimeInterface::format */ - public function __call(string $name, array $params) + public function format(string $pattern): string { - return $this->datetime->$name(...$params); + return $this->delegate->format($pattern); } } diff --git a/src/DateTimeFormatId.php b/src/DateTimeFormatId.php index 4018d9a..cd4517b 100644 --- a/src/DateTimeFormatId.php +++ b/src/DateTimeFormatId.php @@ -4,7 +4,7 @@ /** * - * @see: https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats */ final class DateTimeFormatId { diff --git a/src/DateTimeFormatLength.php b/src/DateTimeFormatLength.php index ca7be1a..f8fb8b7 100644 --- a/src/DateTimeFormatLength.php +++ b/src/DateTimeFormatLength.php @@ -3,7 +3,7 @@ namespace ICanBoogie\CLDR; /** - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats */ enum DateTimeFormatLength: string { diff --git a/src/DateTimeFormatter.php b/src/DateTimeFormatter.php index 756b925..a77a65c 100644 --- a/src/DateTimeFormatter.php +++ b/src/DateTimeFormatter.php @@ -2,19 +2,16 @@ namespace ICanBoogie\CLDR; +use Closure; use DateTimeImmutable; use DateTimeInterface; use InvalidArgumentException; -use RuntimeException; use function ceil; use function floor; use function is_array; use function is_numeric; use function str_pad; -use function str_repeat; -use function strlen; -use function substr; use const STR_PAD_LEFT; @@ -23,50 +20,9 @@ * * The class allows you to format dates and times in a locale-sensitive manner using * {@link https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#Date_Format_Patterns Unicode format patterns}. - * - * @property-read Calendar $calendar The calendar used by the formatter. */ class DateTimeFormatter implements Formatter { - /** - * Pattern characters mapping to the corresponding translator methods. - * - * @var array - * Where _key_ is a pattern character and _value_ its formatter. - */ - private static array $formatters = [ - - 'G' => 'format_era', - 'y' => 'format_year', -// 'Y' => Year (in "Week of Year" based calendars). -// 'u' => Extended year. - 'Q' => 'format_quarter', - 'q' => 'format_standalone_quarter', - 'M' => 'format_month', - 'L' => 'format_standalone_month', -// 'l' => Special symbol for Chinese leap month, used in combination with M. Only used with the Chinese calendar. - 'w' => 'format_week_of_year', - 'W' => 'format_week_of_month', - 'd' => 'format_day_of_month', - 'D' => 'format_day_of_year', - 'F' => 'format_day_of_week_in_month', - - 'h' => 'format_hour12', - 'H' => 'format_hour24', - 'm' => 'format_minutes', - 's' => 'format_seconds', - 'E' => 'format_day_in_week', - 'c' => 'format_day_in_week_stand_alone', - 'e' => 'format_day_in_week_local', - 'a' => 'format_period', - 'k' => 'format_hour_in_day', - 'K' => 'format_hour_in_period', - 'z' => 'format_timezone_non_location', - 'Z' => 'format_timezone_basic', - 'v' => 'format_timezone_non_location' - - ]; - /** * Pad a numeric value with zero on its left. */ @@ -75,6 +31,10 @@ private static function numeric_pad(int $value, int $length = 2): string return str_pad((string)$value, $length, '0', STR_PAD_LEFT); } + /** + * @param Calendar $calendar + * The calendar used by the formatter. + */ public function __construct( public readonly Calendar $calendar ) { @@ -83,56 +43,32 @@ public function __construct( /** * Formats a date according to a pattern. * - * @param DateTimeInterface|string|int $datetime + * @param float|int|string|DateTimeInterface $datetime * The datetime to format. * * @return string - * The formatted date time. + * The formatted date. * * @throws \Exception * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats - * - * @uses format_era - * @uses format_year - * @uses format_standalone_quarter - * @uses format_standalone_month - * @uses format_week_of_year - * @uses format_week_of_month - * @uses format_day_of_month - * @uses format_day_of_year - * @uses format_day_of_week_in_month - * @uses format_day_in_week - * @uses format_day_in_week_stand_alone - * @uses format_day_in_week_local - * @uses format_period - * @uses format_hour12 - * @uses format_hour24 - * @uses format_hour_in_period - * @uses format_hour_in_day - * @uses format_minutes - * @uses format_seconds - * @uses format_timezone_basic - * @uses format_timezone_non_location - * + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-dates.html#26-element-datetimeformats */ public function format( - $datetime, + float|int|string|DateTimeInterface $datetime, string|DateTimeFormatLength|DateTimeFormatId $pattern_or_length_or_id ): string { $accessor = new DateTimeAccessor($this->ensure_datetime($datetime)); $pattern = $this->resolve_pattern($pattern_or_length_or_id); - $tokens = DateFormatPattern::tokenize($pattern); + $tokens = DateFormatPatternParser::parse($pattern); $rc = ''; foreach ($tokens as $token) { - if (is_array($token)) { // a callback: method name, repeating chars + if (is_array($token)) { [ $c, $l ] = $token; - $function = self::$formatters[$c] ?? - throw new InvalidArgumentException("Invalid date pattern character '$c' used in '$pattern'"); - $token = $this->$function($accessor, $l); + $f = $this->match_formatter($c, $pattern); + $token = $f($accessor, $l); } $rc .= $token; @@ -141,6 +77,45 @@ public function format( return $rc; } + /** + * @param string $c + * A pattern character. + * + * @return Closure(DateTimeAccessor, int $length):string + */ + private function match_formatter(string $c, string $pattern): Closure + { + return match ($c) { + 'G' => $this->format_era(...), + 'y' => $this->format_year(...), +// 'Y' => Year (in "Week of Year" based calendars) +// 'u' => Extended year + 'Q' => $this->format_quarter(...), + 'q' => $this->format_standalone_quarter(...), + 'M' => $this->format_month(...), + 'L' => $this->format_standalone_month(...), +// 'l' => Special symbol for Chinese leap month, used in combination with M. + 'w' => $this->format_week_of_year(...), + 'W' => $this->format_week_of_month(...), + 'd' => $this->format_day_of_month(...), + 'D' => $this->format_day_of_year(...), + 'F' => $this->format_day_of_week_in_month(...), + 'h' => $this->format_hour12(...), + 'H' => $this->format_hour24(...), + 'm' => $this->format_minutes(...), + 's' => $this->format_seconds(...), + 'E' => $this->format_day_in_week(...), + 'c' => $this->format_day_in_week_stand_alone(...), + 'e' => $this->format_day_in_week_local(...), + 'a' => $this->format_period(...), + 'k' => $this->format_hour_in_day(...), + 'K' => $this->format_hour_in_period(...), + 'z', 'v' => $this->format_timezone_non_location(...), + 'Z' => $this->format_timezone_basic(...), + default => throw new InvalidArgumentException("Unsupported date pattern character '$c' used in '$pattern'") + }; + } + /** * Resolves the specified pattern, which can be a width, a skeleton, or an actual pattern. */ @@ -163,20 +138,19 @@ protected function resolve_pattern( $id = $pattern_or_length_or_id->id; return $this->calendar['dateTimeFormats']['availableFormats'][$id] - ?? throw new RuntimeException("Unknown DateTime format id: $id"); + ?? throw new InvalidArgumentException("Unknown DateTime format id: $id"); } return $pattern_or_length_or_id; } - /* - * era (G) - */ - /** - * Era - Replaced with the Era string for the current date. One to three letters for the - * abbreviated form, four letters for the long form, five for the narrow form. [1..3,4,5] - * @todo How to support multiple Eras?, e.g. Japanese. + * Era (G); Replaced with the Era string for the current date. + * + * One to three letters for the abbreviated form, four letters for the long form, five for the narrow form: [1..3, + * 4, 5] + * + * @TODO How to support multiple Eras?, e.g. Japanese. */ private function format_era(DateTimeAccessor $datetime, int $length): string { @@ -194,13 +168,9 @@ private function format_era(DateTimeAccessor $datetime, int $length): string }; } - /* - * year (y) - */ - /** - * Year. Normally the length specifies the padding, but for two letters it also specifies the - * maximum length. [1..n] + * Year (y); Normally the length specifies the padding, but for two letters it also specifies the maximum length: + * [1..n]. */ private function format_year(DateTimeAccessor $datetime, int $length): string { @@ -213,13 +183,9 @@ private function format_year(DateTimeAccessor $datetime, int $length): string return self::numeric_pad($year, $length); } - /* - * quarter (Q,q) - */ - /** - * Quarter - Use one or two "Q" for the numerical quarter, three for the abbreviation, or four - * for the full (wide) name. [1..2,3,4] + * Quarter (Q); One or two "Q" for the numerical quarter, three for the abbreviation, or four for the full (wide) + * name: [1..2, 3, 4] * * @uses Calendar::$abbreviated_quarters * @uses Calendar::$wide_quarters @@ -246,8 +212,8 @@ private function format_quarter( } /** - * Stand-Alone Quarter - Use one or two "q" for the numerical quarter, three for the - * abbreviation, or four for the full (wide) name. [1..2,3,4] + * Stand-Alone Quarter (q); One or two "q" for the numerical quarter, three for the abbreviation, or four for the + * full (wide) name: [1..2, 3, 4] * * @uses Calendar::$standalone_abbreviated_quarters * @uses Calendar::$standalone_wide_quarters @@ -263,74 +229,74 @@ private function format_standalone_quarter(DateTimeAccessor $datetime, int $leng } /* - * month (M|L) + * Month (M|L) */ /** - * Month - Use one or two "M" for the numerical month, three for the abbreviation, four for - * the full name, or five for the narrow name. [1..2,3,4,5] - * - * @uses Calendar::$abbreviated_months - * @uses Calendar::$wide_months - * @uses Calendar::$narrow_months + * Month (M); One or two "M" for the numerical month, three for the abbreviation, four for the full name, or five + * for the narrow name: [1..2, 3, 4, 5] */ - private function format_month( - DateTimeAccessor $datetime, - int $length, - string $abbreviated = 'abbreviated_months', - string $wide = 'wide_months', - string $narrow = 'narrow_months' - ): string { - if ($length > 5) { - return ''; - } - - $month = $datetime->month; - - switch ($length) { - case 1: - return (string)$month; - case 2: - return self::numeric_pad($month); - case 3: - $names = $this->calendar->$abbreviated; - return $names[$month]; - case 4: - $names = $this->calendar->$wide; - return $names[$month]; - case 5: - $names = $this->calendar->$narrow; - return $names[$month]; - } - - return ''; // @codeCoverageIgnore + private function format_month(DateTimeAccessor $datetime, int $length): string + { + return $this->do_format_month( + datetime: $datetime, + length: $length, + abbreviated: $this->calendar->abbreviated_months, + wide: $this->calendar->wide_months, + narrow: $this->calendar->narrow_months, + ); } /** - * Stand-Alone Month - Use one or two "L" for the numerical month, three for the abbreviation, - * or four for the full (wide) name, or 5 for the narrow name. [1..2,3,4,5] - * - * @uses Calendar::$standalone_abbreviated_months - * @uses Calendar::$standalone_wide_months - * @uses Calendar::$standalone_narrow_months + * Stand-Alone Month (L); One or two "L" for the numerical month, three for the abbreviation, or four for the full + * (wide) name, or 5 for the narrow name: [1..2, 3, 4, 5] */ private function format_standalone_month(DateTimeAccessor $datetime, int $length): string { - return $this->format_month( + return $this->do_format_month( datetime: $datetime, length: $length, - abbreviated: 'standalone_abbreviated_months', - wide: 'standalone_wide_months', - narrow: 'standalone_narrow_months' + abbreviated: $this->calendar->standalone_abbreviated_months, + wide: $this->calendar->standalone_wide_months, + narrow: $this->calendar->standalone_narrow_months, ); } + /** + * @param array $abbreviated + * @param array $wide + * @param array $narrow + */ + private function do_format_month( + DateTimeAccessor $datetime, + int $length, + array $abbreviated, + array $wide, + array $narrow, + ): string { + if ($length > 5) { + return ''; + } + + /** @var int<1, 5> $length */ + + $month = $datetime->month; + + return match ($length) { + 1 => (string)$month, + 2 => self::numeric_pad($month), + 3 => $abbreviated[$month], + 4 => $wide[$month], + 5 => $narrow[$month], + }; + } + /* - * week (w|W) + * Week (w|W) */ /** - * Week of Year. [1..2] + * Week of the year (w); [1..2]. */ private function format_week_of_year(DateTimeAccessor $datetime, int $length): string { @@ -344,7 +310,7 @@ private function format_week_of_year(DateTimeAccessor $datetime, int $length): s } /** - * Week of Month. [1] + * Week of the month (W); [1]. */ private function format_week_of_month(DateTimeAccessor $datetime, int $length): string { @@ -356,11 +322,11 @@ private function format_week_of_month(DateTimeAccessor $datetime, int $length): } /* - * day (d,D,F) + * Day (d,D,F) */ /** - * Date - Day of the month. [1..2] + * Day of the month (d); [1..2]. */ private function format_day_of_month(DateTimeAccessor $datetime, int $length): string { @@ -378,7 +344,7 @@ private function format_day_of_month(DateTimeAccessor $datetime, int $length): s } /** - * Day of year. [1..3] + * Day of the year (D); [1..3]. */ private function format_day_of_year(DateTimeAccessor $datetime, int $length): string { @@ -392,7 +358,7 @@ private function format_day_of_year(DateTimeAccessor $datetime, int $length): st } /** - * Day of Week in Month. The example is for the 2nd Wed in July. [1] + * Day of the week in a month (F); For example, "2nd Wed in July": [1]. */ private function format_day_of_week_in_month(DateTimeAccessor $datetime, int $length): string { @@ -404,12 +370,12 @@ private function format_day_of_week_in_month(DateTimeAccessor $datetime, int $le } /* - * weekday (E,e,c) + * Weekday (E,e,c) */ /** - * Day of week - Use one through three letters for the short day, or four for the full name, - * five for the narrow name, or six for the short name. [1..3,4,5,6] + * Weekday (E); One through three letters for the short day, or four for the full name, five for the narrow name, or + * six for the short name: [1..3, 4, 5, 6]. */ private function format_day_in_week(DateTimeAccessor $datetime, int $length): string { @@ -418,7 +384,7 @@ private function format_day_in_week(DateTimeAccessor $datetime, int $length): st } $day = $datetime->weekday; - $code = $this->resolve_day_code($day); + $code = $this->name_for_day_code($day); $calendar = $this->calendar; return match ($length) { @@ -428,30 +394,14 @@ private function format_day_in_week(DateTimeAccessor $datetime, int $length): st 6 => $calendar->short_days[$code], default => '', }; - // @codeCoverageIgnore } /** - * Stand-Alone local day of week - Use one letter for the local numeric value (same as 'e'), - * three for the abbreviated day name, four for the full (wide) name, five for the narrow name, - * or six for the short name. - * - * @uses Calendar::$standalone_abbreviated_days - * @uses Calendar::$standalone_wide_days - * @uses Calendar::$standalone_narrow_days - * @uses Calendar::$standalone_short_days + * Stand-Alone weekday (e); One letter for the local numeric value (same as 'e'), three for the abbreviated day + * name, four for the full (wide) name, five for the narrow name, or six for the short name. */ private function format_day_in_week_stand_alone(DateTimeAccessor $datetime, int $length): string { - static $mapping = [ - - 3 => 'abbreviated', - 4 => 'wide', - 5 => 'narrow', - 6 => 'short', - - ]; - if ($length == 2 || $length > 6) { return ''; } @@ -462,15 +412,23 @@ private function format_day_in_week_stand_alone(DateTimeAccessor $datetime, int return (string)$day; } - $code = $this->resolve_day_code($day); + /** @var int<3, 6> $length */ + + $days = match ($length) { + 3 => $this->calendar->standalone_abbreviated_days, + 4 => $this->calendar->standalone_wide_days, + 5 => $this->calendar->standalone_narrow_days, + 6 => $this->calendar->standalone_short_days, + }; + + $code = $this->name_for_day_code($day); - return $this->calendar->{'standalone_' . $mapping[$length] . '_days'}[$code]; + return $days[$code]; } /** - * Local day of week. Same as E except adds a numeric value that will depend on the local - * starting day of the week, using one or two letters. For this example, Monday is the - * first day of the week. + * Local day of the week (c); Same as E except adds a numeric value that will depend on the local starting day of + * the week, using one or two letters; For example, Monday is the first day of the week. */ private function format_day_in_week_local(DateTimeAccessor $datetime, int $length): string { @@ -481,14 +439,10 @@ private function format_day_in_week_local(DateTimeAccessor $datetime, int $lengt return $this->format_day_in_week($datetime, $length); } - /* - * period (a) - */ - /** - * AM or PM. [1] + * Period (a); AM or PM. [1] * - * @return string AM or PM designator + * @return string AM or PM designator. */ private function format_period(DateTimeAccessor $datetime): string { @@ -500,10 +454,11 @@ private function format_period(DateTimeAccessor $datetime): string */ /** - * Hour [1-12]. When used in skeleton data or in a skeleton passed in an API for flexible data - * pattern generation, it should match the 12-hour-cycle format preferred by the locale - * (h or K); it should not match a 24-hour-cycle format (H or k). Use hh for zero - * padding. [1..2] + * Hour [1-12] (h); When used in skeleton data or in a skeleton passed in an API for flexible data pattern + * generation, it should match the 12-hour-cycle format preferred by the locale (h or K); it shouldn't match a + * 24-hour-cycle format (H or k). + * + * Use "hh" for zero-padding; [1..2]. */ private function format_hour12(DateTimeAccessor $datetime, int $length): string { @@ -522,10 +477,11 @@ private function format_hour12(DateTimeAccessor $datetime, int $length): string } /** - * Hour [0-23]. When used in skeleton data or in a skeleton passed in an API for flexible - * data pattern generation, it should match the 24-hour-cycle format preferred by the - * locale (H or k); it should not match a 12-hour-cycle format (h or K). Use HH for zero - * padding. [1..2] + * Hour [0-23] (H); When used in skeleton data or in a skeleton passed in an API for flexible data pattern + * generation, it should match the 24-hour-cycle format preferred by the locale (H or k); it shouldn't match a + * 12-hour-cycle format (h or K). + * + * Use "HH" for zero-padding; [1..2]. */ private function format_hour24(DateTimeAccessor $datetime, int $length): string { @@ -543,8 +499,9 @@ private function format_hour24(DateTimeAccessor $datetime, int $length): string } /** - * Hour [0-11]. When used in a skeleton, only matches K or h, see above. Use KK for zero - * padding. [1..2] + * Hour [0-11] (K); When used in a skeleton, only matches K or h, see above. + * + * Use "KK" for zero-padding; [1..2]. */ private function format_hour_in_period(DateTimeAccessor $datetime, int $length): string { @@ -562,8 +519,9 @@ private function format_hour_in_period(DateTimeAccessor $datetime, int $length): } /** - * Hour [1-24]. When used in a skeleton, only matches k or H, see above. Use kk for zero - * padding. [1..2] + * Hour [1-24] (k); When used in a skeleton, only matches k or H, see above. + * + * Use "kk" for zero-padding; [1..2]. */ private function format_hour_in_day(DateTimeAccessor $datetime, int $length): string { @@ -580,24 +538,16 @@ private function format_hour_in_day(DateTimeAccessor $datetime, int $length): st return self::numeric_pad($hour); } - /* - * minute (m) - */ - /** - * Minute. Use one or two "m" for zero padding. + * Minute (m); One or two "m" for zero-padding. */ private function format_minutes(DateTimeAccessor $datetime, int $length): string { return $this->format_minutes_or_seconds($datetime, $length, 'minute'); } - /* - * second - */ - /** - * Second. Use one or two "s" for zero padding. + * Second (s); One or two "s" for zero-padding. */ private function format_seconds(DateTimeAccessor $datetime, int $length): string { @@ -605,7 +555,7 @@ private function format_seconds(DateTimeAccessor $datetime, int $length): string } /** - * Minute. Use one or two "m" for zero padding. + * Minute (m); One or two "m" for zero-padding. */ private function format_minutes_or_seconds(DateTimeAccessor $datetime, int $length, string $which): string { @@ -627,7 +577,7 @@ private function format_minutes_or_seconds(DateTimeAccessor $datetime, int $leng */ /** - * The ISO8601 basic format. + * The ISO8601 basic format (z). */ private function format_timezone_basic(DateTimeAccessor $datetime): string { @@ -635,7 +585,7 @@ private function format_timezone_basic(DateTimeAccessor $datetime): string } /** - * The specific non-location format. + * The specific non-location format (Z, v). */ private function format_timezone_non_location(DateTimeAccessor $datetime): string { @@ -645,11 +595,9 @@ private function format_timezone_non_location(DateTimeAccessor $datetime): strin } /** - * @param DateTimeInterface|string|int $datetime - * - * @throws \Exception + * @throws \Exception if the {@see DateTimeImmutable} instance can't be created. */ - private function ensure_datetime($datetime): DateTimeInterface + private function ensure_datetime(float|int|string|DateTimeInterface $datetime): DateTimeInterface { if ($datetime instanceof DateTimeInterface) { return $datetime; @@ -658,20 +606,20 @@ private function ensure_datetime($datetime): DateTimeInterface return new DateTimeImmutable(is_numeric($datetime) ? "@$datetime" : (string)$datetime); } - private function resolve_day_code(int $day): string + /** + * @param int<1, 7> $day + * A day code. + */ + private function name_for_day_code(int $day): string { - static $translate = [ - + return match ($day) { 1 => 'mon', 2 => 'tue', 3 => 'wed', 4 => 'thu', 5 => 'fri', 6 => 'sat', - 7 => 'sun' - - ]; - - return $translate[$day]; + 7 => 'sun', + }; } } diff --git a/src/Exception.php b/src/Exception.php index 28649d0..862676a 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -7,20 +7,15 @@ /** * CLDR exceptions implement this interface so that they can be easily recognized. * - *
- * try
- * {
+ * ```php
+ * try {
  *     // …
- * }
- * catch (\ICanBoogie\CLDR\Exception $e)
- * {
+ * } catch (\ICanBoogie\CLDR\Exception $e) {
  *     // a CLDR exception
- * }
- * catch (\Exception $e
- * {
+ * } catch (\Exception $e {
  *     // another type of exception
  * }
- * 
+ * ``` */ interface Exception extends Throwable { diff --git a/src/ListFormatter.php b/src/ListFormatter.php index 7d6e443..149fd93 100644 --- a/src/ListFormatter.php +++ b/src/ListFormatter.php @@ -7,7 +7,7 @@ /** * Formats variable-length lists of things such as "Monday, Tuesday, Friday, and Saturday". * - * @see http://www.unicode.org/reports/tr35/tr35-general.html#ListPatterns + * @link https://www.unicode.org/reports/tr35/tr35-general.html#ListPatterns * * @implements Localizable */ diff --git a/src/ListType.php b/src/ListType.php index abcd651..2c3a4a2 100644 --- a/src/ListType.php +++ b/src/ListType.php @@ -3,7 +3,7 @@ namespace ICanBoogie\CLDR; /** - * @see: https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#11-list-patterns + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#11-list-patterns */ enum ListType: string { diff --git a/src/Locale.php b/src/Locale.php index 813ee12..7cb212a 100644 --- a/src/Locale.php +++ b/src/Locale.php @@ -30,10 +30,21 @@ * @property-read Units $units * @uses self::get_units() * + * @extends AbstractSectionCollection * @implements Localizable */ class Locale extends AbstractSectionCollection implements Localizable, Warmable { + /** + * @uses get_context_transforms + * @uses get_currency_formatter + * @uses get_calendar + * @uses get_calendars + * @uses get_language + * @uses get_list_formatter + * @uses get_number_formatter + * @uses get_units + */ use AccessorTrait; /** @@ -84,7 +95,6 @@ public function __construct( parent::__construct($repository); } - // @phpstan-ignore-next-line public function offsetGet($offset) { // Not all locales have context transforms @@ -95,7 +105,7 @@ public function offsetGet($offset) return parent::offsetGet($offset); } - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset(self::OFFSET_MAPPING[$offset]); } @@ -148,7 +158,6 @@ private function get_calendar(): Calendar private function get_numbers(): Numbers { - /** @phpstan-ignore-next-line */ return $this->numbers ??= new Numbers($this, $this['numbers']); } @@ -177,7 +186,6 @@ private function get_list_formatter(): LocalizedListFormatter private function get_context_transforms(): ContextTransforms { - /** @phpstan-ignore-next-line */ return $this->context_transforms ??= new ContextTransforms($this['contextTransforms']); } @@ -198,7 +206,7 @@ public function localized(Locale|LocaleId|string $locale): LocalizedLocale } /** - * Formats a number using {@link $number_formatter}. + * Formats a number using {@see $number_formatter}. * * @param float|int $number * diff --git a/src/Locale/ListPattern.php b/src/Locale/ListPattern.php index 64f727f..ecce0a3 100644 --- a/src/Locale/ListPattern.php +++ b/src/Locale/ListPattern.php @@ -3,7 +3,7 @@ namespace ICanBoogie\CLDR\Locale; /** - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#ListPatterns + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#ListPatterns */ final class ListPattern { diff --git a/src/LocalizedCurrency.php b/src/LocalizedCurrency.php index dd2b537..9fdfe46 100644 --- a/src/LocalizedCurrency.php +++ b/src/LocalizedCurrency.php @@ -6,26 +6,27 @@ * A localized currency. * * @extends LocalizedObjectWithFormatter - * - * @property-read string $name The localized name of the currency. - * @property-read string $symbol The localized symbol of the currency. */ -class LocalizedCurrency extends LocalizedObjectWithFormatter +final class LocalizedCurrency extends LocalizedObjectWithFormatter { /** - * @return LocalizedCurrencyFormatter + * @var string The localized name of the currency. */ - protected function lazy_get_formatter(): Formatter - { - return $this->locale->currency_formatter; - } + public readonly string $name; /** - * @uses get_name + * @var string The localized symbol of the currency. */ - protected function get_name(): string + public readonly string $symbol; + + public function __construct(object $target, Locale $locale) { - return $this->name_for(); + $l = $locale['currencies'][$target->code]; + $this->name = $l['displayName']; + // Not all currencies have a symbol, we default to the currency code in those cases. + $this->symbol = $l['symbol'] ?? $target->code; + + parent::__construct($target, $locale, $locale->currency_formatter); } /** @@ -39,30 +40,15 @@ public function name_for(int $count = null): string if ($count == 1) { $offset .= '-count-one'; - } else { - if ($count) { - $offset .= '-count-other'; - } + } elseif ($count) { + $offset .= '-count-other'; } - /** @phpstan-ignore-next-line */ return $this->locale['currencies'][$this->target->code][$offset]; } - private string $symbol; - - /** - * Returns the localized symbol of the currency. - * - * @uses get_symbol - */ - protected function get_symbol(): string - { - return $this->symbol ??= $this->locale['currencies'][$this->target->code]['symbol']; // @phpstan-ignore-line - } - /** - * Formats currency using localized conventions. + * Formats currency using locale's conventions. * * @param float|int|numeric-string $number */ diff --git a/src/LocalizedCurrencyFormatter.php b/src/LocalizedCurrencyFormatter.php index dbe0a31..efcb684 100644 --- a/src/LocalizedCurrencyFormatter.php +++ b/src/LocalizedCurrencyFormatter.php @@ -39,7 +39,7 @@ private function resolve_currency_symbol(string $currency): string /** * Resolves a pattern. * - * The special patterns {@link PATTERN_STANDARD} and {@link PATTERN_ACCOUNTING} are resolved + * The special patterns {@see PATTERN_STANDARD} and {@see PATTERN_ACCOUNTING} are resolved * from the currency formats. */ private function resolve_pattern(string $pattern): string diff --git a/src/LocalizedDateTime.php b/src/LocalizedDateTime.php index 04d3e0f..f41850a 100644 --- a/src/LocalizedDateTime.php +++ b/src/LocalizedDateTime.php @@ -2,9 +2,7 @@ namespace ICanBoogie\CLDR; -use DateTime; use DateTimeInterface; -use ICanBoogie\PropertyNotDefined; /** * A localized date time. @@ -34,14 +32,9 @@ */ final class LocalizedDateTime extends LocalizedObjectWithFormatter { - /** - * @inheritDoc - * - * @return DateTimeFormatter - */ - protected function lazy_get_formatter(): Formatter + public function __construct(DateTimeInterface $target, Locale $locale) { - return $this->locale->calendar->datetime_formatter; + parent::__construct($target, $locale, $locale->calendar->datetime_formatter); } /** @@ -51,65 +44,35 @@ protected function lazy_get_formatter(): Formatter */ public function __get($property) { - if (str_starts_with($property, 'as_')) { - return $this->{'format_' . $property}(); - } - - try { - return parent::__get($property); - } catch (PropertyNotDefined) { - return $this->target->$property; - } - } - - /** - * @param string $property - * @param mixed $value - */ - public function __set($property, $value): void - { - $this->target->$property = $value; - } - - /** - * @param string $method - * @param array $arguments - * - * @return mixed - * - * @throws \Exception - */ - public function __call($method, $arguments) - { - return $this->target->$method(...$arguments); + return match ($property) { + 'as_full' => $this->format_as_full(), + 'as_long' => $this->format_as_long(), + 'as_medium' => $this->format_as_medium(), + 'as_short' => $this->format_as_short(), + default => $this->target->$property, + }; } public function __toString(): string { - $target = $this->target; - - if (method_exists($target, __FUNCTION__)) { - return (string)$target; - } - // `ATOM` is used instead of `ISO8601` because of a bug in the pattern - // @see http://php.net/manual/en/class.datetime.php#datetime.constants.iso8601 + // @link https://php.net/manual/en/class.datetime.php#datetime.constants.iso8601 - return $this->target->format(DateTime::ATOM); + return $this->target->format(DateTimeInterface::ATOM); } /** - * @inheritDoc + * @see DateTimeFormatter::format() * * @throws \Exception */ - public function format(string|DateTimeFormatLength|DateTimeFormatId $pattern): string + public function format(string|DateTimeFormatLength|DateTimeFormatId $pattern_or_length_or_id): string { - return $this->formatter->format($this->target, $pattern); + return $this->formatter->format($this->target, $pattern_or_length_or_id); } /** - * Formats the instance according to the {@link DateTimeFormatLength::FULL} length. + * Formats the instance according to the {@see DateTimeFormatLength::FULL} length. */ public function format_as_full(): string { @@ -117,7 +80,7 @@ public function format_as_full(): string } /** - * Formats the instance according to the {@link DateTimeFormatLength::LONG} length. + * Formats the instance according to the {@see DateTimeFormatLength::LONG} length. */ public function format_as_long(): string { @@ -125,7 +88,7 @@ public function format_as_long(): string } /** - * Formats the instance according to the {@link DateTimeFormatLength::MEDIUM} length. + * Formats the instance according to the {@see DateTimeFormatLength::MEDIUM} length. */ public function format_as_medium(): string { @@ -133,7 +96,7 @@ public function format_as_medium(): string } /** - * Formats the instance according to the {@link DateTimeFormatLength::SHORT} length. + * Formats the instance according to the {@see DateTimeFormatLength::SHORT} length. */ public function format_as_short(): string { diff --git a/src/LocalizedListFormatter.php b/src/LocalizedListFormatter.php index 0e8b842..fb4232e 100644 --- a/src/LocalizedListFormatter.php +++ b/src/LocalizedListFormatter.php @@ -9,7 +9,7 @@ * * @extends LocalizedObject * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#ListPatterns + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#ListPatterns */ class LocalizedListFormatter extends LocalizedObject implements Formatter { @@ -20,7 +20,6 @@ class LocalizedListFormatter extends LocalizedObject implements Formatter */ public function format(array $list, ListType $type = ListType::STANDARD): string { - /** @phpstan-ignore-next-line */ $list_pattern = ListPattern::from($this->locale['listPatterns']["listPattern-type-$type->value"]); return $this->target->format($list, $list_pattern); diff --git a/src/LocalizedLocale.php b/src/LocalizedLocale.php index 895ff0a..7b2477c 100644 --- a/src/LocalizedLocale.php +++ b/src/LocalizedLocale.php @@ -5,19 +5,19 @@ /** * A localized locale. * - * @property-read string $name - * The localized name of the locale. - * * @extends LocalizedObject */ class LocalizedLocale extends LocalizedObject { /** - * @uses get_name + * @var string The localized name of the locale. */ - protected function get_name(): string + public readonly string $name; + + public function __construct(Locale $target, Locale $locale) { - /** @phpstan-ignore-next-line */ - return $this->locale['languages'][$this->target->id->value]; + $this->name = $locale['languages'][$target->id->value]; + + parent::__construct($target, $locale); } } diff --git a/src/LocalizedNumberFormatter.php b/src/LocalizedNumberFormatter.php index b853b20..581eb3f 100644 --- a/src/LocalizedNumberFormatter.php +++ b/src/LocalizedNumberFormatter.php @@ -18,6 +18,6 @@ public function format(float|int|string $number, string $pattern = null): string { $numbers = $this->locale->numbers; - return $this->target->format($number, $pattern ?? $numbers->decimal_format, $numbers->symbols); + return $this->target->format($number, $pattern ?? $numbers->standard_decimal_format, $numbers->symbols); } } diff --git a/src/LocalizedObject.php b/src/LocalizedObject.php index b8a9a71..347cb93 100644 --- a/src/LocalizedObject.php +++ b/src/LocalizedObject.php @@ -2,8 +2,6 @@ namespace ICanBoogie\CLDR; -use ICanBoogie\Accessor\AccessorTrait; - /** * Representation of a localized object. * @@ -11,12 +9,6 @@ */ abstract class LocalizedObject { - /** - * @uses get_target - * @uses get_locale - */ - use AccessorTrait; - /** * @phpstan-param T $target The object to localize. */ diff --git a/src/LocalizedObjectWithFormatter.php b/src/LocalizedObjectWithFormatter.php index 79be713..5e51511 100644 --- a/src/LocalizedObjectWithFormatter.php +++ b/src/LocalizedObjectWithFormatter.php @@ -18,28 +18,13 @@ abstract class LocalizedObjectWithFormatter extends LocalizedObject { /** - * @var TFormatter|null + * @phpstan-param TFormatter $formatter */ - private $formatter; - - /** - * @param string $property - * - * @return mixed - */ - public function __get($property) - { - if ($property === 'formatter') { - return $this->formatter ??= $this->lazy_get_formatter(); - } - - return parent::__get($property); + public function __construct( + object $target, + Locale $locale, + public readonly Formatter $formatter, + ) { + parent::__construct($target, $locale); } - - /** - * Returns the formatter used to format the target object. - * - * @return TFormatter - */ - abstract protected function lazy_get_formatter(): Formatter; } diff --git a/src/LocalizedTerritory.php b/src/LocalizedTerritory.php index 28488ba..29c80c3 100644 --- a/src/LocalizedTerritory.php +++ b/src/LocalizedTerritory.php @@ -5,19 +5,19 @@ /** * A localized territory. * - * @property-read string $name - * The localized name of the territory. - * * @extends LocalizedObject */ class LocalizedTerritory extends LocalizedObject { /** - * @uses get_name + * @var string The localized name of the territory. */ - protected function get_name(): string + public readonly string $name; + + public function __construct(Territory $target, Locale $locale) { - /** @phpstan-ignore-next-line */ - return $this->locale['territories'][$this->target->code->value]; + $this->name = $locale['territories'][$target->code->value]; + + parent::__construct($target, $locale); } } diff --git a/src/NumberPattern.php b/src/NumberPattern.php index 94b7473..f42d9fc 100644 --- a/src/NumberPattern.php +++ b/src/NumberPattern.php @@ -19,55 +19,42 @@ */ final class NumberPattern { - /** - * @var NumberPattern[] - */ - private static array $instances = []; - public static function from(string $pattern): NumberPattern { - if (isset(self::$instances[$pattern])) { - return self::$instances[$pattern]; - } + static $instances; + return $instances[$pattern] ??= self::do_from($pattern); + } + + private static function do_from(string $pattern): self + { $parsed_pattern = NumberPatternParser::parse($pattern); - return self::$instances[$pattern] = new self( - $pattern, - $parsed_pattern['positive_prefix'], - $parsed_pattern['positive_suffix'], - $parsed_pattern['negative_prefix'], - $parsed_pattern['negative_suffix'], - $parsed_pattern['multiplier'], - $parsed_pattern['decimal_digits'], - $parsed_pattern['max_decimal_digits'], - $parsed_pattern['integer_digits'], - $parsed_pattern['group_size1'], - $parsed_pattern['group_size2'] - ); + return new self($pattern, ...$parsed_pattern); } /** * @param string $pattern * @param string $positive_prefix - * Prefix to positive number. + * Prefix to a positive number. * @param string $positive_suffix - * Suffix to positive number. + * Suffix to a positive number. * @param string $negative_prefix - * Prefix to negative number. + * Prefix to a negative number. * @param string $negative_suffix * Suffix to negative number. * @param int $multiplier * 100 for percent, 1000 for per mille. * @param int $decimal_digits - * The number of required digits after decimal point. The string is padded with zeros if there is not enough - * digits. + * The number of required digits after the decimal point. + * The string is padded with zeros if there aren't enough digits. * `-1` means the decimal point should be dropped. * @param int $max_decimal_digits - * The maximum number of digits after decimal point. Additional digits will be truncated. + * The maximum number of digits after the decimal point. + * Additional digits will be truncated. * @param int $integer_digits - * The number of required digits before decimal point. The string is padded with zeros if there is not enough - * digits. + * The number of required digits before the decimal point. + * The string is padded with zeros if there aren't enough digits. * @param int $group_size1 * The primary grouping size. `0` means no grouping. * @param int $group_size2 @@ -94,7 +81,7 @@ public function __toString(): string } /** - * Parse a number according to the pattern and return its integer and decimal parts. + * Parses a number according to the pattern and return its integer and decimal parts. * * @param float|int|numeric-string $number * @@ -120,7 +107,7 @@ public function parse_number(float|int|string $number): array } /** - * Formats integer according to group pattern. + * Formats an integer according to a group pattern. */ public function format_integer_with_group(int $integer, string $group_symbol): string { @@ -138,14 +125,14 @@ public function format_integer_with_group(int $integer, string $group_symbol): s $size = $group_size2 > 0 ? $group_size2 : $group_size1; $str1 = str_pad($str1, (int)((strlen($str1) + $size - 1) / $size) * $size, ' ', STR_PAD_LEFT); - return ltrim(implode($group_symbol, (array)str_split($str1, $size))) . $group_symbol . $str2; + return ltrim(implode($group_symbol, str_split($str1, $size))) . $group_symbol . $str2; } /** * Formats an integer with a decimal. * * @param int|string $integer - * An integer, or a formatted integer as returned by {@link format_integer_with_group}. + * An integer, or a formatted integer as returned by {@see format_integer_with_group}. */ public function format_integer_with_decimal(int|string $integer, string $decimal, string $decimal_symbol): string { diff --git a/src/NumberPatternParser.php b/src/NumberPatternParser.php index 88f5ce4..6c62e4e 100644 --- a/src/NumberPatternParser.php +++ b/src/NumberPatternParser.php @@ -10,7 +10,20 @@ use function substr; /** - * @see http://unicode.org/reports/tr35/tr35-numbers.html#Number_Pattern_Character_Definitions + * @link https://unicode.org/reports/tr35/tr35-numbers.html#Number_Pattern_Character_Definitions + * + * @phpstan-type PatternArray array{ + * positive_prefix: string, + * positive_suffix: string, + * negative_prefix: string, + * negative_suffix: string, + * multiplier: int, + * decimal_digits: int, + * max_decimal_digits: int, + * integer_digits: int, + * group_size1: int, + * group_size2: int + * } */ final class NumberPatternParser { @@ -37,18 +50,9 @@ final class NumberPatternParser /** * Parses a given string pattern. * - * @return array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } + * @param string $pattern + * + * @return PatternArray */ public static function parse(string $pattern): array { @@ -64,18 +68,8 @@ public static function parse(string $pattern): array } /** - * @param array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } $format + * @param string $pattern + * @param PatternArray $format */ private static function parse_multiple_patterns(string &$pattern, array &$format): void { @@ -98,18 +92,8 @@ private static function parse_multiple_patterns(string &$pattern, array &$format } /** - * @param array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } $format + * @param string $pattern + * @param PatternArray $format */ private static function parse_multiplier(string $pattern, array &$format): void { @@ -121,18 +105,8 @@ private static function parse_multiplier(string $pattern, array &$format): void } /** - * @param array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } $format + * @param string $pattern + * @param PatternArray $format */ private static function parse_decimal_part(string &$pattern, array &$format): void { @@ -154,18 +128,8 @@ private static function parse_decimal_part(string &$pattern, array &$format): vo } /** - * @param array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } $format + * @param string $pattern + * @param PatternArray $format */ private static function parse_integer_part(string $pattern, array &$format): void { @@ -178,18 +142,8 @@ private static function parse_integer_part(string $pattern, array &$format): voi } /** - * @param array{ - * positive_prefix: string, - * positive_suffix: string, - * negative_prefix: string, - * negative_suffix: string, - * multiplier: int, - * decimal_digits: int, - * max_decimal_digits: int, - * integer_digits: int, - * group_size1: int, - * group_size2: int - * } $format + * @param string $pattern + * @param PatternArray $format */ private static function parse_group_sizes(string $pattern, array &$format): void { diff --git a/src/Numbers.php b/src/Numbers.php index 831b972..1b199b6 100644 --- a/src/Numbers.php +++ b/src/Numbers.php @@ -10,7 +10,7 @@ * * @extends ArrayObject * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#1-numbering-systems + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#1-numbering-systems */ final class Numbers extends ArrayObject { @@ -27,47 +27,49 @@ final class Numbers extends ArrayObject public readonly array $decimal_formats; /** - * Shortcut to the `decimalFormats-numberSystem-$default_numbering_system/standard`. + * The standard decimal format of the default numbering system; for example, "#,##0.###". + * + * Shortcut to `decimalFormats-numberSystem-$default_numbering_system/standard`. */ - public readonly string $decimal_format; + public readonly string $standard_decimal_format; /** - * Shortcut to the `decimalFormats-numberSystem-$default_numbering_system/short/decimalFormats`. + * Shortcut to `decimalFormats-numberSystem-$default_numbering_system/short/decimalFormats`. * * @phpstan-ignore-next-line */ public readonly array $short_decimal_formats; /** - * Shortcut to the `decimalFormats-numberSystem-$default_numbering_system/long/decimalFormats`. + * Shortcut to `decimalFormats-numberSystem-$default_numbering_system/long/decimalFormats`. * * @phpstan-ignore-next-line */ public readonly array $long_decimal_formats; /** - * Shortcut to the `scientificFormats-numberSystem-$default_numbering_system`. + * Shortcut to `scientificFormats-numberSystem-$default_numbering_system`. * * @phpstan-ignore-next-line */ public readonly array $scientific_formats; /** - * Shortcut to the `percentFormats-numberSystem-$default_numbering_system`. + * Shortcut to `percentFormats-numberSystem-$default_numbering_system`. * * @phpstan-ignore-next-line */ public readonly array $percent_formats; /** - * Shortcut to the `currencyFormats-numberSystem-$default_numbering_system`. + * Shortcut to `currencyFormats-numberSystem-$default_numbering_system`. * * @phpstan-ignore-next-line */ public readonly array $currency_formats; /** - * Shortcut to the `miscPatterns-numberSystem-$default_numbering_system`. + * Shortcut to `miscPatterns-numberSystem-$default_numbering_system`. * * @phpstan-ignore-next-line */ @@ -75,6 +77,8 @@ final class Numbers extends ArrayObject /** * @param array $data + * + * @link https://github.com/unicode-org/cldr-json/blob/45.0.0/cldr-json/cldr-numbers-full/main/en-001/numbers.json */ public function __construct( public readonly Locale $locale, @@ -84,7 +88,7 @@ public function __construct( $this->default_numbering_system = $dns = $data['defaultNumberingSystem']; $this->decimal_formats = $data["decimalFormats-numberSystem-$dns"]; - $this->decimal_format = $this->decimal_formats['standard']; + $this->standard_decimal_format = $this->decimal_formats['standard']; $this->short_decimal_formats = $this->decimal_formats['short']['decimalFormat']; $this->long_decimal_formats = $this->decimal_formats['long']['decimalFormat']; $this->scientific_formats = $data["scientificFormats-numberSystem-$dns"]; diff --git a/src/Numbers/Symbols.php b/src/Numbers/Symbols.php index fcf9501..ad5460a 100644 --- a/src/Numbers/Symbols.php +++ b/src/Numbers/Symbols.php @@ -5,7 +5,7 @@ /** * Defines the localized symbols that are commonly used when formatting numbers in a given locale. * - * @see https://unicode.org/reports/tr35/tr35-numbers.html#Number_Symbols + * @link https://unicode.org/reports/tr35/tr35-numbers.html#Number_Symbols */ final class Symbols { diff --git a/src/Plurals/Operands.php b/src/Plurals/Operands.php index 61a813b..0ae1a45 100644 --- a/src/Plurals/Operands.php +++ b/src/Plurals/Operands.php @@ -11,7 +11,7 @@ * * @internal * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Operands + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Operands */ final class Operands { diff --git a/src/Plurals/Relation.php b/src/Plurals/Relation.php index dd35b02..cb54c87 100644 --- a/src/Plurals/Relation.php +++ b/src/Plurals/Relation.php @@ -22,7 +22,7 @@ * * @internal * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Relations + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Relations */ final class Relation { diff --git a/src/Plurals/Rule.php b/src/Plurals/Rule.php index a284852..424b4e2 100644 --- a/src/Plurals/Rule.php +++ b/src/Plurals/Rule.php @@ -11,7 +11,7 @@ /** * Representation of plural samples. * - * @see http://unicode.org/reports/tr35/tr35-72-numbers.html#Language_Plural_Rules + * @link https://unicode.org/reports/tr35/tr35-72-numbers.html#Language_Plural_Rules */ final class Rule { diff --git a/src/Plurals/Samples.php b/src/Plurals/Samples.php index fe960dc..a138e65 100644 --- a/src/Plurals/Samples.php +++ b/src/Plurals/Samples.php @@ -21,7 +21,7 @@ * * @implements IteratorAggregate * - * @see http://unicode.org/reports/tr35/tr35-numbers.html#Samples + * @link https://unicode.org/reports/tr35/tr35-numbers.html#Samples */ final class Samples implements IteratorAggregate { diff --git a/src/Plurals/SamplesCache.php b/src/Plurals/SamplesCache.php index 4e4ffd5..556662f 100644 --- a/src/Plurals/SamplesCache.php +++ b/src/Plurals/SamplesCache.php @@ -9,7 +9,7 @@ final class SamplesCache { /** * @var array - * Where _key_ is a rule statement and _value_ a {@link Samples}. + * Where _key_ is a rule statement and _value_ a {@see Samples}. */ private static array $instances = []; diff --git a/src/Repository.php b/src/Repository.php index 5e34386..1a9f566 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -77,7 +77,6 @@ private function get_list_formatter(): ListFormatter private function get_plurals(): Plurals { - /** @phpstan-ignore-next-line */ return $this->plurals ??= new Plurals($this->get_supplemental()['plurals']); } diff --git a/src/ResourceNotFound.php b/src/ResourceNotFound.php index 7406ced..3c05b97 100644 --- a/src/ResourceNotFound.php +++ b/src/ResourceNotFound.php @@ -3,7 +3,7 @@ namespace ICanBoogie\CLDR; /** - * Exception throw when a path does not exist on the CLDR source. + * Exception thrown in an attempt to read a path that doesn't exist on the CLDR source. */ final class ResourceNotFound extends \Exception implements Exception { diff --git a/src/Spaces.php b/src/Spaces.php index 0421ad1..758b9fa 100644 --- a/src/Spaces.php +++ b/src/Spaces.php @@ -5,7 +5,7 @@ /** * Spaces encoded in UTF-8 * - * @see https://www.fileformat.info/info/unicode/category/Zs/list.htm + * @link https://www.fileformat.info/info/unicode/category/Zs/list.htm */ interface Spaces { diff --git a/src/Supplemental.php b/src/Supplemental.php index 910d3b5..f93e05f 100644 --- a/src/Supplemental.php +++ b/src/Supplemental.php @@ -16,6 +16,8 @@ * * echo $supplemental['calendarPreferenceData']['001']; // gregorian * + * + * @extends AbstractSectionCollection */ final class Supplemental extends AbstractSectionCollection implements Warmable { @@ -55,7 +57,7 @@ final class Supplemental extends AbstractSectionCollection implements Warmable ]; - public function offsetExists($offset): bool + public function offsetExists(mixed $offset): bool { return isset(self::OFFSET_MAPPING[$offset]); } diff --git a/src/Supplemental/Fraction.php b/src/Supplemental/Fraction.php index 3848f2a..4aabc0e 100644 --- a/src/Supplemental/Fraction.php +++ b/src/Supplemental/Fraction.php @@ -5,7 +5,7 @@ /** * @internal * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Supplemental_Currency_Data + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#Supplemental_Currency_Data */ final class Fraction { diff --git a/src/Territory.php b/src/Territory.php index 3b94f11..7533102 100644 --- a/src/Territory.php +++ b/src/Territory.php @@ -26,7 +26,7 @@ * @property-read string $name_as_* The name of the territory in the specified language. * @property-read int $population The population of the territory. * - * @see http://www.unicode.org/reports/tr35/tr35-numbers.html#Supplemental_Currency_Data + * @link https://www.unicode.org/reports/tr35/tr35-numbers.html#Supplemental_Currency_Data * * @implements Localizable */ @@ -63,7 +63,6 @@ private function get_containment(): array private function get_currencies(): RegionCurrencies { return $this->currencies ??= RegionCurrencies::from( - /** @phpstan-ignore-next-line */ $this->repository->supplemental['currencyData']['region'][$this->code->value] ); } @@ -155,9 +154,11 @@ public function __toString(): string } /** + * @param string $property + * * @return mixed */ - public function __get(string $property) + public function __get($property) { if (str_starts_with($property, 'name_as_')) { $locale_id = trim_prefix($property, 'name_as_'); @@ -174,7 +175,6 @@ public function __get(string $property) */ private function retrieve_from_supplemental(string $section): array { - /** @phpstan-ignore-next-line */ return $this->repository->supplemental[$section][$this->code->value]; } @@ -228,7 +228,6 @@ public function localized(Locale|LocaleId|string $locale): LocalizedTerritory private function resolve_week_data(string $which): string { $code = $this->code; - /** @phpstan-ignore-next-line */ $data = $this->repository->supplemental['weekData'][$which]; return $data[$code->value] ?? $data['001']; diff --git a/src/Units.php b/src/Units.php index 0fef257..94c8966 100644 --- a/src/Units.php +++ b/src/Units.php @@ -38,7 +38,6 @@ private static function length_to_unit_type(UnitLength $length): ListType public function __construct( public readonly Locale $locale ) { - /** @phpstan-ignore-next-line */ $this->data = $locale['units']; $this->sequence = new Sequence($this); } @@ -95,7 +94,7 @@ public function format(float|int|string $number, string $unit, UnitLength $lengt * * @param float|int|numeric-string $number * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#compound-units + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#compound-units */ public function format_compound( float|int|string $number, @@ -132,7 +131,7 @@ public function format_compound( * * @param array $units_and_numbers * - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#Unit_Sequences + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-general.html#Unit_Sequences */ public function format_sequence(array $units_and_numbers, UnitLength $length = self::DEFAULT_LENGTH): string { diff --git a/src/Units/Sequence.php b/src/Units/Sequence.php index f039168..3f074f2 100644 --- a/src/Units/Sequence.php +++ b/src/Units/Sequence.php @@ -15,7 +15,7 @@ * @property-read string $as_short Short string representation. * @property-read string $as_narrow Narrow string representation. * - * @see http://unicode.org/reports/tr35/tr35-general.html#Unit_Sequences + * @link https://unicode.org/reports/tr35/tr35-general.html#Unit_Sequences */ final class Sequence { diff --git a/tests/CalendarCollectionTest.php b/tests/CalendarCollectionTest.php index 17f3c5f..9002795 100644 --- a/tests/CalendarCollectionTest.php +++ b/tests/CalendarCollectionTest.php @@ -5,7 +5,7 @@ use BadMethodCallException; use ICanBoogie\CLDR\Calendar; use ICanBoogie\CLDR\CalendarCollection; -use ICanBoogie\OffsetNotWritable; +use LogicException; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -26,13 +26,13 @@ public function test_offsetExists(): void public function test_offsetSet(): void { - $this->expectException(OffsetNotWritable::class); + $this->expectException(LogicException::class); self::$collection['gregorian'] = null; } public function test_offsetUnset(): void { - $this->expectException(OffsetNotWritable::class); + $this->expectException(LogicException::class); unset(self::$collection['gregorian']); } diff --git a/tests/DateTimePatternTest.php b/tests/DateTimePatternParserTest.php similarity index 77% rename from tests/DateTimePatternTest.php rename to tests/DateTimePatternParserTest.php index 963a2ae..aa2f183 100644 --- a/tests/DateTimePatternTest.php +++ b/tests/DateTimePatternParserTest.php @@ -2,21 +2,21 @@ namespace Test\ICanBoogie\CLDR; -use ICanBoogie\CLDR\DateFormatPattern; +use ICanBoogie\CLDR\DateFormatPatternParser; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -final class DateTimePatternTest extends TestCase +final class DateTimePatternParserTest extends TestCase { - #[DataProvider("provide_tokenize")] - public function test_tokenize(string $pattern, array $expected): void + #[DataProvider("provide_parse")] + public function test_parse(string $pattern, array $expected): void { - $actual = DateFormatPattern::tokenize($pattern); + $actual = DateFormatPatternParser::parse($pattern); $this->assertEquals($expected, $actual); } - public static function provide_tokenize(): array + public static function provide_parse(): array { return [ diff --git a/tests/LocaleTest.php b/tests/LocaleTest.php index 6fca392..7e3a643 100644 --- a/tests/LocaleTest.php +++ b/tests/LocaleTest.php @@ -15,7 +15,6 @@ use ICanBoogie\CLDR\Units; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Test\ICanBoogie\CLDR\LocaleTest\LocalizableSample; final class LocaleTest extends TestCase { @@ -181,7 +180,6 @@ public function test_format_list(): void #[DataProvider("provide_context_transforms_availability")] public function test_context_transforms_availability(string $locale_id, bool $expected): void { - // @phpstan-ignore-next-line $actual = count(locale_for($locale_id)['contextTransforms']) > 0; $this->assertSame($expected, $actual); diff --git a/tests/NumbersTest.php b/tests/NumbersTest.php index 0fc2f53..f7994d7 100644 --- a/tests/NumbersTest.php +++ b/tests/NumbersTest.php @@ -153,7 +153,7 @@ public function test_get_decimal_format(string $locale_id, string $expected): vo $numbers_data = $locale['numbers']; $numbers = new Numbers($locale, $numbers_data); - $this->assertEquals($expected, $numbers->decimal_format); + $this->assertEquals($expected, $numbers->standard_decimal_format); } /** diff --git a/tests/Plurals/OperandsTest.php b/tests/Plurals/OperandsTest.php index 3ab1b2d..e89fb6a 100644 --- a/tests/Plurals/OperandsTest.php +++ b/tests/Plurals/OperandsTest.php @@ -31,7 +31,7 @@ public function test_cases(string $number, array $expected): void } /** - * @see https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#table-plural-operand-examples + * @link https://www.unicode.org/reports/tr35/tr35-72/tr35-numbers.html#table-plural-operand-examples */ public static function provide_test_cases(): array { diff --git a/tests/PluralsTest.php b/tests/PluralsTest.php index 84966ad..d30cda5 100644 --- a/tests/PluralsTest.php +++ b/tests/PluralsTest.php @@ -17,7 +17,6 @@ final class PluralsTest extends TestCase protected function setUp(): void { - // @phpstan-ignore-next-line $this->plurals = new Plurals(get_repository()->supplemental['plurals']); } diff --git a/tests/SupplementalTest.php b/tests/SupplementalTest.php index 33f8a30..4f0a991 100644 --- a/tests/SupplementalTest.php +++ b/tests/SupplementalTest.php @@ -3,8 +3,7 @@ namespace Test\ICanBoogie\CLDR; use ICanBoogie\CLDR\Supplemental; -use ICanBoogie\OffsetNotDefined; -use ICanBoogie\OffsetNotWritable; +use LogicException; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; @@ -63,7 +62,6 @@ public static function provide_test_sections(): array public function test_default_calendar(): void { - // @phpstan-ignore-next-line $this->assertArrayHasKey('001', self::$sut['calendarPreferenceData']); } @@ -79,21 +77,21 @@ public function test_offset_exists(): void public function test_should_throw_exception_when_getting_undefined_offset(): void { $s = self::$sut; - $this->expectException(OffsetNotDefined::class); + $this->expectException(LogicException::class); $s[uniqid()]; // @phpstan-ignore-line } public function test_should_throw_exception_in_attempt_to_set_offset(): void { $s = self::$sut; - $this->expectException(OffsetNotWritable::class); + $this->expectException(LogicException::class); $s['timeData'] = null; } public function test_should_throw_exception_in_attempt_to_unset_offset(): void { $s = self::$sut; - $this->expectException(OffsetNotWritable::class); + $this->expectException(LogicException::class); unset($s['timeData']); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e5f368a..faa4910 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -45,6 +45,8 @@ function create_provider(): Provider exit(1); } + $redis->flushAll(); + return $provider = new CachedProvider( new WebProvider(), new CacheCollection([