Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add toLocaleString() method to array #47

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ From Hacktoberfest:
- Test coverage at 100%
- Arr::isEmpty() methods thanks to @Tautve for the implementation and @RoadSigns for the review
- Allow Arr::flatMap() to support multidimensional arrays by @RoadSigns
- Add toLocaleString() to get the string representation of the elements in the array

## 0.0.9 - 2022-10-02
From Hacktoberfest:
Expand Down
20 changes: 20 additions & 0 deletions doc/arr.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,23 @@ var_dump($arr->copyWithin(-2, -3, -1));

```

## Return a string representing the elements in the array using a locale and timezone

Default locale is en_US, and the timezone is UTC, in order to use a different locale make sure it is installed.

To check available locales in linux based systems run `locale -a`

To install a missing locale in linux based systems run `sudo apt-get install language-pack-XX`

```php
use HiFolks\DataType\Arr;

$arr = Arr::make([1, 2, 3, 'a', 'abc', 123456.4, '2022/10/01']);
var_dump($arr->toLocaleString()); // Using en_US as default locale and UTC as default timezone
// 1,2,3,a,abc,123,456.40,Sat 01 Oct 2022 12:00:00 AM UTC

$arr = Arr::make([1, 2, 3, 'a', 'abc', 123456.4, '2022/10/01']);
var_dump($arr->toLocaleString('fr_FR', 'Europe/Paris')); // Using provided locale and timezone
// [1,2,3,a,abc,123 456,40,sam. 01 oct. 2022 00:00:00]
```

6 changes: 6 additions & 0 deletions examples/cheatsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,9 @@ function print_result(mixed $something): void
print_result($arr->copyWithin(-2, -3, -1));
// [1, 2, 3, 3, 4]
}

// Return a string representing the elements of the array
$arr = Arr::make([1, 2, 3, 'a', 'abc', 123456.4, '2022/10/01']);

print_r($arr->toLocaleString()); // Default locale and timezone
print_r($arr->toLocaleString('fr_FR', 'Europe/Paris')); // Provided locale and timezone
59 changes: 59 additions & 0 deletions src/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -726,4 +726,63 @@ public function isEmpty(): bool
{
return $this->length() === 0;
}

/**
* Returns a string representing the elements of the array
* @return string the string representation
*/
public function toLocaleString(string $locale = 'en_US', string $timezone = 'UTC'): string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, while this covers the Date.prototype.toLocaleString() there is also the Object.prototype.toLocaleString() and the Number.prototype.toLocalString() that can be converted from the Array.protoype.toLocalString().

Link to the other types of toLocalString() conversions
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toLocaleString#examples

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can definitely add support for the other methods, I'll update the current PR unless otherwise advised.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. if you want you can do it in this PR, or if you prefer you could close this and create another new PR with this refactor.
I mention "refactor" because this package is for Array so I would like to provide the toLocaleString for Arr (public method). The toLocaleString for other types (number and data) is for a clear code that is easier to test.

{
if ($this->isEmpty()) {
return '';
}

$fallbackLocale = 'en_US';
date_default_timezone_set($timezone);
$currentLocale = setlocale(LC_ALL, $locale.'.utf8');

if (!$currentLocale) {
$currentLocale = setlocale(LC_ALL, $fallbackLocale.'.utf8');
}

$localeConfig = localeconv();

$result = $this->map(function ($item) use ($localeConfig) {
if (is_numeric($item)) {
$item = number_format(
$item,
is_float($item) ? 2 : 0,
$localeConfig['decimal_point'] ?? '.',
$localeConfig["thousands_sep"] ?? ','
);
} elseif ($this->isDate($item)) {
$date = date_parse($item);
$item = strftime(
'%c',
mktime($date['hour'], $date['minute'], $date['second'], $date['month'], $date['day'], $date['year'])
);
}

return $item;
});

return $result->toString();
}

/**
* Checks whether a value is a valid date
* @return boolean true if value is a valid date, false otherwise
*/
private function isDate($value): bool
{
if (!$value) {
return false;
}

$date = date_parse($value);

return $date['error_count'] == 0
&& $date['warning_count'] == 0
&& checkdate($date['month'], $date['day'], $date['year']);
}
}
60 changes: 59 additions & 1 deletion tests/ArrTest.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

use HiFolks\DataType\Arr;
namespace HiFolks\DataType;

it('is Array', function () {
$arr = Arr::make();
Expand Down Expand Up @@ -625,3 +625,61 @@
expect($result->length())->toEqual(4);
expect($result->arr())->toEqual([2, 4, 6, 8]);
});

it('tests setLocaleString() returns an empty string for empty array', function () {
$arr = Arr::make([]);

$result = $arr->toLocaleString();
expect($result)
->toBeString()
->toEqual('');
});

it("tests setLocaleString() returns a string representing the elements of the array", function () {
$arr = Arr::make(['🥝', '🍎', 'I_DONT_KNOW', 1, 2, 3]);

$result = $arr->toLocaleString(); // 'en_US', 'UTC'
expect($result)
->toBeString()
->toEqual('🥝,🍎,I_DONT_KNOW,1,2,3');
});

it("tests setLocaleString() transforms dates and numbers using default locale and timezone", function () {
$arr = Arr::make([-123897.23, +123456.03, 'a', '2022-10-01']);

$result = $arr->toLocaleString(); // 'en_US', 'UTC'
expect($result)
->toBeString()
->toEqual('-123,897.23,123,456.03,a,Sat 01 Oct 2022 12:00:00 AM UTC');
});

it("tests setLocaleString() transforms dates and numbers using provided locale and timezone when available", function () {
$arr = Arr::make([-123897.23, +123456.03, 'a', '2022-10-01']);

$envLocale = setlocale(LC_ALL, 'fr_FR.utf8');
$result = $arr->toLocaleString('fr_FR', 'Europe/Paris');

if ($envLocale) {
expect($result)
->toBeString()
->toEqual('-123 897,23,123 456,03,a,sam. 01 oct. 2022 00:00:00');
}
});

it("tests setLocaleString() transforms dates and numbers using default locale if provided locale is not available", function () {
$arr = Arr::make([-123897.23, +123456.03, 'a', '2022-10-01']);

$result = $arr->toLocaleString('foo_BAR', 'Europe/Paris');
expect($result)
->toBeString()
->toEqual('-123,897.23,123,456.03,a,Sat 01 Oct 2022 12:00:00 AM CEST');
});

it("tests setLocaleString() skips nulls and invalid dates", function () {
$arr = Arr::make(['product', 123456.4, null, '2020-14-14']);

$result = $arr->toLocaleString();
expect($result)
->toBeString()
->toEqual('product,123,456.40,,2020-14-14');
});