From fd327adc04d3d1479036835c8cf999c76c2bfbda Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:27:35 +0400 Subject: [PATCH] Docs update. --- README.md | 2 +- packages/dev/src/App/Example.php | 24 +- packages/formatter/README.md | 281 +++++++++++++++--- packages/formatter/UPGRADE.md | 16 + packages/formatter/docs/Examples/Config.php | 39 ++- packages/formatter/docs/Examples/Currency.php | 30 ++ .../formatter/docs/Examples/DurationIntl.php | 21 ++ .../{Duration.php => DurationPattern.php} | 0 .../formatter/docs/Examples/Uppercase.php | 44 +++ phpstan-baseline-well-known.neon | 1 + 10 files changed, 378 insertions(+), 80 deletions(-) create mode 100644 packages/formatter/docs/Examples/Currency.php create mode 100644 packages/formatter/docs/Examples/DurationIntl.php rename packages/formatter/docs/Examples/{Duration.php => DurationPattern.php} (100%) create mode 100644 packages/formatter/docs/Examples/Uppercase.php diff --git a/README.md b/README.md index 657445ac..0cc35301 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ This package provides highly powerful [`@searchBy`](packages/graphql/docs/Direct ## (Laravel) Intl Formatter -This package provides a customizable wrapper around [Intl](https://www.php.net/manual/en/book.intl) formatters to use it inside Laravel application. +This package provides a customizable wrapper around [Intl](https://www.php.net/manual/en/book.intl) formatters to use it inside Laravel application. And also allows defining own. [Read more](). diff --git a/packages/dev/src/App/Example.php b/packages/dev/src/App/Example.php index 941dcf50..052bf0b5 100644 --- a/packages/dev/src/App/Example.php +++ b/packages/dev/src/App/Example.php @@ -2,10 +2,10 @@ namespace LastDragon_ru\LaraASP\Dev\App; -use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Foundation\Application; use LastDragon_ru\LaraASP\Core\Application\ApplicationResolver; -use LastDragon_ru\LaraASP\Core\Utils\ConfigMerger; +use LastDragon_ru\LaraASP\Core\Application\Configuration\Configuration; +use LastDragon_ru\LaraASP\Core\Application\Configuration\ConfigurationResolver; use LastDragon_ru\LaraASP\Documentator\Processor\FileSystem\File; use LastDragon_ru\LaraASP\Documentator\Processor\Tasks\Preprocess\Instructions\IncludeExample\Contracts\Runner; use LastDragon_ru\LaraASP\Documentator\Utils\Text; @@ -83,6 +83,8 @@ public function __invoke(File $file): ?string { $result = "{$output}"; } } finally { + self::$app->forgetScopedInstances(); + self::$app = null; self::$file = null; self::$dumper = null; @@ -113,17 +115,15 @@ protected static function app(): Application { } /** - * @param array $settings + * @template T of Configuration + * + * @param class-string> $resolver + * @param callable(T): void|null $callback */ - public static function config(string $root, array $settings): void { - // Update - $repository = self::app()->make(Repository::class); - $config = (array) $repository->get($root, []); - $config = (new ConfigMerger())->merge([ConfigMerger::Strict => false], $config, $settings); - - $repository->set([ - $root => $config, - ]); + public static function config(string $resolver, ?callable $callback): void { + if ($callback !== null) { + $callback(self::app()->make($resolver)->getInstance()); + } } private static function getExpression(string $method): ?string { diff --git a/packages/formatter/README.md b/packages/formatter/README.md index 58f6d9d1..712ec4d6 100644 --- a/packages/formatter/README.md +++ b/packages/formatter/README.md @@ -1,6 +1,6 @@ # (Laravel) Intl Formatter -This package provides a customizable wrapper around [Intl](https://www.php.net/manual/en/book.intl) formatters to use it inside Laravel application. +This package provides a customizable wrapper around [Intl](https://www.php.net/manual/en/book.intl) formatters to use it inside Laravel application. And also allows defining own. [include:artisan]: [//]: # (start: preprocess/78cfc4c7c7c55577) @@ -39,9 +39,21 @@ composer require lastdragon-ru/lara-asp-formatter [//]: # (end: preprocess/8750339286f08805) +# Configuration + +Config can be used to customize formats. Before this, you need to publish it via the following command, and then you can edit `config/lara-asp-formatter.php`. + +```shell +php artisan vendor:publish --provider=LastDragon_ru\\LaraASP\\Formatter\\Provider --tag=config +``` + # Usage -Formatter is very simple to use: +> [!NOTE] +> +> The resolved formats are cached, thus run-time changes in the configuration will not be applied. You can `clone` the formatter instance to reset the internal cache. + +The [`Formatter`][code-links/9fbde97537a14196] is very simple to use. Please also check [`Formatter`][code-links/9fbde97537a14196] to see built-in formats 🤗 [include:example]: ./docs/Examples/Usage.php [//]: # (start: preprocess/4c2bcd97f5d25b12) @@ -81,15 +93,7 @@ The `$locale->decimal(123.454321)` is: [//]: # (end: preprocess/4c2bcd97f5d25b12) -Please check [source code](./src/Formatter.php) to see available methods and [config example](defaults/config.php) to available settings 🤗 - -# Formats - -Some methods like as `date()`/`datetime()`/etc have `$format` argument. The argument specifies not the format but the format name. So you can use the names and do not worry about real formats. It is very important when application big/grow. To specify available names and formats the package config should be published and customized. - -```shell -php artisan vendor:publish --provider=LastDragon_ru\\LaraASP\\Formatter\\Provider --tag=config -``` +You can also define separate setting for each locale: [include:example]: ./docs/Examples/Config.php [//]: # (start: preprocess/e30ad70238f2c282) @@ -100,36 +104,35 @@ php artisan vendor:publish --provider=LastDragon_ru\\LaraASP\\Formatter\\Provide use Illuminate\Support\Facades\Date; use LastDragon_ru\LaraASP\Dev\App\Example; +use LastDragon_ru\LaraASP\Formatter\Config\Config; +use LastDragon_ru\LaraASP\Formatter\Config\Format; +use LastDragon_ru\LaraASP\Formatter\Formats\IntlDateTime\IntlDateTimeFormat; +use LastDragon_ru\LaraASP\Formatter\Formats\IntlDateTime\IntlDateTimeOptions; use LastDragon_ru\LaraASP\Formatter\Formatter; -use LastDragon_ru\LaraASP\Formatter\Package; - -Example::config(Package::Name, [ - 'options' => [ - Formatter::Date => 'default', - ], - 'all' => [ - Formatter::Date => [ - 'default' => 'd MMM yyyy', - 'custom' => 'yyyy/MM/dd', - ], - ], - 'locales' => [ - 'ru_RU' => [ - Formatter::Date => [ - 'custom' => 'dd.MM.yyyy', - ], +use LastDragon_ru\LaraASP\Formatter\PackageConfig; + +Example::config(PackageConfig::class, static function (Config $config): void { + $config->formats[Formatter::Date] = new Format( + IntlDateTimeFormat::class, + new IntlDateTimeOptions( + dateType: IntlDateFormatter::SHORT, + timeType: IntlDateFormatter::NONE, + pattern : 'd MMM yyyy', + ), + [ + 'ru_RU' => new IntlDateTimeOptions( + pattern: 'dd.MM.yyyy', + ), ], - ], -]); + ); +}); $datetime = Date::make('2023-12-30T20:41:40.000018+04:00'); $default = app()->make(Formatter::class); $locale = $default->forLocale('ru_RU'); Example::dump($default->date($datetime)); -Example::dump($default->date($datetime, 'custom')); Example::dump($locale->date($datetime)); -Example::dump($locale->date($datetime, 'custom')); ``` The `$default->date($datetime)` is: @@ -138,32 +141,161 @@ The `$default->date($datetime)` is: "30 Dec 2023" ``` -The `$default->date($datetime, 'custom')` is: +The `$locale->date($datetime)` is: ```plain -"2023/12/30" +"30.12.2023" ``` -The `$locale->date($datetime)` is: +[//]: # (end: preprocess/e30ad70238f2c282) + +# Adding new formats + +You just need to create a class that implements [`Format`][code-links/f729e209367a8080], add into the package config, and add macros to the [`Formatter`][code-links/9fbde97537a14196] class. + +> [!NOTE] +> +> [include:docblock]: ./src/Contracts/Format.php +> [//]: # (start: preprocess/0015746c2d34336b) +> [//]: # (warning: Generated automatically. Do not edit.) +> +> The instance will be created through container with the following additional +> arguments: +> +> * `$formatter`: [`Formatter`][code-links/9fbde97537a14196] - the current formatter instance (can be used to get locale/timezone). +> * `$options` (array) - formatter options defined inside app config (may contain `null`s). +> +> [//]: # (end: preprocess/0015746c2d34336b) +> + +[include:example]: ./docs/Examples/Uppercase.php +[//]: # (start: preprocess/20404ebb04e0776f) +[//]: # (warning: Generated automatically. Do not edit.) + +```php + + */ +class UppercaseFormat implements FormatContract { + public function __construct() { + // empty + } + + #[Override] + public function __invoke(mixed $value): string { + return mb_strtoupper((string) $value); + } +} + +Formatter::macro('uppercase', function (Stringable|string|null $value): string { + return $this->format('uppercase', $value); +}); + +Example::config(PackageConfig::class, static function (Config $config): void { + $config->formats['uppercase'] = new Format( + UppercaseFormat::class, + ); +}); + +// @phpstan-ignore method.notFound +Example::dump(app()->make(Formatter::class)->uppercase('string')); +``` + +The `app()->make(Formatter::class)->uppercase('string')` is: ```plain -"30 дек. 2023" +"STRING" ``` -The `$locale->date($datetime, 'custom')` is: +[//]: # (end: preprocess/20404ebb04e0776f) + +# Notes about built-in formats + +## Currency + +By default, the [`Formatter`][code-links/9fbde97537a14196] use locale currency. You can redefine it globally through config, specify for the call, and/or add a macros for another currency. + +[include:example]: ./docs/Examples/Currency.php +[//]: # (start: preprocess/579d73db05700cf0) +[//]: # (warning: Generated automatically. Do not edit.) + +```php +formats[Formatter::Currency] = new Format( + IntlCurrencyFormat::class, + new IntlCurrencyOptions( + currency: 'USD', + ), + ); +}); + +Formatter::macro('eur', function (float|int|null $value): string { + return $this->format(Formatter::Currency, [$value, 'EUR']); +}); + +$formatter = app()->make(Formatter::class); +$value = 123.45; + +// @phpstan-ignore method.notFound +Example::dump($formatter->eur($value)); // macro +Example::dump($formatter->currency($value)); // locale default +Example::dump($formatter->currency($value, 'EUR')); // as defined +``` + +The `$formatter->eur($value)` is: ```plain -"30.12.2023" +"€123.45" ``` -[//]: # (end: preprocess/e30ad70238f2c282) +The `$formatter->currency($value)` is: + +```plain +"$123.45" +``` + +The `$formatter->currency($value, 'EUR')` is: + +```plain +"€123.45" +``` + +[//]: # (end: preprocess/579d73db05700cf0) -# Duration +## Duration -To format duration you can use built-in Intl formatter, but it doesn't support fraction seconds and have different format between locales (for example, `12345` seconds is `3:25:45` in `en_US` locale, and `12 345` in `ru_RU`). These reasons make difficult to use it in real applications. To make `duration()` more useful, the alternative syntax was added. +To format duration you can use built-in Intl formatter, but it doesn't support fraction seconds and have a different format between locales (for example, `12345` seconds is `3:25:45` in `en_US` locale, and `12 345` in `ru_RU`). These reasons make it difficult to use it in real applications. To make `duration()` more useful, the alternative syntax was added and used by default. -[include:docblock]: ./src/Utils/DurationFormatter.php ({"summary": false}) -[//]: # (start: preprocess/29da251049347125) +[include:docblock]: ./src/Formats/Duration/DurationFormat.php ({"summary": false}) +[//]: # (start: preprocess/ef4289839adfe4ca) [//]: # (warning: Generated automatically. Do not edit.) The syntax is the same as [ICU Date/Time format syntax](https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax). @@ -181,10 +313,10 @@ The syntax is the same as [ICU Date/Time format syntax](https://unicode-org.gith | `'` | escape for text | | `''` | two single quotes produce one | -[//]: # (end: preprocess/29da251049347125) +[//]: # (end: preprocess/ef4289839adfe4ca) -[include:example]: ./docs/Examples/Duration.php -[//]: # (start: preprocess/1bbaf6764d0f3cce) +[include:example]: ./docs/Examples/DurationPattern.php +[//]: # (start: preprocess/75de7a9481771185) [//]: # (warning: Generated automatically. Do not edit.) ```php @@ -219,7 +351,51 @@ The `$locale->duration(1234543)` is: "342:55:43.000" ``` -[//]: # (end: preprocess/1bbaf6764d0f3cce) +[//]: # (end: preprocess/75de7a9481771185) + +To use Intl Formatter, you need to change the duration format in the config: + +[include:example]: ./docs/Examples/DurationIntl.php +[//]: # (start: preprocess/1e573cfe77ba6df3) +[//]: # (warning: Generated automatically. Do not edit.) + +```php +formats[Formatter::Duration] = new Format( + IntlDurationFormat::class, + ); +}); + +$default = app()->make(Formatter::class); // For default app locale +$locale = $default->forLocale('ru_RU'); // For ru_RU locale +$value = 123.4543; + +Example::dump($default->duration($value)); +Example::dump($locale->duration($value)); +``` + +The `$default->duration($value)` is: + +```plain +"2:03" +``` + +The `$locale->duration($value)` is: + +```plain +"123" +``` + +[//]: # (end: preprocess/1e573cfe77ba6df3) # Upgrading @@ -234,3 +410,14 @@ Please follow [Upgrade Guide](UPGRADE.md). This package is the part of Awesome Set of Packages for Laravel. Please use the [main repository](https://github.com/LastDragon-ru/lara-asp) to [report issues](https://github.com/LastDragon-ru/lara-asp/issues), send [pull requests](https://github.com/LastDragon-ru/lara-asp/pulls), or [ask questions](https://github.com/LastDragon-ru/lara-asp/discussions). [//]: # (end: preprocess/c4ba75080f5a48b7) + +[//]: # (start: code-links) +[//]: # (warning: Generated automatically. Do not edit.) + +[code-links/f729e209367a8080]: src/Contracts/Format.php + "\LastDragon_ru\LaraASP\Formatter\Contracts\Format" + +[code-links/9fbde97537a14196]: src/Formatter.php + "\LastDragon_ru\LaraASP\Formatter\Formatter" + +[//]: # (end: code-links) diff --git a/packages/formatter/UPGRADE.md b/packages/formatter/UPGRADE.md index d4cffb85..c54f470c 100644 --- a/packages/formatter/UPGRADE.md +++ b/packages/formatter/UPGRADE.md @@ -29,6 +29,8 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases) # Upgrade from v6 +This version is the deep refactoring of the [`Formatter`][code-links/9fbde97537a14196] class to make it simple and allow adding new formats easily. All built-in formats are now instances of [`Format`][code-links/f729e209367a8080] interface. Also, the config now is the [`Config`][code-links/d45c59bc79a55ae4] instance instead of an array, and locale-specific settings were moved into format itself. Please check the updated documentation for more details. + [include:file]: ../../docs/Shared/Upgrade/FromV6.md [//]: # (start: preprocess/9679e76379216855) [//]: # (warning: Generated automatically. Do not edit.) @@ -52,3 +54,17 @@ Please also see [changelog](https://github.com/LastDragon-ru/lara-asp/releases) [//]: # (end: preprocess/2e85dad2b0618274) * [ ] If you are passing `\IntlDateFormatter::*` constants as `$format` argument for `Formatter::time()`/`Formatter::date()`/`Formatter::datetime()`, add a new custom format(s) which will refer to `\IntlDateFormatter::*` constant(s). + +[//]: # (start: code-links) +[//]: # (warning: Generated automatically. Do not edit.) + +[code-links/d45c59bc79a55ae4]: src/Config/Config.php + "\LastDragon_ru\LaraASP\Formatter\Config\Config" + +[code-links/f729e209367a8080]: src/Contracts/Format.php + "\LastDragon_ru\LaraASP\Formatter\Contracts\Format" + +[code-links/9fbde97537a14196]: src/Formatter.php + "\LastDragon_ru\LaraASP\Formatter\Formatter" + +[//]: # (end: code-links) diff --git a/packages/formatter/docs/Examples/Config.php b/packages/formatter/docs/Examples/Config.php index 97b2faf3..f13fc895 100644 --- a/packages/formatter/docs/Examples/Config.php +++ b/packages/formatter/docs/Examples/Config.php @@ -2,33 +2,32 @@ use Illuminate\Support\Facades\Date; use LastDragon_ru\LaraASP\Dev\App\Example; +use LastDragon_ru\LaraASP\Formatter\Config\Config; +use LastDragon_ru\LaraASP\Formatter\Config\Format; +use LastDragon_ru\LaraASP\Formatter\Formats\IntlDateTime\IntlDateTimeFormat; +use LastDragon_ru\LaraASP\Formatter\Formats\IntlDateTime\IntlDateTimeOptions; use LastDragon_ru\LaraASP\Formatter\Formatter; -use LastDragon_ru\LaraASP\Formatter\Package; +use LastDragon_ru\LaraASP\Formatter\PackageConfig; -Example::config(Package::Name, [ - 'options' => [ - Formatter::Date => 'default', - ], - 'all' => [ - Formatter::Date => [ - 'default' => 'd MMM yyyy', - 'custom' => 'yyyy/MM/dd', +Example::config(PackageConfig::class, static function (Config $config): void { + $config->formats[Formatter::Date] = new Format( + IntlDateTimeFormat::class, + new IntlDateTimeOptions( + dateType: IntlDateFormatter::SHORT, + timeType: IntlDateFormatter::NONE, + pattern : 'd MMM yyyy', + ), + [ + 'ru_RU' => new IntlDateTimeOptions( + pattern: 'dd.MM.yyyy', + ), ], - ], - 'locales' => [ - 'ru_RU' => [ - Formatter::Date => [ - 'custom' => 'dd.MM.yyyy', - ], - ], - ], -]); + ); +}); $datetime = Date::make('2023-12-30T20:41:40.000018+04:00'); $default = app()->make(Formatter::class); $locale = $default->forLocale('ru_RU'); Example::dump($default->date($datetime)); -Example::dump($default->date($datetime)); -Example::dump($locale->date($datetime)); Example::dump($locale->date($datetime)); diff --git a/packages/formatter/docs/Examples/Currency.php b/packages/formatter/docs/Examples/Currency.php new file mode 100644 index 00000000..c4cc6ac2 --- /dev/null +++ b/packages/formatter/docs/Examples/Currency.php @@ -0,0 +1,30 @@ +formats[Formatter::Currency] = new Format( + IntlCurrencyFormat::class, + new IntlCurrencyOptions( + currency: 'USD', + ), + ); +}); + +Formatter::macro('eur', function (float|int|null $value): string { + return $this->format(Formatter::Currency, [$value, 'EUR']); +}); + +$formatter = app()->make(Formatter::class); +$value = 123.45; + +// @phpstan-ignore method.notFound +Example::dump($formatter->eur($value)); // macro +Example::dump($formatter->currency($value)); // locale default +Example::dump($formatter->currency($value, 'EUR')); // as defined diff --git a/packages/formatter/docs/Examples/DurationIntl.php b/packages/formatter/docs/Examples/DurationIntl.php new file mode 100644 index 00000000..a15ea3c6 --- /dev/null +++ b/packages/formatter/docs/Examples/DurationIntl.php @@ -0,0 +1,21 @@ +formats[Formatter::Duration] = new Format( + IntlDurationFormat::class, + ); +}); + +$default = app()->make(Formatter::class); // For default app locale +$locale = $default->forLocale('ru_RU'); // For ru_RU locale +$value = 123.4543; + +Example::dump($default->duration($value)); +Example::dump($locale->duration($value)); diff --git a/packages/formatter/docs/Examples/Duration.php b/packages/formatter/docs/Examples/DurationPattern.php similarity index 100% rename from packages/formatter/docs/Examples/Duration.php rename to packages/formatter/docs/Examples/DurationPattern.php diff --git a/packages/formatter/docs/Examples/Uppercase.php b/packages/formatter/docs/Examples/Uppercase.php new file mode 100644 index 00000000..b4474c99 --- /dev/null +++ b/packages/formatter/docs/Examples/Uppercase.php @@ -0,0 +1,44 @@ + + */ +class UppercaseFormat implements FormatContract { + public function __construct() { + // empty + } + + #[Override] + public function __invoke(mixed $value): string { + return mb_strtoupper((string) $value); + } +} + +Formatter::macro('uppercase', function (Stringable|string|null $value): string { + return $this->format('uppercase', $value); +}); + +Example::config(PackageConfig::class, static function (Config $config): void { + $config->formats['uppercase'] = new Format( + UppercaseFormat::class, + ); +}); + +// @phpstan-ignore method.notFound +Example::dump(app()->make(Formatter::class)->uppercase('string')); diff --git a/phpstan-baseline-well-known.neon b/phpstan-baseline-well-known.neon index cdf7169b..128244f0 100644 --- a/phpstan-baseline-well-known.neon +++ b/phpstan-baseline-well-known.neon @@ -17,6 +17,7 @@ parameters: - "#^Dynamic call to static method Illuminate\\\\Testing\\\\TestResponse\\<[^>]+\\>\\:\\:assert[^(]+\\(\\)\\.$#" - "#^Dynamic call to static method Illuminate\\\\Database\\\\Eloquent\\\\Model(\\<[^>]+\\>)?\\:\\:[^(]+\\(\\)\\.$#" - "#^Dynamic call to static method Illuminate\\\\Database\\\\Eloquent\\\\Builder(\\<[^>]+\\>)?\\:\\:[^(]+\\(\\)\\.$#" + - "#^Dynamic call to static method Illuminate\\\\Container\\\\Container::forgetScopedInstances\\(\\)\\.$#" # Sometimes it is needed... # https://github.com/phpstan/phpstan/issues/3296