Add NumericCode, introduce CountryCode interface, and sync ISO 3166-1.#26
Merged
Conversation
- Replace AlphaCode with CountryCode as the public contract. - Remove getName() from the interface, keeping only toString(). - Rename InvalidAlphaCode(Implementation) to InvalidCountryCode(Implementation) and promote them from Internal/Exceptions/ to Exceptions/. - Relocate CountryTest to tests/Unit/ and rename AlphaCodeXpto to CountryCodeXpto.
- Add NumericCode enum covering all current ISO 3166-1 numeric codes. - Expose toNumeric() on Alpha2Code and Alpha3Code. - Add $numeric property to Country. - Rename deprecated cases (CAPE_VERDE, CZECH_REPUBLIC, TURKEY, MALVINAS, SWAZILAND, EAST_TIMOR, MACEDONIA, VATICAN_CITY_STATE) to current ISO names. - Add missing countries (SOUTH_SUDAN, CURACAO, SERBIA, MONTENEGRO, GUERNSEY, JERSEY, ISLE_OF_MAN, HOLY_SEE, etc.). - Remove withdrawn codes (YUGOSLAVIA, ZAIRE, NETHERLANDS_ANTILLES, FRANCE_METROPOLITAN).
There was a problem hiding this comment.
Pull request overview
This PR updates the library’s ISO 3166-1 surface by introducing a CountryCode interface and NumericCode enum, expanding Country construction/conversion to support numeric codes, and synchronizing the ISO country lists. It also refreshes repository tooling, CI workflows, and documentation to align with tiny-blocks ecosystem conventions.
Changes:
- Add
NumericCodeand introduce theCountryCodeinterface; updateCountry,Alpha2Code, andAlpha3Codeto support numeric conversions and string parsing. - Restructure and expand unit tests to cover numeric codes, new parsing behavior, and extension scenarios.
- Align tooling/docs/CI with the canonical tiny-blocks configuration (reports paths, stricter PHPUnit flags, PHPStan scope, templates, and security policy).
Reviewed changes
Copilot reviewed 44 out of 45 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/Unit/CountryTest.php | New unit test suite covering CountryCode/NumericCode behavior, conversions, parsing, and timezones. |
| tests/Models/CountryWithCallingCode.php | Test fixture demonstrating extension of Country with an extra property. |
| tests/Models/CountryCodeXpto.php | Test-only CountryCode implementation used to validate unsupported implementations. |
| tests/CountryTest.php | Removes the old test suite in favor of the new tests/Unit/ structure. |
| src/NumericCode.php | Adds ISO 3166-1 numeric codes and conversion helpers to alpha codes + integer. |
| src/Internal/TimezoneCatalog.php | Removes the internal cached timezone catalog helper. |
| src/Internal/Exceptions/InvalidAlphaCodeImplementation.php | Removes old internal exception after replacing AlphaCode-based API. |
| src/Internal/Exceptions/InvalidAlphaCode.php | Removes old internal exception after replacing AlphaCode-based API. |
| src/Internal/CountryNameNormalizer.php | Adjusts the normalizer class definition (no longer readonly). |
| src/Exceptions/InvalidCountryCodeImplementation.php | Adds public exception for unsupported CountryCode implementations. |
| src/Exceptions/InvalidCountryCode.php | Adds public exception for invalid country code strings. |
| src/CountryTimezones.php | Switches timezone lookup to direct DateTimeZone::listIdentifiers() and adjusts API/docs ordering. |
| src/CountryCode.php | Introduces a common interface implemented by alpha and numeric code enums. |
| src/Country.php | Updates Country factories to accept CountryCode, adds numeric support, and adds tryFromString(). |
| src/AlphaCode.php | Removes the old AlphaCode interface. |
| src/Alpha3Code.php | Updates ISO list and implements CountryCode + numeric conversion. |
| src/Alpha2Code.php | Updates ISO list and implements CountryCode + numeric conversion. |
| SECURITY.md | Adds a security policy file consistent with repository documentation rules. |
| README.md | Updates docs/examples/TOC to include numeric codes and new Country creation methods. |
| phpunit.xml | Tightens PHPUnit configuration and moves reports to reports/. |
| phpstan.neon.dist | Raises PHPStan strictness, includes tests, and adds targeted ignores for known false positives. |
| phpcs.xml | Adds PHPCS ruleset configuration for src and tests. |
| Makefile | Aligns targets with canonical composer scripts and reports/ paths. |
| infection.json.dist | Moves Infection outputs/tmp to reports/ and updates mutator config. |
| composer.json | Updates metadata, dependencies, and scripts to match canonical tiny-blocks tooling layout. |
| .gitignore | Refreshes ignored artifacts (tool caches, reports paths) per canonical repo layout. |
| .github/workflows/codeql.yml | Updates CodeQL workflow formatting + adds concurrency/timeout. |
| .github/workflows/ci.yml | Updates CI to resolve PHP version from composer.json, adds concurrency, and standardizes job layout. |
| .github/workflows/auto-assign.yml | Adds concurrency/timeout and standardizes permissions/job naming. |
| .github/PULL_REQUEST_TEMPLATE.md | Adds a canonical PR template checklist and structure. |
| .github/ISSUE_TEMPLATE/feature_request.md | Adds a canonical feature request template. |
| .github/ISSUE_TEMPLATE/bug_report.md | Adds a canonical bug report template. |
| .github/copilot-instructions.md | Updates Copilot instructions to reference .claude/ rules as source of truth. |
| .gitattributes | Updates wording and adds dev-only export-ignore entries for reports/cache. |
| .editorconfig | Adds max_line_length = 120. |
| .claude/rules/php-library-tooling.md | Adds canonical tooling rules for tiny-blocks PHP libraries. |
| .claude/rules/php-library-testing.md | Expands canonical testing rules (BDD structure, naming, coverage discipline). |
| .claude/rules/php-library-modeling.md | Expands canonical modeling rules for public API + exceptions + extension points. |
| .claude/rules/php-library-github-workflows.md | Adds canonical workflow structure rules for PHP libraries. |
| .claude/rules/php-library-documentation.md | Adds canonical README/Markdown documentation rules and templates. |
| .claude/rules/php-library-commits.md | Adds Conventional Commits rules (applied on request). |
| .claude/rules/php-library-code-style.md | Adds canonical semantic code style rules (naming, constructors, PHPDoc policy, etc.). |
| .claude/rules/php-library-architecture.md | Adds canonical project structure and public/Internal boundary rules. |
| .claude/rules/github-workflows.md | Removes the older workflow rules file in favor of PHP-library-specific workflow rules. |
| .claude/CLAUDE.md | Updates the top-level CLAUDE index to point to the new rule files. |
Comments suppressed due to low confidence (2)
src/Internal/CountryNameNormalizer.php:12
CountryNameNormalizerhas only static behavior but is still instantiable. The code style rules recommend pairing static-onlyfinal classutilities withprivate function __construct() {}to prevent instantiation (see.claude/rules/php-library-code-style.md“Inheritance and constructors”).
tests/Unit/CountryTest.php:246- Testing rules require naming tests after behavior, not method names. Names like
testCountryFromStringWithAlpha2Coderead as API/implementation-focused; consider renaming to a behavior form (e.g., “When code is Alpha-2 then resolves matching country codes”).
Comment on lines
+25
to
32
| protected function __construct( | ||
| public readonly string $name, | ||
| public readonly Alpha2Code $alpha2, | ||
| public readonly Alpha3Code $alpha3, | ||
| public readonly NumericCode $numeric, | ||
| public readonly CountryTimezones $timezones | ||
| ) { | ||
| } |
Comment on lines
+51
to
+53
| $resolvedName = empty($name) | ||
| ? CountryNameNormalizer::fromEnumName(enumName: $alpha2->name) | ||
| : $name; |
Comment on lines
34
to
44
| public static function fromAlpha2(Alpha2Code $alpha2): CountryTimezones | ||
| { | ||
| $identifiers = TimezoneCatalog::forAlpha2(alpha2Value: $alpha2->value); | ||
| $identifiers = DateTimeZone::listIdentifiers( | ||
| timezoneGroup: DateTimeZone::PER_COUNTRY, | ||
| countryCode: $alpha2->value | ||
| ); | ||
| $timezones = Timezones::fromStrings(...$identifiers); | ||
| $default = $timezones->all()[0] ?? Timezone::utc(); | ||
|
|
||
| return new CountryTimezones(timezones: $timezones, default: $default); | ||
| return new CountryTimezones(default: $default, timezones: $timezones); | ||
| } |
Comment on lines
+7
to
+14
| "iana", | ||
| "country", | ||
| "alpha-2", | ||
| "alpha-3", | ||
| "numeric", | ||
| "timezone", | ||
| "iso-3166-1", | ||
| "tiny-blocks" |
Comment on lines
+7
to
+16
| use RuntimeException; | ||
|
|
||
| final class InvalidCountryCode extends RuntimeException | ||
| { | ||
| public function __construct(string $code) | ||
| { | ||
| $template = 'Country code <%s> is invalid.'; | ||
|
|
||
| parent::__construct(message: sprintf($template, $code)); | ||
| } |
Comment on lines
+16
to
+23
| protected function __construct( | ||
| string $name, | ||
| Alpha2Code $alpha2, | ||
| Alpha3Code $alpha3, | ||
| NumericCode $numeric, | ||
| CountryTimezones $timezones, | ||
| public readonly string $callingCode | ||
| ) { |
Comment on lines
+165
to
+172
| /** @Given a Country created from an Alpha-2 code */ | ||
| $country = Country::from(code: $alpha2); | ||
|
|
||
| /** @When calling toString on the alpha-2 code */ | ||
| $alpha2String = $country->alpha2->toString(); | ||
|
|
||
| /** @Then it returns the two-letter code */ | ||
| self::assertSame($expectedAlpha2String, $alpha2String); |
Comment on lines
+7
to
+16
| use RuntimeException; | ||
|
|
||
| final class InvalidCountryCodeImplementation extends RuntimeException | ||
| { | ||
| public function __construct(string $class) | ||
| { | ||
| $template = 'The country code implementation <%s> is invalid.'; | ||
|
|
||
| parent::__construct(message: sprintf($template, $class)); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.