aw-studio/laravel-bitflags
Laravel Bitflags stores multiple boolean flags in a single integer column. It provides an Eloquent cast for toggling, checking, and querying bitwise options without extra database columns.
v1.0.0 is the first stable release and is intended for PHP 8.2+ with Laravel 11, 12 or 13. If the app is still on Laravel 8–10 or PHP < 8.2, stay on the ^0.1 line rather than upgrading.
Install the stable release:
composer require aw-studio/laravel-bitflags:^1.0
Start by checking the README requirements section, then look at the Bitflags cast class and the package tests for examples of the query macros. The first practical use case is a model with an unsigned integer bitmask column, such as per-user notification channels, feature flags, permissions, or lightweight preferences:
$table->unsignedBigInteger('flags')->default(0);
Then apply the package’s Bitflags cast to that attribute using the import shown in the README:
use AwStudio\Bitflags\Casts\Bitflags;
protected $casts = [
'flags' => Bitflags::class,
];
Once cast, the attribute is read and written as a collection/array of flags rather than a raw integer. No application code changes are needed when upgrading an existing v0.1 app that already satisfies the new platform requirements.
Use the bitmask column as the single source of truth for a fixed set of flags. Define the available flags once, then read and write them through the cast rather than manipulating integers directly in controllers or models.
Typical model workflow:
0.Bitflags.$model->flags as the flag collection/array.Keep flag definition centralized. If your app uses enums or dedicated flag classes, map request/API values to those definitions before assigning to the model, and serialize back to stable scalar values at API boundaries. This avoids leaking raw bit positions into forms, policies, and frontend code.
For querying, prefer the package’s Eloquent query macros over hand-written bitwise SQL. They are intended for filtering records by flags and help avoid mistakes with operator precedence and grouping. Use them for common cases such as:
This pattern works well for policy checks and feature gating:
if ($user->flags->has(Flag::BetaFeatures)) {
// ...
}
Use the exact helper and macro names from the package README, since the cast is the stable integration point and the helpers/macros are convenience APIs.
When exposing flags through API resources, return a normalized array rather than the raw integer. Validate incoming flag arrays against the allowed set before saving. For existing rows, consider backfilling NULL flag columns to 0 if your domain treats “no flags” and “not configured” as the same state.
Upgrade gate: v1.0 requires PHP 8.2+ and Laravel 11/12/13. Check composer.json platform constraints before upgrading. Laravel 8–10 and PHP < 8.2 must remain on ^0.1.
null now becomes []: v1.0 casts null column values to an empty flag array and avoids PHP’s decbin(null) deprecation. If your code previously used null to mean “never configured” versus [] to mean “configured with no flags”, that distinction is no longer visible through the cast. Use a separate column or a non-null default if you need it.
Cast contract typing: The Bitflags cast now matches Laravel’s current CastsAttributes contract. If you extended or wrapped the cast in your application, update your method signatures to match Laravel’s typed contract.
Integer width matters: Bitmasks are limited by the database column type. Use an appropriately sized unsigned integer column and avoid adding more flags than the column can represent. For large or growing flag sets, consider a different storage model.
Avoid raw bitwise SQL in application code: Hand-written expressions like flags & ? are easy to get wrong when combined with OR/AND conditions. Use the package query macros where possible, and add tests for compound flag filters.
Debug with raw values: When a flag check behaves unexpectedly, inspect the raw attribute value and compare it with the expected bitmask. Also confirm the model is not returning a stale cached value after direct database updates.
Explicit Illuminate dependencies: v1.0 declares illuminate/database and illuminate/contracts explicitly. This is safer for package consumers, but keep Laravel framework and package versions aligned to avoid Composer resolution surprises in non-standard installations.
Extension point: If you need custom serialization or domain-specific flag behavior, wrap the cast or build a small application-level flag service around it rather than scattering bitwise operations throughout the codebase.
How can I help you explore Laravel packages today?