cmandersen / bitwise
A bitwise operator package for making it easier to use bitwise columns in Eloquent models by adding a custom cast class and query functionality
Requires
- php: ^8.0
- illuminate/contracts: ^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^10.4
- phpunit/phpunit: ^9.0|^10.0|^11.0
README
A Laravel package that makes it easy to work with bitwise flags in Eloquent models. Store multiple boolean flags efficiently in a single integer database column with natural query syntax.
Requirements
- PHP 8.0 or higher
- Laravel 9.x, 10.x, 11.x, or 12.x
Installation
Install the package via Composer:
composer require cmandersen/bitwise
The package will automatically register itself via Laravel's package discovery.
Setup Your Database
Create your database column as an unsigned integer:
// In your migration Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->unsignedInteger('permissions')->default(0); $table->unsignedInteger('features')->default(0); $table->timestamps(); });
Cast Your Model Attributes
Add bitwise casting to your Eloquent model attributes:
use Illuminate\Database\Eloquent\Model; use Cmandersen\Bitwise\AsBitwise; class User extends Model { protected function casts(): array { return [ // Method 1: Auto-generate flags from names 'permissions' => AsBitwise::auto(['read', 'write', 'delete', 'admin']), // Method 2: Define flags with explicit values 'features' => AsBitwise::flags(['notifications' => 1, 'dark_mode' => 2, 'beta' => 4]), // Method 3: Shorthand syntax 'roles' => 'bitwise:user,moderator,admin', 'settings' => 'bitwise:email_notifications,push_notifications,sms_notifications', ]; } }
Working with Flags
Once cast, your attribute becomes a BitwiseCollection
with many helpful methods:
$user = User::find(1); // Check if flags are set if ($user->permissions->has('read')) { // User has read permission } if ($user->permissions->has('read', 'write')) { // User has both read AND write permissions } if ($user->permissions->hasAny('read', 'admin')) { // User has read OR admin permissions (or both) } // Add flags $user->permissions = $user->permissions->add('write'); $user->permissions = $user->permissions->add('delete', 'admin'); // Remove flags $user->permissions = $user->permissions->remove('delete'); // Toggle flags $user->permissions = $user->permissions->toggle('admin'); // Get only specific flags $readWrite = $user->permissions->only('read', 'write'); // Get all except specific flags $withoutAdmin = $user->permissions->except('admin'); // Clear all flags $user->permissions = $user->permissions->clear(); // Set all available flags $user->permissions = $user->permissions->all(); // Save changes $user->save();
Querying Models by Flags
The package automatically adds powerful query methods to all your models. No traits or additional setup required!
Basic Queries
// Find users who have 'read' permission $readUsers = User::whereBitwise('permissions', 'read')->get(); // Find users who have both 'read' AND 'write' permissions $readWriteUsers = User::whereBitwise('permissions', ['read', 'write'])->get(); // Find users who have ANY of the specified permissions $moderatorUsers = User::whereHasAnyBitwise('permissions', ['write', 'delete'])->get(); // Find users who DON'T have admin permissions $regularUsers = User::whereDoesntHaveBitwise('permissions', 'admin')->get(); // Find users with EXACTLY the 'read' permission (no other permissions) $readOnlyUsers = User::whereBitwiseEquals('permissions', 'read')->get();
Combining with Other Conditions
// Multiple flag combinations $multiplePermissions = User::whereInBitwise('permissions', ['read', 'admin'])->get(); $mixedValues = User::whereInBitwise('permissions', [ 'read', // Single permission ['read', 'write'], // Multiple permissions (has both) ])->get(); // Exclude specific permissions $excludePermissions = User::whereNotInBitwise('permissions', ['admin', 'delete'])->get(); // OR conditions $readOrWrite = User::whereBitwise('permissions', 'read') ->orWhereBitwise('permissions', 'write') ->get(); // Complex queries with other conditions $complexQuery = User::where('name', 'like', '%admin%') ->whereHasBitwise('permissions', 'admin') ->whereDoesntHaveBitwise('features', 'beta') ->orderBy('created_at', 'desc') ->get();
Complete Query Reference
All methods support OR variations (prefix with or
):
whereBitwise($column, $flags)
- Has specified flagswhereHasBitwise($column, $flags)
- Alias for whereBitwisewhereHasAnyBitwise($column, $flags)
- Has any of the flagswhereDoesntHaveBitwise($column, $flags)
- Doesn't have flagswhereBitwiseEquals($column, $flags)
- Has exactly these flagswhereInBitwise($column, $values)
- Bitwise equivalent of whereInwhereNotInBitwise($column, $values)
- Bitwise equivalent of whereNotIn
Array-like Access
BitwiseCollection
implements ArrayAccess
, so you can use array syntax:
// Check if flag is set (read-only) if ($user->permissions['read']) { // User has read permission } // Note: Direct assignment is not allowed - use add()/remove() methods instead // $user->permissions['read'] = true; // This will throw an exception
Setting Flags During Creation/Update
You can set flags in several ways:
// Using array of flag names User::create([ 'name' => 'John Doe', 'permissions' => ['read', 'write'], ]); // Using a BitwiseCollection $permissions = (new BitwiseCollection(0, ['read' => 1, 'write' => 2])) ->add('read', 'write'); User::create([ 'name' => 'Jane Doe', 'permissions' => $permissions, ]); // Using direct integer value (if you know the bit values) User::create([ 'name' => 'Admin User', 'permissions' => 15, // 1 + 2 + 4 + 8 = all flags ]);
Advanced Usage
For more advanced use cases, you can work with individual flags and utilities:
Manual Flag Generation
use Cmandersen\Bitwise\Bitwise; // Auto-generate flags from names $flags = Bitwise::generateFlags(['read', 'write', 'delete', 'admin']); // Results in: ['read' => 1, 'write' => 2, 'delete' => 4, 'admin' => 8] // Generate from associative array with mixed values $flags = Bitwise::generateFromAssoc([ 'read' => null, // Auto-assigned: 1 'write' => 16, // Manual value: 16 'delete' => null, // Auto-assigned: 32 (next available) 'admin' => true, // Auto-assigned: 64 ]);
Working with Individual Flags
use Cmandersen\Bitwise\BitwiseFlag; $readFlag = new BitwiseFlag('read', 1); $writeFlag = new BitwiseFlag('write', 2); // Check flag properties echo $readFlag->name; // 'read' echo $readFlag->value; // 1 echo $readFlag; // 'read' (string conversion) // Flag operations $readFlag->isSetIn(5); // true (5 = 1 + 4, so read flag is set) $readFlag->setBit(4); // 5 (4 | 1 = 5) $readFlag->unsetBit(5); // 4 (5 & ~1 = 4) $readFlag->toggleBit(4); // 5 (4 ^ 1 = 5) // Combine flags $combined = $readFlag->combine($writeFlag); // 3 (1 | 2 = 3)
Methods Reference
BitwiseCollection Methods
Method | Description | Returns |
---|---|---|
has(...$flags) |
Check if all specified flags are set | bool |
hasAny(...$flags) |
Check if any specified flags are set | bool |
add(...$flags) |
Add flags (returns new instance) | BitwiseCollection |
remove(...$flags) |
Remove flags (returns new instance) | BitwiseCollection |
toggle(...$flags) |
Toggle flags (returns new instance) | BitwiseCollection |
only(...$flags) |
Keep only specified flags | BitwiseCollection |
except(...$flags) |
Remove specified flags (alias for remove) | BitwiseCollection |
clear() |
Remove all flags | BitwiseCollection |
all() |
Set all available flags | BitwiseCollection |
getValue() |
Get integer value | int |
getFlags() |
Get array of BitwiseFlag objects | array |
getFlagNames() |
Get array of active flag names | array |
isEmpty() |
Check if no flags are set | bool |
isNotEmpty() |
Check if any flags are set | bool |
toArray() |
Get array of active flag names | array |
count() |
Count active flags | int |
BitwiseFlag Methods
Method | Description | Returns |
---|---|---|
is($flag) |
Check if this flag matches another | bool |
hasValue($value) |
Check if flag has specific value | bool |
isPowerOfTwo() |
Check if value is power of 2 | bool |
combine(...$flags) |
Combine with other flags | int |
isSetIn($value) |
Check if flag is set in value | bool |
setBit($value) |
Set this flag in value | int |
unsetBit($value) |
Unset this flag in value | int |
toggleBit($value) |
Toggle this flag in value | int |
License
This package is open-sourced software licensed under the MIT license.