-
-
Notifications
You must be signed in to change notification settings - Fork 14
feat: port framework enum support from Laravel #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Enable using BackedEnums as session keys across all session methods, leveraging the Str::from() and Str::fromAll() helpers for normalization. Methods updated: - get, put, pull, remove, forget - exists, missing, has, hasAny - remember, push, increment, decrement - flash, now - only, except - hasOldInput, getOldInput Includes 41 new tests covering single enums, arrays of enums, mixed arrays (enums + strings), and int-backed enum support.
|
Hi @binaryfire, thank you for this pull request! Will this PR introduce breaking changes for anyone who has implemented custom session stores? Custom implementations of the session store interface will need to update their method signatures to accept additional Therefore, I'll merge it into the upcoming |
|
@albertcht Ah yeah, good point. No problems! I'm going to make PRs for the other places where enum support would be useful. This what I'm thinking:
What do you think? |
I think enum support is a great idea, but we could be more strategic about where it provides the most value. Enums work best when the string values are complete, standalone identifiers that are used as-is throughout the application. They're ideal for scenarios where you have a fixed, predefined set of values that get repeatedly referenced across multiple layers (controllers, services, views, middleware) without modification. Enums are a poor fit when string values need concatenation with dynamic parts or represent hierarchical structures. For example, patterns like From your list, I think Gate seems to be the most suitable choice, while others like Cache, Config, Context, and RateLimiter don't seem to be good fits. |
|
Hi @albertcht. Laravel has added There have have been several PRs for adding enum support across the framework and they've all been accepted: laravel/framework#58241 The RateLimiter supports enums now too: https://github.com/laravel/framework/blob/3026dc7a7cf24b413a34c14ea3da992d045cac66/src/Illuminate/Cache/RateLimiter.php#L318 I know you said we should limit the places enums are supported, but I think we should follow Laravel's lead and add support to the following things: Already supported by Laravel:
Not supported by Laravel yet, but I'm sure they will be soon:
What do you think? I use enums for all these things. Not in every situation, but whenever possible. There's no performance overhead and it gives developers the option of better type safety if they want it. I'll port everything over plus add support in a few more places I think make sense, then you can take a look. |
- Add UnitEnum support to session contract and store (BackedEnum uses ->value, UnitEnum uses ->name) - Replace Str::from()/fromAll() with enum_value() to match Laravel - Simplify enum_value() helper to match Laravel's direct implementation (remove unnecessary transform() wrapper) - Add comprehensive UnitEnum test coverage (24 new tests) - Update all session method signatures with strict UnitEnum types BREAKING CHANGE: Session contract method signatures now include UnitEnum type. Custom implementations must update their signatures.
- Add enum support to for() and limiter() methods for named rate limiters - Add resolveLimiterName() helper using enum_value() - Add comprehensive enum tests covering BackedEnum, UnitEnum, and string interoperability Following Laravel's approach where only named limiter methods support enums (for/limiter), not key-based methods (attempt/hit/etc) since those typically use dynamic concatenated keys.
- Update Gate contract with enum type hints for has(), define(), allows(), denies(), check(), any(), none(), authorize(), and inspect() methods - Update Gate implementation to use enum_value() for ability resolution - Update Authorize middleware to support enums in using() method - Update AuthorizesRequests trait to use enum_value() in parseAbilityAndArguments() - Add comprehensive GateEnumTest with tests for all enum scenarios
- Override groupBy() to convert UnitEnum/Stringable keys via enum_value() - Override keyBy() to convert UnitEnum keys via enum_value() - Override getArrayableItems() to wrap UnitEnum as [$enum] instead of casting - Override operatorForWhere() to use enum_value() for comparisons - Add Collection.php to phpstan ignored paths (same as Eloquent Collection) - Add comprehensive tests for both enum and base functionality
Add enum support to Cache Repository key methods (get, put, add, increment, decrement, forever, forget, remember, etc.) and their child classes (TaggedCache, RedisTaggedCache). Also adds enum support for cache tags, allowing enums to be used as tag names - a feature Laravel doesn't have yet.
Allow using enums as context keys for set, get, has, destroy, override, and getOrSet methods. Follows the same pattern as Session enum support.
Allow using enums as replacement values in translations. The enum's value (for BackedEnum) or name (for UnitEnum) is used as the replacement string.
…nd Queue - Redis::connection() now accepts UnitEnum for connection names - FilesystemManager::disk()/drive() now accepts UnitEnum for disk names - Model::setConnection() now accepts UnitEnum for connection names - Factory::connection() now accepts UnitEnum for connection names - Pivot::setConnection() now accepts UnitEnum for connection names - MorphPivot::setConnection() now accepts UnitEnum for connection names - Queueable::onConnection/onQueue() changed from BackedEnum to UnitEnum for consistency
BackedEnum extends UnitEnum, so including both in union types is redundant. Simplified all BackedEnum|UnitEnum unions to just UnitEnum.
Since BackedEnum extends UnitEnum, having both in union types is redundant. This removes BackedEnum from union types in validation, permission, queue, and cache packages while keeping the import where needed for instanceof checks.
Cast enum_value() results to string where underlying methods expect string parameters. This ensures int-backed enums (e.g., enum Foo: int) work correctly by converting their int values to strings. Fixed locations: - Context: 6 parent method calls expecting string $id - Gate: raw() call expecting string ability - FilesystemManager: disk name resolution - Redis: connection name resolution - PendingBatch/PendingChain: queue name (with null handling) - Cache Repository: increment/decrement/forever and event dispatch - TaggedCache: increment/decrement with itemKey - RedisTaggedCache: all key operations - Session Store: Arr::pull() calls requiring string keys Added int-backed enum tests for Context, Cache, Gate, Filesystem, and Redis to verify the casts work correctly.
- Schedule: job() accepts UnitEnum for queue/connection, useCache() for store - ManagesFrequencies: timezone() accepts UnitEnum - QueuedClosure: onConnection(), onQueue(), onGroup() accept UnitEnum - EventDispatcher: queue names support UnitEnum in queueHandler() - InteractsWithBroadcasting: broadcastVia() accepts UnitEnum - PendingBroadcast: via() accepts UnitEnum - Collection: lazy() returns Hypervel's LazyCollection for enum support - LazyCollection: countBy() supports enum group keys All use (string) enum_value() to handle int-backed enums correctly.
- InteractsWithData: date() timezone param accepts UnitEnum - Query/Builder: castBinding() supports UnitEnum (not just BackedEnum) Both use enum_value() for consistent enum handling.
Both helpers now accept UnitEnum for timezone parameter and use enum_value() for consistent enum handling.
Let int-backed enums fail with TypeError at typed boundaries instead of silently converting to strings like "1". This matches Laravel's behavior where enum_value() returns the raw value and type mismatches fail naturally. Also adds enum tests for TaggedCache, RedisTaggedCache, and RateLimited.
Replace Str::from() and Str::fromAll() with enum_value() for consistency with other enum-supporting APIs across the codebase. Also updates type hints from BackedEnum to UnitEnum to match the established pattern.
- Cookie: has(), get(), make(), expire(), unqueue(), forever(), forget() - Js: Changed BackedEnum to UnitEnum, use enum_value() - ThrottleRequests::using(): Accept enum limiter names - PendingBatch/PendingChain::onConnection(): Accept enum connection names - Updated facade docblocks via facade-documenter - Added comprehensive enum tests
|
Hi @albertcht. This PR is ready for review. I've updated the post. Most of this is just porting enum support from Laravel. I added enum support in a few additional areas as well. Let me know what you think. |
This PR ports Laravel's comprehensive
enum_value()support throughout the framework, allowing enums to be used in place of strings across caching, queues, broadcasting, scheduling, validation, and more.Summary
Laravel has gradually added enum support across the entire framework, allowing developers to use type-safe enums instead of magic strings for things like queue names, cache keys, broadcast channels, and more. This PR brings that same level of enum support to Hypervel, and builds on it.
The
enum_value()helper function extracts the underlying value from enums:->value(string or int)->name(string)Ported from Laravel
Cache
Repository:has(),missing(),get(),pull(),put(),set(),add(),increment(),decrement(),forever(),remember(),sear(),rememberForever(),forget(),delete()RateLimiter:for(),limiter(),tooManyAttempts(),hit(),attempts(),resetAttempts(),remaining(),retriesLeft(),clear(),availableIn(),cleanRateLimiterKey()Queue & Bus
Queueabletrait:onConnection(),onQueue(),allOnConnection(),allOnQueue()PendingDispatch:onConnection(),onQueue(),afterCommit(),beforeCommit()PendingBatch:onQueue(),onConnection()PendingChain:onQueue(),onConnection()RateLimitedmiddleware: Constructor accepts enum limiter namesBroadcasting
InteractsWithBroadcastingtrait:broadcastOn()PendingBroadcast:onQueue(),onConnection()Scheduling
ManagesFrequenciestrait:days(),weekdays(),weekends(),sundays()throughsaturdays()Schedule:job()accepts enum queue/connectionDatabase & Eloquent
Query\Builder:from(),fromSub(),join()and variants,crossJoinSub(),orderBy(),latest(),oldest(),groupBy(),dd(),dump()Model:setTable()Pivot/MorphPivot:setTable()Factory:connection(),recycle()Auth & Gate
Gate:allows(),denies(),check(),any(),none(),authorize(),inspect(),raw(),define(),resource(),policy()AuthorizesRequeststrait:authorize(),authorizeForUser(),authorizeResource(),can()Authorizemiddleware: Enum abilities supportSession
Store/Sessioncontract:get(),has(),put(),remember(),push(),increment(),decrement(),forget(),remove(),pull()Events
EventDispatcher:dispatch(),listen(),hasListeners(),push(),flush(),forget()QueuedClosure:onConnection(),onQueue()Validation
Rule::in(),Rule::notIn(): Accept enum valuesIn/NotInrules: Constructor accepts enumsFilesystem
FilesystemManager:disk(),drive(),build(),set(),forgetDisk(),purge()Storagefacade:fake(),persistentFake()Router
ThrottleRequestsmiddleware:using()accepts enum limiter namesRedis
Redisfacade:connection()Translation
Translator:get(),choice(),has(),hasForLocale()Support
Collection/LazyCollection:contains(),doesntContain(),containsStrict()InteractsWithDatatrait:data(),has(),filled(),isNotFilled(),missing(),hasAny()Js: Enum value serialization (changed from BackedEnum to UnitEnum)Helpers
report(): Exception context accepts enum keysExtra Additions (Hypervel-specific)
Laravel currently doesn't support enums for these things, but probably will in the future:
Cache Tags
TaggedCache:increment(),decrement()RedisTaggedCache:add(),put(),increment(),decrement(),forever()Context
Context:set(),get(),has(),destroy(),override(),getOrSet()Cookie
CookieManager/Cookiecontract:has(),get(),make(),expire(),unqueue(),forever(),forget()Sanctum
Updated Sanctum to use
enum_value()instead ofStr::from()/Str::fromAll()for consistency:HasApiTokenstrait:tokenCan(),tokenCant(),createToken()PersonalAccessToken/TransientToken:can(),cant()Str::from()/Str::fromAll()withenum_value()/array_map(enum_value(...))Type Signature Improvements
Laravel doesn't use signature type hints to avoid breaking backwards compatibility. Since this will be merged in 0.4, we can make it a breaking change and use modern typing:
BackedEnumtoUnitEnumin type hints to match Laravel's pattern (UnitEnum is the base interface that BackedEnum extends)BackedEnum|UnitEnumunion types (simplified to justUnitEnumsince BackedEnum extends UnitEnum)Queueable,PendingDispatch,PendingBatch,PendingChain,In,NotIn,Js, Sanctum traits/contractsSimplified
enum_value()ImplementationRemoved unnecessary
transform()wrapper to match Laravel's simpler implementation:Test Coverage
Added comprehensive tests for all enum support:
->value)->name)