Appearance
Country & County Management
Flow ID: AD-39 | Module(s): Country (domain layer only) | Complexity: Medium Last Updated: 2026-04-04
Business Context
Country and county (region/state) management is a pure modern domain-layer feature with no legacy admin controllers. It provides a comprehensive REST API for managing ISO-standard country records and their subdivisions (counties/regions), both with multi-language name support.
Countries use ISO 3166-1 alpha-2 codes as primary keys (e.g., "GR", "US"). Counties use a composite alpha code (e.g., "GR-A" for Attica). The data is consumed by shipping zone calculations, checkout address forms, transporter availability rules, and storefront address management.
API Reference
REST Endpoints -- Country
| Method | Path | Action | Description |
|---|---|---|---|
| GET | /rest/country/country | index | List countries (paginated) |
| GET | /rest/country/country/item | item | Get single country by filter |
| GET | /rest/country/country/{alpha2} | show | Get country by alpha-2 code |
| POST | /rest/country/country | store | Create a country |
| POST | /rest/country/country/{alpha2} | update | Update a country |
| DELETE | /rest/country/country/{alpha2} | destroy | Delete a country |
Filters: alpha2 (exact), alpha3 (exact), isoCode (exact), name.{locale} (partial via MUI) Sorts: alpha2, alpha3, isoCode, name.{locale}Relations: translations (one_to_many), counties (one_to_many)
REST Endpoints -- County
| Method | Path | Action | Description |
|---|---|---|---|
| GET | /rest/country/county | index | List counties (paginated) |
| GET | /rest/country/county/item | item | Get single county by filter |
| GET | /rest/country/county/{alpha} | show | Get county by alpha code |
| POST | /rest/country/county | store | Create a county |
| POST | /rest/country/county/{alpha} | update | Update a county |
| DELETE | /rest/country/county/{alpha} | destroy | Delete a county |
Filters: alpha (exact), countryAlpha2 (exact), name.{locale} (partial via MUI) Sorts: alpha, countryAlpha2, name.{locale}Relations: translations (one_to_many), country (belongs_to)
Legacy Admin/Storefront Routes
No legacy admin controllers exist for country management. All CRUD is done via the REST API.
Code Flow
REST Read Flow (Country)
- GET
/rest/country/country?filter[name.el]=Ελλ&with=translations,counties Controllers\Country::index()delegates toHandlesRestfulActions::index().ListRequestparses query params. Thename.{locale}filter is handled as a MUI translation filter.Service::all()builds specifications:- MUI name filters use
FilterByTranslationspecification (joins MUI table). - MUI sort uses
SortByTranslationspecification. - Standard fields use
Filterspecification.
- MUI name filters use
Repository::match()executes query againstcountrytable.WithRelationsincludestranslations(fromcountry_mui) andcounties(fromcounty).Resource::resource()transforms to JSON:alpha2,alpha3,isoCode,phoneCodeplus nested relations.
REST Write Flow (Country)
- POST
/rest/country/countrywith{ alpha2: "CY", alpha3: "CYP", isoCc: 196, phoneCode: "357", translations: [{lang: "el", name: "Kupros"}, {lang: "en", name: "Cyprus"}] }. Controllers\Country::store()->doStore()fromHandlesWriteActions.WriteService::create()constructsWriteDatafrom input, validates, inserts master record, then inserts MUI records per language fromtranslationsarray.- Returns the created entity via
Resource.
Domain Layer
Country (src/Domains/Country/Country/)
| Component | Class | Description |
|---|---|---|
| Entity | Repository\Entity | alpha_2 (PK), alpha_3, iso_cc, phone_code. Implements FilterTranslation |
| Repository | Repository\Repository | Table country, PK alpha_2 (string) |
| RepositoryConfigurator | Repository\RepositoryConfigurator | translations -> MuiRepository (ONE_TO_MANY on alpha_2), counties -> CountyRepository (ONE_TO_MANY on country_alpha_2) |
| MuiRepository | Repository\MuiRepository | Translation repository for country_mui |
| Service | Service | Read service with MUI filter/sort support |
| WriteService | WriteService | Full CRUD with MUI writes |
| WriteData | WriteData | alpha2, alpha3, isoCc, phoneCode |
| MuiWriteData | MuiWriteData | lang, name |
| Validator | Validator | Validation rules for create/update |
| FilterByTranslation | Specification\FilterByTranslation | Joins MUI table for name filtering |
| SortByTranslation | Specification\SortByTranslation | Joins MUI table for name sorting |
County (src/Domains/Country/County/)
| Component | Class | Description |
|---|---|---|
| Entity | Repository\Entity | county_alpha (PK, string), country_alpha_2 (FK). Implements FilterTranslation |
| Repository | Repository\Repository | Table county, PK county_alpha (string) |
| RepositoryConfigurator | Repository\RepositoryConfigurator | translations -> MuiRepository, country -> CountryRepository (BELONGS_TO on country_alpha_2) |
| MuiRepository | Repository\MuiRepository | Translation repository for county_mui |
| Service | Service | Read service with MUI filter/sort support |
| WriteService | WriteService | Full CRUD with MUI writes |
| WriteData | WriteData | countyAlpha, countryAlpha2 |
| MuiWriteData | MuiWriteData | lang, countyName |
REST Layer (src/Rest/Country/)
| Component | Class | Description |
|---|---|---|
| Controller | Controllers\Country | Full CRUD, string PK routes (.+) |
| Controller | Controllers\County | Full CRUD, string PK routes (.+) |
| Resource | Resources\Country\Resource | alpha2, alpha3, isoCode, phoneCode + translations + counties |
| Resource | Resources\County\Resource | alpha, countryAlpha2 + translations + country |
| MuiResource | Resources\Country\MuiResource | Country translation |
| MuiResource | Resources\County\MuiResource | County translation |
| DI Container | container.php | REST controller registrations |
DI Container (src/Domains/Country/container.php)
Registers all Country and County domain services, repositories, MUI repositories, write repositories, write services, and validators. Both MUI repositories use NullRelationConfigurator.
Architecture
| Component | Path | Purpose |
|---|---|---|
| Domain container | src/Domains/Country/container.php | DI registration for all country/county services |
| REST container | src/Rest/Country/container.php | DI registration for REST controllers |
| REST routes | application/config/rest_routes.php:277-302, 1288-1302 | Route definitions |
| OpenAPI spec | Annotations on controller classes | Auto-generated via php cli.php job/GenerateOpenApiJson |
Data Model
country
| Column | Type | Description |
|---|---|---|
alpha_2 | char(2) (PK) | ISO 3166-1 alpha-2 code |
alpha_3 | char(3) | ISO 3166-1 alpha-3 code |
iso_cc | int | ISO numeric country code |
phone_code | varchar | International dialing prefix |
country_mui
| Column | Type | Description |
|---|---|---|
alpha_2 | char(2) (FK) | Country alpha-2 code |
name | varchar | Localized country name |
lang | varchar | Language code |
county
| Column | Type | Description |
|---|---|---|
county_alpha | varchar (PK) | County alpha code (e.g., "GR-A") |
country_alpha_2 | char(2) (FK) | Parent country alpha-2 code |
county_mui
| Column | Type | Description |
|---|---|---|
county_alpha | varchar (FK) | County alpha code |
county_name | varchar | Localized county name |
lang | varchar | Language code |
Configuration
No registry keys or special config files. Country/county data is managed entirely via the REST API. The DI module is registered in application/config/container/modules.php.
Client Extension Points
- Override RepositoryConfigurator: Create
Custom\Domains\Country\Country\Repository\RepositoryConfiguratorand DI alias to add custom relations. - Override WriteService: Create
Custom\Domains\Country\Country\WriteServiceto add custom validation or post-save hooks. - Override Resource: Create
Custom\Rest\Country\Resources\Country\Resourceto add custom fields to the API response.
Business Rules
- String primary keys: Both Country and County use string PKs (
alpha_2andcounty_alpha), requiring(.+)route patterns instead of(:num). - MUI support: Both entities have
*_muicompanion tables. Translation filters use JOIN-based specifications (FilterByTranslation). - Parent-child relationship: Counties belong to a country via
country_alpha_2. Deleting a country does not cascade to counties (no FK constraint cascading at app level). - Transporter availability: Counties are referenced by
rest/transporter/county-availabilityfor shipping zone configuration. - ISO compliance: Country codes follow ISO 3166-1 standards.
Related Flows
- SY-20 Geolocation & Shipping Zones -- Counties are used for shipping zone targeting
- AD-06 Transporter Admin -- County availability uses county data for transporter zone configuration
- CF-06 Order Preview -- Address forms use country/county dropdowns during checkout
- SY-23 MUI Translation Pattern --
country_muiandcounty_muicompanion tables store per-language names withFilterByTranslationandSortByTranslationspecifications