Appearance
Geolocation & Shipping Zones
Flow ID: SY-20 | Module(s): eshop, core | Complexity: Medium Last Updated: 2026-04-04
Business Overview
The geolocation and shipping zones system manages country and county/region data used throughout the platform for address forms, transporter availability, checkout shipping calculations, and store location display. The AdvCountriesCounties library loads all geographic data at controller initialization and provides it as structured lookups for both the storefront and admin panel.
What the system provides:
- Country and county data with multi-language support (MUI)
- Filtered views based on registry-configured available countries
- Dropdown-ready data for address forms (countries, counties, phone codes)
- Integration with transporter availability checks
- PSCache for query performance
Where it is used:
- Checkout address forms (shipping and billing)
- Admin order management (address display and editing)
- Transporter availability calculations
- Store location labeling
- Reporting filters
Architecture
AdvCountriesCounties (Library)
|
+--> constructor -> initializeData()
|
+--> Load models: country_model, county_model
+--> Load registry
+--> Read AVAILABLE_COUNTRIES from registry (pipe-delimited array)
+--> PSCache: country_model::countries($countryCodes) -> setUpCountries()
+--> PSCache: county_model::counties() -> setUpCounties()
+--> countries() all countries indexed by alpha_2
+--> availableCountries() filtered by AVAILABLE_COUNTRIES registry
+--> countriesDropDown($lang) {alpha_2 => name} for select elements
+--> availableCountriesDropDown() filtered dropdown
+--> countiesDropDown($lang) {country => {county_alpha => name}} nested
+--> availableCountiesDropDown() filtered nested dropdown
+--> phoneCodes() {alpha_2 => phone_code}
+--> availablePhoneCodes() filtered phone codes
+--> getCountryRawDataCodes() raw country object by alpha_2
+--> getCountyRawDataCodes() raw county object by county_alpha (searches all countries)Core Classes
| Class | File | Purpose |
|---|---|---|
AdvCountriesCounties | ecommercen/libraries/AdvCountriesCounties.php | Base library with all lookup methods |
CountriesCounties | application/libraries/CountriesCounties.php | Client-overridable subclass |
Adv_country_model | ecommercen/eshop/models/Adv_country_model.php | Country database queries |
Country_model | application/modules/eshop/models/Country_model.php | Client-overridable country model |
Adv_county_model | ecommercen/eshop/models/Adv_county_model.php | County database queries |
County_model | application/modules/eshop/models/County_model.php | Client-overridable county model |
Instantiation
The library is instantiated in both base controllers, making it available on every page:
php
// In Adv_front_controller constructor:
$this->countriesCounties = new CountriesCounties();
// In Adv_admin_controller constructor:
$this->countriesCounties = new CountriesCounties();Code Flow
1. Initialization
initializeData() runs in the constructor:
- Load models:
country_modelandcounty_model - Load registry library
- Read available countries:
registry->getArray('AVAILABLE_COUNTRIES', 'ESHOP', '')returns an array like['GR', 'CY', 'DE'] - Flip to lookup:
array_flip($countries)for O(1) availability checks - Load countries via PSCache:
pscache->model('country_model', 'countries', [[], $countries], $ttl)-- fetches all countries filtered by available codes, with L2 cache TTL - Load counties via PSCache:
pscache->model('county_model', 'counties', [], $ttl)-- fetches all counties
2. Country Data Structure
setUpCountries() processes the flat query result into a structured format:
countries['GR'] = {
alpha_2: 'GR',
alpha_3: 'GRC',
iso_cc: 300,
phone_code: '+30',
captions: {
el: 'Ελλάδα',
en: 'Greece',
de: 'Griechenland'
}
}Each country row from the MUI join produces one language entry in captions. The lang and name properties are removed after merging into captions.
3. County Data Structure
setUpCounties() nests counties under their parent country:
counties['GR']['AT'] = {
country_alpha_2: 'GR',
county_alpha: 'AT',
captions: {
el: 'Αττική',
en: 'Attica'
}
}4. Dropdown Methods
All dropdown methods return simple key-value arrays suitable for HTML <select> elements:
countriesDropDown($lang):['GR' => 'Greece', 'CY' => 'Cyprus', ...]countiesDropDown($lang):['GR' => ['AT' => 'Attica', 'TH' => 'Thessaloniki', ...], ...]phoneCodes():['GR' => '+30', 'CY' => '+357', ...]
The "available" variants filter by the AVAILABLE_COUNTRIES registry setting.
5. County Ordering
Counties are ordered by a configurable priority list (counties_order config item) in descending FIELD() order, then alphabetically by name. This allows merchants to put their most common delivery regions first.
Data Model
Table: country
| Column | Type | Role |
|---|---|---|
alpha_2 | char(2) | PK, ISO 3166-1 alpha-2 code (e.g., GR) |
alpha_3 | char(3) | ISO 3166-1 alpha-3 code (e.g., GRC) |
iso_cc | int | ISO 3166-1 numeric code |
phone_code | varchar | International dialing code (e.g., +30) |
Table: country_mui
| Column | Type | Role |
|---|---|---|
alpha_2 | char(2) | FK to country.alpha_2 |
lang | varchar | Language code |
name | varchar | Country name in specified language |
Table: county
| Column | Type | Role |
|---|---|---|
county_alpha | varchar | PK, region/county code (e.g., AT for Attica) |
country_alpha_2 | char(2) | FK to country.alpha_2 |
Table: county_mui
| Column | Type | Role |
|---|---|---|
county_alpha | varchar | FK to county.county_alpha |
lang | varchar | Language code |
county_name | varchar | County name in specified language |
Configuration
Registry Settings
| Group | Key | Purpose |
|---|---|---|
ESHOP | AVAILABLE_COUNTRIES | Pipe-delimited list of enabled country alpha_2 codes (e.g., GR|CY|DE) |
Application Config
| Config item | Purpose |
|---|---|
cache_l2_default_expires | PSCache TTL for geographic data queries |
counties_order | Array of county codes to prioritize in dropdown ordering |
Caching
Geographic data is cached via PSCache at two levels:
- Country data:
pscache->model('country_model', 'countries', ...)with L2 TTL - County data:
pscache->model('county_model', 'counties', ...)with L2 TTL
Cache is automatically refreshed when TTL expires. No manual cache invalidation is needed for geographic data changes (though PSCache can be cleared if immediate updates are required).
Client Extension Points
Override the library: Create
CountriesCountiesinapplication/libraries/extendingAdvCountriesCounties. Override methods to add custom filtering (e.g., exclude counties not served by the merchant's transporters).Override country model: Extend
Country_modelto add custom ordering or filtering logic (e.g., priority sort for primary market).Override county model: Extend
County_modelto add custom county data or override the ordering.Configure available countries: Update
ESHOP.AVAILABLE_COUNTRIESin the registry via admin settings to control which countries appear in checkout forms and transporter calculations.Configure county ordering: Set
counties_orderinapplication/config/app.phpto prioritize specific regions in dropdowns.Store label customization: The
buildStoreLabel()helper inecommercen/helpers/store_helper.phpusesCountriesCountiesfor address formatting. Override the pattern parameter to change store address display.
Business Rules
| Rule | Description |
|---|---|
| Available-country filtering | Only countries listed in ESHOP.AVAILABLE_COUNTRIES registry appear in checkout and transporter checks |
| Multi-language captions | Country and county names are stored per language; the $lang parameter selects the display language |
| English fallback | Dropdown methods fall back to English (en) when a requested language caption is not available |
| Eager loading | All geographic data is loaded once per request in the controller constructor -- no lazy loading |
| PSCache performance | Database queries are cached via PSCache to avoid per-request database hits |
| Universal availability | The library is instantiated in both front and admin base controllers, making it available on every page load |
| County nesting | Counties are always accessed through their parent country code, supporting multiple countries with overlapping region names |
Related Flows
- CF-06 Order Preview -- address forms use country/county dropdowns
- CF-07 Order Confirmation -- shipping address validation
- AD-06 Transporter Admin -- transporter availability zones use country/county data
- AD-18 Store Management -- store address labeling via
buildStoreLabel() - SY-19 Config Registry --
AVAILABLE_COUNTRIESconfiguration