Skip to content

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

MethodPathActionDescription
GET/rest/country/countryindexList countries (paginated)
GET/rest/country/country/itemitemGet single country by filter
GET/rest/country/country/{alpha2}showGet country by alpha-2 code
POST/rest/country/countrystoreCreate a country
POST/rest/country/country/{alpha2}updateUpdate a country
DELETE/rest/country/country/{alpha2}destroyDelete 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

MethodPathActionDescription
GET/rest/country/countyindexList counties (paginated)
GET/rest/country/county/itemitemGet single county by filter
GET/rest/country/county/{alpha}showGet county by alpha code
POST/rest/country/countystoreCreate a county
POST/rest/country/county/{alpha}updateUpdate a county
DELETE/rest/country/county/{alpha}destroyDelete 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)

  1. GET /rest/country/country?filter[name.el]=Ελλ&with=translations,counties
  2. Controllers\Country::index() delegates to HandlesRestfulActions::index().
  3. ListRequest parses query params. The name.{locale} filter is handled as a MUI translation filter.
  4. Service::all() builds specifications:
    • MUI name filters use FilterByTranslation specification (joins MUI table).
    • MUI sort uses SortByTranslation specification.
    • Standard fields use Filter specification.
  5. Repository::match() executes query against country table.
  6. WithRelations includes translations (from country_mui) and counties (from county).
  7. Resource::resource() transforms to JSON: alpha2, alpha3, isoCode, phoneCode plus nested relations.

REST Write Flow (Country)

  1. POST /rest/country/country with { alpha2: "CY", alpha3: "CYP", isoCc: 196, phoneCode: "357", translations: [{lang: "el", name: "Kupros"}, {lang: "en", name: "Cyprus"}] }.
  2. Controllers\Country::store() -> doStore() from HandlesWriteActions.
  3. WriteService::create() constructs WriteData from input, validates, inserts master record, then inserts MUI records per language from translations array.
  4. Returns the created entity via Resource.

Domain Layer

Country (src/Domains/Country/Country/)

ComponentClassDescription
EntityRepository\Entityalpha_2 (PK), alpha_3, iso_cc, phone_code. Implements FilterTranslation
RepositoryRepository\RepositoryTable country, PK alpha_2 (string)
RepositoryConfiguratorRepository\RepositoryConfiguratortranslations -> MuiRepository (ONE_TO_MANY on alpha_2), counties -> CountyRepository (ONE_TO_MANY on country_alpha_2)
MuiRepositoryRepository\MuiRepositoryTranslation repository for country_mui
ServiceServiceRead service with MUI filter/sort support
WriteServiceWriteServiceFull CRUD with MUI writes
WriteDataWriteDataalpha2, alpha3, isoCc, phoneCode
MuiWriteDataMuiWriteDatalang, name
ValidatorValidatorValidation rules for create/update
FilterByTranslationSpecification\FilterByTranslationJoins MUI table for name filtering
SortByTranslationSpecification\SortByTranslationJoins MUI table for name sorting

County (src/Domains/Country/County/)

ComponentClassDescription
EntityRepository\Entitycounty_alpha (PK, string), country_alpha_2 (FK). Implements FilterTranslation
RepositoryRepository\RepositoryTable county, PK county_alpha (string)
RepositoryConfiguratorRepository\RepositoryConfiguratortranslations -> MuiRepository, country -> CountryRepository (BELONGS_TO on country_alpha_2)
MuiRepositoryRepository\MuiRepositoryTranslation repository for county_mui
ServiceServiceRead service with MUI filter/sort support
WriteServiceWriteServiceFull CRUD with MUI writes
WriteDataWriteDatacountyAlpha, countryAlpha2
MuiWriteDataMuiWriteDatalang, countyName

REST Layer (src/Rest/Country/)

ComponentClassDescription
ControllerControllers\CountryFull CRUD, string PK routes (.+)
ControllerControllers\CountyFull CRUD, string PK routes (.+)
ResourceResources\Country\Resourcealpha2, alpha3, isoCode, phoneCode + translations + counties
ResourceResources\County\Resourcealpha, countryAlpha2 + translations + country
MuiResourceResources\Country\MuiResourceCountry translation
MuiResourceResources\County\MuiResourceCounty translation
DI Containercontainer.phpREST 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

ComponentPathPurpose
Domain containersrc/Domains/Country/container.phpDI registration for all country/county services
REST containersrc/Rest/Country/container.phpDI registration for REST controllers
REST routesapplication/config/rest_routes.php:277-302, 1288-1302Route definitions
OpenAPI specAnnotations on controller classesAuto-generated via php cli.php job/GenerateOpenApiJson

Data Model

country

ColumnTypeDescription
alpha_2char(2) (PK)ISO 3166-1 alpha-2 code
alpha_3char(3)ISO 3166-1 alpha-3 code
iso_ccintISO numeric country code
phone_codevarcharInternational dialing prefix

country_mui

ColumnTypeDescription
alpha_2char(2) (FK)Country alpha-2 code
namevarcharLocalized country name
langvarcharLanguage code

county

ColumnTypeDescription
county_alphavarchar (PK)County alpha code (e.g., "GR-A")
country_alpha_2char(2) (FK)Parent country alpha-2 code

county_mui

ColumnTypeDescription
county_alphavarchar (FK)County alpha code
county_namevarcharLocalized county name
langvarcharLanguage 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\RepositoryConfigurator and DI alias to add custom relations.
  • Override WriteService: Create Custom\Domains\Country\Country\WriteService to add custom validation or post-save hooks.
  • Override Resource: Create Custom\Rest\Country\Resources\Country\Resource to add custom fields to the API response.

Business Rules

  1. String primary keys: Both Country and County use string PKs (alpha_2 and county_alpha), requiring (.+) route patterns instead of (:num).
  2. MUI support: Both entities have *_mui companion tables. Translation filters use JOIN-based specifications (FilterByTranslation).
  3. 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).
  4. Transporter availability: Counties are referenced by rest/transporter/county-availability for shipping zone configuration.
  5. ISO compliance: Country codes follow ISO 3166-1 standards.