Skip to content

Conversation

@binaryfire
Copy link
Contributor

This PR adds the 10 primitive cast types that Laravel has but Hypervel/Hyperf lacks, bringing Hypervel's model casting capabilities to feature parity with Laravel.

New Cast Types

Cast Description
encrypted AES-256 encrypted value
encrypted:array Encrypted JSON → array
encrypted:collection Encrypted JSON → Collection
encrypted:json Encrypted JSON → array
encrypted:object Encrypted JSON → stdClass
hashed One-way bcrypt/argon hash
immutable_date DateTimeImmutable date
immutable_datetime DateTimeImmutable datetime
immutable_custom_datetime DateTimeImmutable with custom format
json:unicode JSON with JSON_UNESCAPED_UNICODE flag

Changes

Hash Package

  • Added verifyConfiguration() to BcryptHasher, ArgonHasher, Argon2IdHasher, and HashManager
  • This method verifies that a hash was created with valid configuration parameters (not exceeding current config)
  • Added @method annotation to Hash facade for IDE support

Core Package (HasAttributes)

  • Added encryption helper methods: encryptUsing(), currentEncrypter(), isEncryptedCastable(), fromEncryptedString(), castAttributeAsEncryptedString()
  • Added hashing helper method: castAttributeAsHashedString()
  • Added JSON unicode support: getJsonCastFlags(), isJsonCastable() override
  • Added immutable datetime detection: isImmutableCustomDateTimeCast()
  • Overrode castAttribute() to handle new cast types (refactored to use match expression)
  • Overrode setAttribute() to encrypt/hash values on set
  • Added $primitiveCastTypes to Model, Pivot, and MorphPivot classes

Usage Examples

class User extends Model
{
    protected function casts(): array
    {
        return [
            // Encrypted values - automatically encrypted on set, decrypted on get
            'api_key' => 'encrypted',
            'settings' => 'encrypted:array',

            // Hashed values - automatically hashed on set
            'password' => 'hashed',

            // Immutable dates - returns CarbonImmutable instead of Carbon
            'birth_date' => 'immutable_date',
            'created_at' => 'immutable_datetime',

            // JSON with unicode support
            'metadata' => 'json:unicode',
        ];
    }
}

Test Coverage

  • 12 new tests for verifyConfiguration() across all hashers
  • 19 new tests for the new cast types covering:
    • Immutable date/datetime casts (3 tests)
    • JSON unicode preservation (2 tests)
    • Encrypted cast roundtrip - all 5 variants (5 tests)
    • Hashed cast - plain text and existing hash handling (3 tests)
    • Null value handling for encrypted/hashed casts (3 tests)
    • encryptUsing() custom encrypter API (3 tests)

Port Laravel's verifyConfiguration() method and its supporting methods
(isUsingCorrectAlgorithm, isUsingValidOptions) to verify that a hash
was created with valid configuration parameters.
Port Laravel's verifyConfiguration() method and its supporting methods
(isUsingCorrectAlgorithm, isUsingValidOptions) to verify that an Argon2i
hash was created with valid configuration parameters (memory, time, threads).
Override isUsingCorrectAlgorithm() to check for 'argon2id' algorithm.
This allows the inherited verifyConfiguration() from ArgonHasher to
work correctly for Argon2id hashes.
Delegate verifyConfiguration() to the underlying driver to verify
that a hash was created with valid configuration parameters.
Add @method annotation for verifyConfiguration() for IDE autocompletion
and static analysis support.
Add comprehensive test coverage for the new verifyConfiguration()
method across all hashers (Bcrypt, Argon, Argon2id) and HashManager.

Tests cover:
- Valid hash verification
- Lower cost/options verification (should pass)
- Higher cost/options verification (should fail)
- Wrong algorithm verification (should fail)
- HashManager delegation to driver
Add the 10 missing cast types from Laravel:
- encrypted, encrypted:array, encrypted:collection, encrypted:json, encrypted:object
- hashed
- immutable_date, immutable_datetime, immutable_custom_datetime
- json:unicode
Add methods to support encrypted casts:
- $encrypter static property for custom encrypter
- encryptUsing() to set custom encrypter
- currentEncrypter() to get the current encrypter
- isEncryptedCastable() to detect encrypted cast types
- fromEncryptedString() to decrypt values
- castAttributeAsEncryptedString() to encrypt values
Add castAttributeAsHashedString() to support the 'hashed' cast type.
The method hashes plain text values and verifies configuration for
already-hashed values to prevent accepting hashes with invalid config.
Add support for:
- encrypted casts (decrypt before processing, strip encrypted: prefix)
- json:unicode (same as array/json on GET)
- immutable_date (returns CarbonImmutable)
- immutable_datetime (returns CarbonImmutable)
- immutable_custom_datetime (returns CarbonImmutable with custom format)

Also adds isImmutableCustomDateTimeCast() helper method and getCastType()
override to properly detect immutable custom datetime casts.
Replace switch statement with PHP 8 match expression for cleaner code.
Extract default case handling into castAttributeDefault() helper method.
Add support for:
- Encrypted casts on SET (encrypt before storing)
- Hashed cast on SET (hash before storing)
- json:unicode on SET (use JSON_UNESCAPED_UNICODE flag)

Also adds:
- getJsonCastFlags() to determine JSON encoding flags
- castAttributeAsJson() override to use flags
- asJson() override to accept flags parameter
Add json:unicode and encrypted:* types to the list of JSON-castable
types to ensure proper JSON encoding on SET for these cast types.
PHP traits cannot override static properties from parent classes/traits.
Move the $primitiveCastTypes property to the Model class instead to
avoid the composition conflict with Hyperf's base model.
Comprehensive tests for:
- immutable_date cast (returns CarbonImmutable)
- immutable_datetime cast (returns CarbonImmutable)
- immutable_custom_datetime cast (returns CarbonImmutable)
- json:unicode cast (preserves unicode characters)
- encrypted cast (encrypts/decrypts values)
- encrypted:array cast
- encrypted:collection cast
- encrypted:object cast
- hashed cast (hashes plain text, preserves existing hashes)
- Cast decimal precision to int in castAttribute()
- Change setAttribute return type annotation to @return static
- Add $primitiveCastTypes to Pivot and MorphPivot classes
  (they use HasAttributes trait but don't extend Hypervel\Model)
- Test null value handling for encrypted casts (SET and GET)
- Test null value handling for hashed cast (SET)
- Test encryptUsing() with custom encrypter
- Test currentEncrypter() returns custom encrypter when set
- Test encrypter can be reset and replaced
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant