Identifier
Foundation Identifier provides injectable contracts for string identifiers and a default ULID implementation. Generated ULIDs are canonical 26-character uppercase strings that combine a millisecond timestamp with secure randomness.
ULIDs work well for identifiers that must be portable across databases or systems while remaining roughly sortable by creation time.
Installation
Section titled “Installation”Install the split package:
Prepare the application
Section titled “Prepare the application”Identifier services are registered through the shared application provider list:
Configuration
Section titled “Configuration”Register the identifier provider
Section titled “Register the identifier provider”In src/App.php, add the Foundation provider before features that generate or validate ULIDs:
The provider registers secure entropy, a system millisecond clock, UlidGenerator, and UlidValidator as shared services.
Choose the contract your feature needs
Section titled “Choose the contract your feature needs”Use the narrowest contract that describes the feature:
| Contract | Use when |
|---|---|
Ulid\Contracts\UlidGenerator |
The stored or exchanged identifier must be a ULID |
Contracts\IdentifierGenerator |
The feature needs a unique string but should not choose its format |
IdentifierProvider binds the ULID-specific contract. It deliberately does not bind the broad IdentifierGenerator contract because the application must decide whether ULID is its default identifier strategy.
If the application chooses ULIDs as its default, create src/Identifier/Provider.php:
Register both providers in src/App.php, in that order:
The callback aliases the broad contract to the configured ULID singleton, so both contracts resolve the same generator.
Generate the application’s default identifier
Section titled “Generate the application’s default identifier”In src/Job/Job_Creator.php, inject the broad contract when the feature needs a unique string but does not own its format. With the application binding above, it resolves to the ULID generator:
A generated value looks like 01ARYZ6S410000000000000000.
If a database column, message contract, or remote API specifically requires a ULID, inject Ulid\Contracts\UlidGenerator instead. That type makes the format requirement explicit and does not require the broad application binding.
Validate external ULIDs
Section titled “Validate external ULIDs”In src/Job/Job_Request.php, use UlidValidator at input boundaries before passing an external identifier into application behavior:
Validation accepts canonical uppercase ULIDs only. Lowercase values, invalid lengths, ambiguous characters such as I, L, O, and U, and timestamps outside the ULID range are rejected.
Understand ordering and exposure
Section titled “Understand ordering and exposure”The first ten ULID characters encode creation time in milliseconds, so sorting canonical ULID strings groups identifiers by generation time.
Testing
Section titled “Testing”Replace format-agnostic generation
Section titled “Replace format-agnostic generation”When application code depends on IdentifierGenerator, use a small fixture that always returns a known value. Create tests/Support/Fixtures/Identifier/Fixed_Identifier_Generator.php:
Bind the fixture before resolving the service under test:
Use UlidValidator when a test only needs to confirm that production generation returns a valid ULID. Avoid asserting an exact value from the system clock and secure entropy.