src/Country.php
<?php
declare(strict_types=1);
namespace Rinvex\Country;
use Locale;
use Exception;
use DateTimeZone;
use ResourceBundle;
class Country
{
/**
* The attributes array.
*
* @var array
*/
protected $attributes;
/**
* Create a new Country instance.
*
* @param array $attributes
*
* @throws \Exception
*/
public function __construct($attributes)
{
// Set the attributes
$this->setAttributes($attributes);
// Check required mandatory attributes
if (empty($this->getName()) || empty($this->getOfficialName())
|| empty($this->getNativeName()) || empty($this->getNativeOfficialName())
|| empty($this->getIsoAlpha2()) || empty($this->getIsoAlpha3())) {
throw new Exception('Missing mandatory country attributes!');
}
}
/**
* Set the attributes.
*
* @param array $attributes
*
* @return $this
*/
public function setAttributes($attributes)
{
$this->attributes = $attributes;
return $this;
}
/**
* Get the attributes.
*
* @return array|null
*/
public function getAttributes(): ?array
{
return $this->attributes;
}
/**
* Set single attribute.
*
* @param string $key
* @param mixed $value
*
* @return $this
*/
public function set($key, $value)
{
$this->attributes[$key] = $value;
return $this;
}
/**
* Get an item from attributes array using "dot" notation.
*
* @param string $key
* @param mixed $default
*
* @return mixed
*/
public function get($key, $default = null)
{
$array = $this->attributes;
if (is_null($key)) {
return $array;
}
if (array_key_exists($key, $array)) {
return $array[$key] ?? $default;
}
foreach (explode('.', $key) as $segment) {
if (is_array($array) && array_key_exists($segment, $array)) {
$array = $array[$segment];
} else {
return $default;
}
}
return $array;
}
/**
* Get the common name.
*
* @return string|null
*/
public function getName(): ?string
{
return $this->get('name.common') ?: $this->get('name');
}
/**
* Get the official name.
*
* @return string|null
*/
public function getOfficialName(): ?string
{
return $this->get('name.official') ?: $this->get('official_name');
}
/**
* Get the given native name or fallback to first native name.
*
* @param string|null $languageCode
*
* @return string|null
*/
public function getNativeName($languageCode = null): ?string
{
$languageCode = $languageCode ? mb_strtolower($languageCode) : null;
return $this->get("name.native.{$languageCode}.common")
?? (current($this->get('name.native', []))['common'] ?? $this->get('native_name'));
}
/**
* Get the given native official name or fallback to first native official name.
*
* @param string|null $languageCode
*
* @return string|null
*/
public function getNativeOfficialName($languageCode = null): ?string
{
$languageCode = $languageCode ? mb_strtolower($languageCode) : null;
return $this->get("name.native.{$languageCode}.official")
?? (current($this->get('name.native', []))['official'] ?? $this->get('native_official_name'));
}
/**
* Get the native names.
*
* @return array|null
*/
public function getNativeNames(): ?array
{
return $this->get('name.native');
}
/**
* Get the demonym.
*
* @return string|null
*/
public function getDemonym(): ?string
{
return $this->get('demonym');
}
/**
* Get the capital.
*
* @return string|null
*/
public function getCapital(): ?string
{
return $this->get('capital');
}
/**
* Get the ISO 3166-1 alpha2.
*
* @return string|null
*/
public function getIsoAlpha2()
{
return $this->get('iso_3166_1_alpha2');
}
/**
* Get the ISO 3166-1 alpha3.
*
* @return string|null
*/
public function getIsoAlpha3()
{
return $this->get('iso_3166_1_alpha3');
}
/**
* Get the ISO 3166-1 numeric.
*
* @return string|null
*/
public function getIsoNumeric(): ?string
{
return $this->get('iso_3166_1_numeric');
}
/**
* Get the given currency or fallback to first currency.
*
* @param string|null $currency
*
* @return array|null
*/
public function getCurrency($currency = null): ?array
{
$currency = $currency ? mb_strtoupper($currency) : null;
return $this->get("currency.{$currency}") ?: (current($this->get('currency', [])) ?: null);
}
/**
* Get the currencies.
*
* @return array|null
*/
public function getCurrencies(): ?array
{
return $this->get('currency');
}
/**
* Get the TLD.
*
* @return string|null
*/
public function getTld(): ?string
{
return current($this->get('tld', [])) ?: null;
}
/**
* Get the TLDs.
*
* @return array|null
*/
public function getTlds(): ?array
{
return $this->get('tld');
}
/**
* Get the alternative spellings.
*
* @return array|null
*/
public function getAltSpellings(): ?array
{
return $this->get('alt_spellings');
}
/**
* Get the given language or fallback to first language.
*
* @param string|null $languageCode
*
* @return string|null
*/
public function getLanguage($languageCode = null): ?string
{
$languageCode = $languageCode ? mb_strtolower($languageCode) : null;
return $this->get("languages.{$languageCode}") ?: (current($this->get('languages', [])) ?: null);
}
/**
* Get the languages.
*
* @return array|null
*/
public function getLanguages(): ?array
{
return $this->get('languages');
}
/**
* Get the translations.
*
* @return array
*/
public function getTranslations(): array
{
// Get english name
$name = [
'eng' => [
'common' => $this->getName(),
'official' => $this->getOfficialName(),
],
];
// Get native names
$natives = $this->getNativeNames() ?: [];
// Get other translations
$file = __DIR__.'/../resources/translations/'.mb_strtolower($this->getIsoAlpha2()).'.json';
$translations = file_exists($file) ? json_decode(file_get_contents($file), true) : [];
// Merge all names together
$result = array_merge($translations, $natives, $name);
// Sort alphabetically
ksort($result);
return $result;
}
/**
* Get the translation.
*
* @param string|null $languageCode
*
* @return array
*/
public function getTranslation($languageCode = null): array
{
return $this->getTranslations()[$languageCode] ?? current($this->getTranslations());
}
/**
* Get the geodata.
*
* @return array|null
*/
public function getGeodata(): ?array
{
return $this->get('geo');
}
/**
* Get the continent.
*
* @return string|null
*/
public function getContinent(): ?string
{
return current($this->get('geo.continent', [])) ?: null;
}
/**
* Determine whether the country uses postal code.
*
* @return bool|null
*/
public function usesPostalCode()
{
return $this->get('geo.postal_code');
}
/**
* Get the latitude.
*
* @return string|null
*/
public function getLatitude(): ?string
{
return $this->get('geo.latitude');
}
/**
* Get the longitude.
*
* @return string|null
*/
public function getLongitude(): ?string
{
return $this->get('geo.longitude');
}
/**
* Get the described latitude.
*
* @return string|null
*/
public function getLatitudeDesc(): ?string
{
return $this->get('geo.latitude_desc');
}
/**
* Get the described longitude.
*
* @return string|null
*/
public function getLongitudeDesc(): ?string
{
return $this->get('geo.longitude_desc');
}
/**
* Get the maximum latitude.
*
* @return string|null
*/
public function getMaxLatitude(): ?string
{
return $this->get('geo.max_latitude');
}
/**
* Get the maximum longitude.
*
* @return string|null
*/
public function getMaxLongitude(): ?string
{
return $this->get('geo.max_longitude');
}
/**
* Get the minimum latitude.
*
* @return string|null
*/
public function getMinLatitude(): ?string
{
return $this->get('geo.min_latitude');
}
/**
* Get the minimum longitude.
*
* @return string|null
*/
public function getMinLongitude(): ?string
{
return $this->get('geo.min_longitude');
}
/**
* Get the area.
*
* @return int|null
*/
public function getArea(): ?int
{
return $this->get('geo.area');
}
/**
* Get the region.
*
* @return string|null
*/
public function getRegion(): ?string
{
return $this->get('geo.region');
}
/**
* Get the subregion.
*
* @return string|null
*/
public function getSubregion(): ?string
{
return $this->get('geo.subregion');
}
/**
* Get the world region.
*
* @return string|null
*/
public function getWorldRegion(): ?string
{
return $this->get('geo.world_region');
}
/**
* Get the region code.
*
* @return string|null
*/
public function getRegionCode(): ?string
{
return $this->get('geo.region_code');
}
/**
* Get the subregion code.
*
* @return string|null
*/
public function getSubregionCode(): ?string
{
return $this->get('geo.subregion_code');
}
/**
* Check the landlock status.
*
* @return bool|null
*/
public function isLandlocked()
{
return $this->get('geo.landlocked');
}
/**
* Get the borders.
*
* @return array|null
*/
public function getBorders(): ?array
{
return $this->get('geo.borders');
}
/**
* Determine whether the country is independent.
*
* @return string|null
*/
public function isIndependent(): ?string
{
return $this->get('geo.independent');
}
/**
* Get the given calling code or fallback to first calling code.
*
* @return string|null
*/
public function getCallingCode(): ?string
{
return current($this->get('dialling.calling_code', [])) ?: (current($this->get('calling_code', [])) ?: null);
}
/**
* Get the calling codes.
*
* @return array|null
*/
public function getCallingCodes(): ?array
{
return $this->get('dialling.calling_code');
}
/**
* Get the national prefix.
*
* @return string|null
*/
public function getNationalPrefix(): ?string
{
return $this->get('dialling.national_prefix');
}
/**
* Get the national number length.
*
* @return int|null
*/
public function getNationalNumberLength(): ?int
{
return current($this->get('dialling.national_number_lengths', [])) ?: null;
}
/**
* Get the national number lengths.
*
* @return array|null
*/
public function getNationalNumberLengths(): ?array
{
return $this->get('dialling.national_number_lengths');
}
/**
* Get the national destination code length.
*
* @return int|null
*/
public function getNationalDestinationCodeLength(): ?int
{
return current($this->get('dialling.national_destination_code_lengths', [])) ?: null;
}
/**
* Get the national destination code lengths.
*
* @return array|null
*/
public function getnationaldestinationcodelengths(): ?array
{
return $this->get('dialling.national_destination_code_lengths');
}
/**
* Get the international prefix.
*
* @return string|null
*/
public function getInternationalPrefix(): ?string
{
return $this->get('dialling.international_prefix');
}
/**
* Get the extras.
*
* @return array|null
*/
public function getExtra(): ?array
{
return $this->get('extra');
}
/**
* Get the geonameid.
*
* @return int|null
*/
public function getGeonameid(): ?int
{
return $this->get('extra.geonameid');
}
/**
* Get the edgar code.
*
* @return string|null
*/
public function getEdgar(): ?string
{
return $this->get('extra.edgar');
}
/**
* Get the itu code.
*
* @return string|null
*/
public function getItu(): ?string
{
return $this->get('extra.itu');
}
/**
* Get the marc code.
*
* @return string|null
*/
public function getMarc(): ?string
{
return $this->get('extra.marc');
}
/**
* Get the wmo code.
*
* @return string|null
*/
public function getWmo(): ?string
{
return $this->get('extra.wmo');
}
/**
* Get the ds code.
*
* @return string|null
*/
public function getDs(): ?string
{
return $this->get('extra.ds');
}
/**
* Get the fifa code.
*
* @return string|null
*/
public function getFifa(): ?string
{
return $this->get('extra.fifa');
}
/**
* Get the fips code.
*
* @return string|null
*/
public function getFips(): ?string
{
return $this->get('extra.fips');
}
/**
* Get the gaul code.
*
* @return int|null
*/
public function getGaul(): ?int
{
return $this->get('extra.gaul');
}
/**
* Get the ioc code.
*
* @return string|null
*/
public function getIoc(): ?string
{
return $this->get('extra.ioc');
}
/**
* Get the cowc code.
*
* @return string|null
*/
public function getCowc(): ?string
{
return $this->get('extra.cowc');
}
/**
* Get the cown code.
*
* @return int|null
*/
public function getCown(): ?int
{
return $this->get('extra.cown');
}
/**
* Get the fao code.
*
* @return int|null
*/
public function getFao(): ?int
{
return $this->get('extra.fao');
}
/**
* Get the imf code.
*
* @return int|null
*/
public function getImf(): ?int
{
return $this->get('extra.imf');
}
/**
* Get the ar5 code.
*
* @return string|null
*/
public function getAr5()
{
return $this->get('extra.ar5');
}
/**
* Get the address format.
*
* @return string|null
*/
public function getAddressFormat(): ?string
{
return $this->get('extra.address_format');
}
/**
* Determine whether the country is EU member.
*
* @return bool|null
*/
public function isEuMember()
{
return $this->get('extra.eu_member');
}
/**
* Determine whether the country has data protection.
*
* @return string|null
*/
public function getDataProtection()
{
return $this->get('extra.data_protection');
}
/**
* Get the VAT rates.
*
* @return array|null
*/
public function getVatRates(): ?array
{
return $this->get('extra.vat_rates');
}
/**
* Get the emoji.
*
* @return string|null
*/
public function getEmoji(): ?string
{
return $this->get('extra.emoji') ?: $this->get('emoji');
}
/**
* Get the geographic data structure.
*
* @return string|null
*/
public function getGeoJson(): ?string
{
if (! ($code = $this->getIsoAlpha2())) {
return null;
}
return file_exists($file = __DIR__.'/../resources/geodata/'.mb_strtolower($code).'.json') ? file_get_contents($file) : null;
}
/**
* Get the flag.
*
* @return string|null
*/
public function getFlag(): ?string
{
if (! ($code = $this->getIsoAlpha2())) {
return null;
}
return file_exists($file = __DIR__.'/../resources/flags/'.mb_strtolower($code).'.svg') ? file_get_contents($file) : null;
}
/**
* Get the divisions.
*
* @return array|null
*/
public function getDivisions(): ?array
{
if (! ($code = $this->getIsoAlpha2())) {
return null;
}
return file_exists($file = __DIR__.'/../resources/divisions/'.mb_strtolower($code).'.json') ? json_decode(file_get_contents($file), true) : null;
}
/**
* Get the divisions.
*
* @param string $division
*
* @return array|null
*/
public function getDivision($division): ?array
{
return ! empty($this->getDivisions()) && isset($this->getDivisions()[$division])
? $this->getDivisions()[$division] : null;
}
/**
* Get the timezones.
*
* @return array|null
*/
public function getTimezones()
{
if (! ($code = $this->getIsoAlpha2())) {
return;
}
return DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $code);
}
/**
* Get the locales.
*
* @return array|null
*/
public function getLocales()
{
if (! ($code = $this->getIsoAlpha2())) {
return;
}
$locales = [];
foreach (ResourceBundle::getLocales('') as $localeCode) {
if ($code === Locale::getRegion($localeCode)) {
$locales[] = $localeCode;
}
}
return $locales;
}
}