added countries support expanded for ISO 3166 standard
This commit is contained in:
@@ -4,17 +4,49 @@ namespace Modules\Countries\Support;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Modules\Countries\Models\Country;
|
||||
use Modules\Countries\Models\CountrySubdivision;
|
||||
|
||||
class CountryRepository
|
||||
{
|
||||
/**
|
||||
* Active countries for form selects.
|
||||
*
|
||||
* @return Collection<int, Country>
|
||||
*/
|
||||
public function activeForSelect(): Collection
|
||||
{
|
||||
return Country::query()->active()->ordered()
|
||||
->get(['id', 'alpha2', 'alpha3', 'numeric', 'name', 'display_name', 'common_name', 'flag_emoji']);
|
||||
->get(['id', 'alpha2', 'alpha3', 'numeric', 'name', 'display_name', 'common_name', 'flag_emoji', 'region', 'subregion']);
|
||||
}
|
||||
|
||||
public function findByAlpha2(string $alpha2): ?Country
|
||||
{
|
||||
return Country::query()->where('alpha2', strtoupper($alpha2))->first();
|
||||
return Country::query()->where('alpha2', Iso3166::normaliseAlpha2($alpha2))->first();
|
||||
}
|
||||
|
||||
public function findByIsoCode(string $code): ?Country
|
||||
{
|
||||
return Country::query()->forIsoCode($code)->first();
|
||||
}
|
||||
|
||||
public function findSubdivision(string $code): ?CountrySubdivision
|
||||
{
|
||||
return CountrySubdivision::query()->where('code', strtoupper(trim($code)))->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Active subdivisions for a country select.
|
||||
*
|
||||
* @return Collection<int, CountrySubdivision>
|
||||
*/
|
||||
public function activeSubdivisionsForCountry(string $alpha2): Collection
|
||||
{
|
||||
$alpha2 = Iso3166::normaliseAlpha2($alpha2);
|
||||
|
||||
return CountrySubdivision::query()
|
||||
->where('country_alpha2', $alpha2)
|
||||
->active()
|
||||
->ordered()
|
||||
->get(['id', 'country_alpha2', 'code', 'subdivision_code', 'name', 'local_name', 'type']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\Countries\Support;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class Iso3166
|
||||
{
|
||||
public const STATUS_OFFICIAL = 'official';
|
||||
public const STATUS_RESERVED = 'reserved';
|
||||
public const STATUS_TRANSITIONAL = 'transitional';
|
||||
public const STATUS_DELETED = 'deleted';
|
||||
public const STATUS_USER_ASSIGNED = 'user_assigned';
|
||||
public const STATUS_EXCEPTIONALLY_RESERVED = 'exceptionally_reserved';
|
||||
|
||||
/** @return list<string> */
|
||||
public static function statuses(): array
|
||||
{
|
||||
return [
|
||||
self::STATUS_OFFICIAL,
|
||||
self::STATUS_RESERVED,
|
||||
self::STATUS_TRANSITIONAL,
|
||||
self::STATUS_DELETED,
|
||||
self::STATUS_USER_ASSIGNED,
|
||||
self::STATUS_EXCEPTIONALLY_RESERVED,
|
||||
];
|
||||
}
|
||||
|
||||
public static function normaliseAlpha2(string $code): string
|
||||
{
|
||||
$normalised = strtoupper(trim($code));
|
||||
|
||||
if (! preg_match('/^[A-Z]{2}$/', $normalised)) {
|
||||
throw new InvalidArgumentException('ISO 3166-1 alpha-2 codes must contain exactly two letters.');
|
||||
}
|
||||
|
||||
return $normalised;
|
||||
}
|
||||
|
||||
public static function normaliseAlpha3(string $code): string
|
||||
{
|
||||
$normalised = strtoupper(trim($code));
|
||||
|
||||
if (! preg_match('/^[A-Z]{3}$/', $normalised)) {
|
||||
throw new InvalidArgumentException('ISO 3166-1 alpha-3 codes must contain exactly three letters.');
|
||||
}
|
||||
|
||||
return $normalised;
|
||||
}
|
||||
|
||||
public static function normaliseNumeric(string|int $code): string
|
||||
{
|
||||
$normalised = str_pad((string) $code, 3, '0', STR_PAD_LEFT);
|
||||
|
||||
if (! preg_match('/^[0-9]{3}$/', $normalised)) {
|
||||
throw new InvalidArgumentException('ISO 3166-1 numeric codes must contain exactly three digits.');
|
||||
}
|
||||
|
||||
return $normalised;
|
||||
}
|
||||
|
||||
public static function normaliseSubdivisionCode(string $countryAlpha2, string $subdivisionCode): string
|
||||
{
|
||||
$country = self::normaliseAlpha2($countryAlpha2);
|
||||
$code = strtoupper(trim($subdivisionCode));
|
||||
|
||||
if (str_starts_with($code, $country.'-')) {
|
||||
return $code;
|
||||
}
|
||||
|
||||
if (! preg_match('/^[A-Z0-9]{1,6}$/', $code)) {
|
||||
throw new InvalidArgumentException('ISO 3166-2 subdivision codes must contain 1 to 6 letters or numbers after the country prefix.');
|
||||
}
|
||||
|
||||
return $country.'-'.$code;
|
||||
}
|
||||
|
||||
public static function flagEmoji(string $alpha2): string
|
||||
{
|
||||
$alpha2 = self::normaliseAlpha2($alpha2);
|
||||
$base = 127397;
|
||||
|
||||
return mb_chr($base + ord($alpha2[0]), 'UTF-8').mb_chr($base + ord($alpha2[1]), 'UTF-8');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user