Skip to content

Commit

Permalink
feat(formatter): More precise Formatter::filesize()/`Formatter::dis…
Browse files Browse the repository at this point in the history
…ksize()` (`1047552` bytes will be converted to "1.00 MiB" instead of "1,023.00 KiB").
  • Loading branch information
LastDragon-ru committed Dec 12, 2023
1 parent 2ffb175 commit 73dea41
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 6 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
},
"require": {
"php": "^8.1|^8.2|^8.3",
"ext-bcmath": "*",
"ext-dom": "*",
"ext-intl": "*",
"ext-json": "*",
Expand Down
1 change: 1 addition & 0 deletions packages/formatter/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
},
"require": {
"php": "^8.1|^8.2|^8.3",
"ext-bcmath": "*",
"ext-intl": "*",
"ext-mbstring": "*",
"laravel/framework": "^9.21.0|^10.0.0",
Expand Down
24 changes: 18 additions & 6 deletions packages/formatter/src/Formatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DateTimeZone;
use Illuminate\Container\Container;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Str;
use Illuminate\Support\Traits\Macroable;
use IntlDateFormatter;
use IntlTimeZone;
Expand All @@ -19,7 +20,10 @@
use OutOfBoundsException;

use function abs;
use function bccomp;
use function bcdiv;
use function config;
use function is_float;
use function is_int;
use function is_null;
use function is_string;
Expand Down Expand Up @@ -494,18 +498,26 @@ protected function formatDateTime(
* @param array<int<0, max>, string> $units
*/
protected function formatFilesize(string|float|int|null $bytes, int $decimals, int $base, array $units): string {
$bytes = (float) $bytes;
$unit = 0;

while ($bytes >= $base) {
$bytes /= $base;
$base = (string) $base;
$scale = 2 * $decimals;
$bytes = match (true) {
is_float($bytes) => sprintf('%0.0f', $bytes),
default => (string) $bytes,
};
$length = static function (string $bytes): int {
return mb_strlen(Str::before($bytes, '.'));
};

while ((bccomp($bytes, $base, $scale) >= 0 || $length($bytes) > 2) && isset($units[$unit + 1])) {
$bytes = bcdiv($bytes, $base, $scale);
$unit++;
}

// Format
return $unit === 0
? $this->integer($bytes)." {$units[$unit]}"
: $this->decimal($bytes, $decimals)." {$units[$unit]}";
? $this->integer((int) $bytes)." {$units[$unit]}"
: $this->decimal((float) $bytes, $decimals)." {$units[$unit]}";
}
// </editor-fold>

Expand Down
8 changes: 8 additions & 0 deletions packages/formatter/src/FormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,20 +269,28 @@ public function testFilesize(): void {
self::assertEquals('0 B', $this->formatter->filesize(null));
self::assertEquals('0 B', $this->formatter->filesize(0));
self::assertEquals('10 B', $this->formatter->filesize(10));
self::assertEquals('1.00 MiB', $this->formatter->filesize(1023 * 1024, 2));
self::assertEquals('10.33 MiB', $this->formatter->filesize(10 * 1024 * 1024 + 1024 * 334));
self::assertEquals('10.00 GiB', $this->formatter->filesize(10 * 1024 * 1024 * 1024, 2));
self::assertEquals('0.87 EiB', $this->formatter->filesize(999_999_999_999_999_999, 2));
self::assertEquals('8.00 EiB', $this->formatter->filesize(PHP_INT_MAX, 2));
}

public function testDisksize(): void {
self::assertEquals('0 B', $this->formatter->disksize(null));
self::assertEquals('0 B', $this->formatter->disksize(0));
self::assertEquals('10 B', $this->formatter->disksize(10));
self::assertEquals('1.00 MB', $this->formatter->disksize(999 * 1000, 2));
self::assertEquals('10.83 MB', $this->formatter->disksize(10 * 1024 * 1024 + 1024 * 334));
self::assertEquals('10.00 GB', $this->formatter->disksize(10 * 1000 * 1000 * 1000, 2));
self::assertEquals('9.22 EB', $this->formatter->disksize(PHP_INT_MAX, 2));
self::assertEquals('10.00 QB', $this->formatter->disksize(10_000_000_000_000_000_000_000_000_000_000, 2));
self::assertEquals('10.00 QB', $this->formatter->disksize('10000000000000000000000000000000', 2));
self::assertEquals('100.00 QB', $this->formatter->disksize('99999999999999999999999999999999', 2));
self::assertEquals(
'10,000.00 QB',
$this->formatter->disksize(10_000_000_000_000_000_000_000_000_000_000_000, 2),
);
}

public function testCurrency(): void {
Expand Down

0 comments on commit 73dea41

Please sign in to comment.