Skip to content

Commit 9234e03

Browse files
authored
[4.x] [SWP-2788] Introduce memoization for efficiency during use on mass (#44)
**Changes** - Introduced a history for finds in the CountryHelper so that we don't perform the same lookup many times - Introduced a caching layer for NumberFormatters used in the CurrencyHelper to avoid creating many unnecessary instances when used on mass
1 parent 5c53b23 commit 9234e03

9 files changed

Lines changed: 104 additions & 27 deletions

.styleci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
preset: laravel
2+
enabled:
3+
- concat_with_spaces
4+
disabled:
5+
- concat_without_spaces

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to `pod-point/countries` will be documented in this file.
44

5+
## 5.0.1 - 2021-05-19
6+
7+
* [SWP-2788](https://podpoint.atlassian.net/browse/SWP-2788) Introduce memoization for efficiency during use on mass
8+
* Introduced a history for finds in the `CountryHelper` so that we don't perform the same lookup many times
9+
* Introduced a caching layer for `NumberFormatters` used in the `CurrencyHelper` to avoid creating many unnecessary instances when used on mass
10+
511
## 5.0.0 - 2021-05-18
612

713
* Major release to support PHP 7.3+ and Laravel 7.x+
@@ -18,6 +24,12 @@ All notable changes to `pod-point/countries` will be documented in this file.
1824

1925
* This package can no longer support PHP7.2 - if using PHP7.2 please use version 4.*.
2026

27+
## 4.0.2 - 2021-05-19
28+
29+
* [SWP-2788](https://podpoint.atlassian.net/browse/SWP-2788) Introduce memoization for efficiency during use on mass
30+
* Introduced a history for finds in the `CountryHelper` so that we don't perform the same lookup many times
31+
* Introduced a caching layer for `NumberFormatters` used in the `CurrencyHelper` to avoid creating many unnecessary instances when used on mass
32+
2133
## 4.0.1 - 2021-05-18
2234

2335
* Implement Laravel Auto-Discovery
@@ -38,6 +50,17 @@ All notable changes to `pod-point/countries` will be documented in this file.
3850

3951
* This package can no longer support PHP7.1 - if using PHP7.1 please use version 3.*.
4052

53+
## 3.1.3 - 2021-05-19
54+
55+
* [SWP-2788](https://podpoint.atlassian.net/browse/SWP-2788) Introduce memoization for efficiency during use on mass
56+
* Introduced a history for finds in the `CountryHelper` so that we don't perform the same lookup many times
57+
* Introduced a caching layer for `NumberFormatters` used in the `CurrencyHelper` to avoid creating many unnecessary instances when used on mass
58+
59+
## 3.1.2 - 2021-05-18
60+
61+
* Minor modernisations
62+
* Moved from Travis CI to Github Actions
63+
4164
## 3.1.1 - 2020-11-05
4265

4366
* `getSystemLocale` in `LocalizedHelper` now returns the fallback locale if the given one is not found. This created issues with some tests because NumberFormatter becomes system dependent if null is given.

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ For Laravel 7.x or 8.x and PHP >= 7.3
3131
composer require pod-point/countries:^5.0
3232
```
3333

34-
Then finally, if you're using a Laravel version which doesn't support Auto Discovery, add the service provider to your `config/app.php` providers array:
34+
Then, finally, if you're using a Laravel version which doesn't support Auto Discovery, add the service provider to your `config/app.php` providers array:
3535

3636
```php
3737
'providers' => [
@@ -49,9 +49,9 @@ $app->register(PodPoint\I18n\CountriesServiceProvider::class);
4949

5050
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
5151

52-
## License
52+
## Licence
5353

54-
The MIT License (MIT). Please see [License File](LICENCE.md) for more information.
54+
The MIT Licence (MIT). Please see [Licence File](LICENCE.md) for more information.
5555

5656
---
5757

src/CountriesServiceProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protected function mergeConfig()
3636
'countries-partial',
3737
])->each(function ($key) {
3838
$this->app->config->set($key, array_merge(
39-
require __DIR__."/../config/$key.php",
39+
require __DIR__ . "/../config/$key.php",
4040
$this->app->config->get($key, [])
4141
));
4242
});

src/CountryHelper.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
class CountryHelper extends Helper
66
{
7+
/**
8+
* Recent lookup results by `property-value`.
9+
*
10+
* @var array
11+
*/
12+
protected $results = [];
13+
714
/**
815
* Returns the first country matching the given property/value pair.
916
*
@@ -14,7 +21,13 @@ class CountryHelper extends Helper
1421
*/
1522
public function findBy(string $property, $value): ?array
1623
{
17-
return collect($this->config->get('countries'))
24+
$key = $this->generateResultsKey($property, $value);
25+
26+
if ($this->results[$key] ?? false) {
27+
return $this->results[$key];
28+
}
29+
30+
return $this->results[$key] = collect($this->config->get('countries'))
1831
->where($property, $value)
1932
->first();
2033
}
@@ -45,4 +58,16 @@ public function getCountryCodeFromLocale(string $locale): ?string
4558

4659
return $code ? $code : null;
4760
}
61+
62+
/**
63+
* Generate a string formed of the property and value for the results cache.
64+
*
65+
* @param string $property
66+
* @param string $value
67+
* @return string
68+
*/
69+
protected function generateResultsKey(string $property, string $value): string
70+
{
71+
return "${property}-{$value}";
72+
}
4873
}

src/CurrencyHelper.php

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,29 @@
66

77
class CurrencyHelper extends LocalizedHelper
88
{
9+
/**
10+
* Number Formatters created per locale.
11+
*
12+
* @var array
13+
*/
14+
protected $localizedFormatters = [];
15+
916
/**
1017
* Return a value in the given currency formatted for the given locale.
1118
*
1219
* @param float|int $value
1320
* @param string $currencyCode
1421
* @param string $locale
22+
* @return string
1523
*
1624
* @deprecated toStandardFormat should be used.
17-
* @return string
1825
*/
1926
public function toFormat(
2027
$value,
2128
string $currencyCode = CurrencyCode::POUND_STERLING,
2229
string $locale = 'en'
2330
): string {
24-
$formatter = new NumberFormatter(
25-
$this->getSystemLocale($locale),
26-
NumberFormatter::CURRENCY
27-
);
31+
$formatter = $this->getFormatter($locale);
2832

2933
/*
3034
* NumberFormatter will round up with 2 decimals only by default.
@@ -71,10 +75,7 @@ public function formatToMinorUnitWhenApplicable(
7175
$pattern = $this->getMinorUnitPattern($locale);
7276

7377
if ($value <= $this->getMinorUnitEnd($locale) && $pattern) {
74-
$formatter = new NumberFormatter(
75-
$this->getSystemLocale($locale),
76-
NumberFormatter::CURRENCY
77-
);
78+
$formatter = $this->getFormatter($locale);
7879

7980
$formatter->setPattern($pattern);
8081

@@ -94,10 +95,7 @@ public function formatToMinorUnitWhenApplicable(
9495
*/
9596
public function getSymbol(string $currencyCode = CurrencyCode::POUND_STERLING, string $locale = 'en'): string
9697
{
97-
$formatter = new NumberFormatter(
98-
"{$this->getSystemLocale($locale)}@currency={$currencyCode}",
99-
NumberFormatter::CURRENCY
100-
);
98+
$formatter = $this->getFormatter($locale);
10199

102100
return $formatter->getSymbol(NumberFormatter::CURRENCY_SYMBOL);
103101
}
@@ -119,7 +117,7 @@ public function toStandardFormat(
119117
string $locale = 'en',
120118
$precision = null
121119
): string {
122-
$formatter = new NumberFormatter($this->getSystemLocale($locale), NumberFormatter::CURRENCY);
120+
$formatter = $this->getFormatter($locale);
123121

124122
if (is_int($precision)) {
125123
$formatter->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $precision);
@@ -128,4 +126,31 @@ public function toStandardFormat(
128126

129127
return $formatter->formatCurrency($value, $currencyCode);
130128
}
129+
130+
/**
131+
* Get an instance of a localized Formatter.
132+
*
133+
* @param string $locale
134+
* @return NumberFormatter
135+
*/
136+
protected function getFormatter(string $locale): NumberFormatter
137+
{
138+
return $this->localizedFormatters[$locale]
139+
?? $this->setFormatter(
140+
$locale,
141+
new NumberFormatter($this->getSystemLocale($locale), NumberFormatter::CURRENCY)
142+
);
143+
}
144+
145+
/**
146+
* Set an instance of a localized Formatter.
147+
*
148+
* @param string $locale
149+
* @param NumberFormatter $formatter
150+
* @return NumberFormatter
151+
*/
152+
public function setFormatter(string $locale, NumberFormatter $formatter): NumberFormatter
153+
{
154+
return $this->localizedFormatters[$locale] = $formatter;
155+
}
131156
}

src/ViewComposers/CountryCodeViewComposer.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ private function countryLabel(string $countryCode, string $countryName, $diallin
124124
*/
125125
private function countryNameMarkup(string $name, bool $defaultChoice = false): string
126126
{
127-
return '&nbsp;<span class="country-name'.($defaultChoice ? ' country-name--heading' : '').'">'.$name.'</span>';
127+
return '&nbsp;<span class="country-name' . ($defaultChoice ? ' country-name--heading' : '') . '">' . $name . '</span>';
128128
}
129129

130130
/**
@@ -141,7 +141,7 @@ private function dialingCodeMarkup(?int $diallingCode = null, bool $defaultChoic
141141
return '';
142142
}
143143

144-
return '&nbsp;<span class="country-dialling-code'.($defaultChoice ? ' country-dialling-code--heading' : '').'">(+'.$diallingCode.')</span>';
144+
return '&nbsp;<span class="country-dialling-code' . ($defaultChoice ? ' country-dialling-code--heading' : '') . '">(+' . $diallingCode . ')</span>';
145145
}
146146

147147
/**
@@ -203,7 +203,7 @@ private function unicodeCharacter(string $letter): string
203203
$letter = strtolower($letter);
204204

205205
if (array_key_exists($letter, $codes)) {
206-
return mb_convert_encoding('&#x'.$codes[$letter].';', 'UTF-8', 'HTML-ENTITIES');
206+
return mb_convert_encoding('&#x' . $codes[$letter] . ';', 'UTF-8', 'HTML-ENTITIES');
207207
}
208208

209209
return '';

tests/TestCase.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ public function loadConfiguration()
3838

3939
try {
4040
$this->app->config = new Repository([
41-
'countries' => $filesystem->getRequire(__DIR__.'/../src/config/countries.php'),
42-
'countries-partial' => $filesystem->getRequire(__DIR__.'/../src/config/countries-partial.php'),
41+
'countries' => $filesystem->getRequire(__DIR__ . '/../src/config/countries.php'),
42+
'countries-partial' => $filesystem->getRequire(__DIR__ . '/../src/config/countries-partial.php'),
4343
]);
4444
} catch (FileNotFoundException $e) {
4545
exit("Package configuration files not found: {$e->getMessage()}");

tests/Unit/CountriesServiceProviderTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function testCountriesConfigIsEnhancedWithAdditionalInfo()
2929
{
3030
$this->loadConfiguration();
3131

32-
$countryWithBasicInfo = $this->app->config->get('countries.'.CountryCode::UNITED_KINGDOM);
32+
$countryWithBasicInfo = $this->app->config->get('countries.' . CountryCode::UNITED_KINGDOM);
3333

3434
$this->assertArrayHasKey('name', $countryWithBasicInfo);
3535
$this->assertArrayHasKey('diallingCode', $countryWithBasicInfo);
@@ -46,8 +46,8 @@ public function testCountriesConfigIsEnhancedWithAdditionalInfo()
4646
$this->loadServiceProvider();
4747

4848
collect([
49-
$this->app->config->get('countries.'.CountryCode::UNITED_KINGDOM),
50-
$this->app->config->get('countries-partial.'.CountryCode::UNITED_KINGDOM),
49+
$this->app->config->get('countries.' . CountryCode::UNITED_KINGDOM),
50+
$this->app->config->get('countries-partial.' . CountryCode::UNITED_KINGDOM),
5151
])->each(function ($enhancedCountry) {
5252
$this->assertArrayHasKey('name', $enhancedCountry);
5353
$this->assertArrayHasKey('diallingCode', $enhancedCountry);

0 commit comments

Comments
 (0)