diff --git a/app/Models/Enums/StudyAccessFlags.php b/app/Models/Enums/StudyAccessFlags.php new file mode 100644 index 0000000..6daf30d --- /dev/null +++ b/app/Models/Enums/StudyAccessFlags.php @@ -0,0 +1,15 @@ + */ +trait BitmaskFunctionality +{ + /** @return Int32BitMask */ + public static function mask(self ...$bits): int + { + if (count($bits) === 0) { + return 0; + } + + return array_reduce($bits, static fn (?int $sum, self $case) => ($sum ?? 0) | $case->value); + } + + /** @param Int32BitMask $value */ + public static function hasCase(int $value): bool + { + return self::tryFrom($value) !== null; + } + + /** @param Int32BitMask $value */ + public static function valueToString(int $value): string + { + return '0b'.substr(chunk_split(sprintf('%\'032b', $value), 4, '_'), 0, -1); + } + + public function toString(): string + { + return self::valueToString($this->value); + } + + /** @return Int32BitMask */ + public static function build(self ...$bits): int + { + return self::set(0, ...$bits); + } + + /** @param Int32BitMask $value */ + + /** @return Int32BitMask */ + public static function set(int $value, self ...$bits): int + { + return $value | self::mask(...$bits); + } + + /** @param Int32BitMask $value */ + + /** @return Int32BitMask */ + public static function clear(int $value, self ...$bits): int + { + return $value & ~self::mask(...$bits); + } + + /** @param Int32BitMask $value */ + + /** @return Int32BitMask */ + public static function toggle(int $value, self ...$bits): int + { + return $value ^ self::mask(...$bits); + } + + /** @param Int32BitMask $value */ + public static function on(int $value, self $bit): bool + { + return ($value & $bit->value) === $bit->value; + } + + /** @param Int32BitMask $value */ + public static function off(int $value, self $bit): bool + { + return ($value & $bit->value) === 0; + } + + /** @param Int32BitMask $value */ + public static function any(int $value, self ...$bits): bool + { + if (count($bits) === 0) { + return true; + } + + return ($value & self::mask(...$bits)) > 0; + } + + /** @param Int32BitMask $value */ + public static function all(int $value, self ...$bits): bool + { + if (count($bits) === 0) { + return true; + } + + $mask = self::mask(...$bits); + + return ($value & $mask) === $mask; + } + + /** @param Int32BitMask $value */ + public static function none(int $value, self ...$bits): bool + { + if (count($bits) === 0) { + return true; + } + + $mask = self::mask(...$bits); + + return ($value & $mask) === 0; + } + + /** + * @param Int32BitMask $value + * @return list + */ + public static function parse(int $value): array + { + return array_filter(self::cases(), static fn (self $case) => self::on($value, $case)); + } +} diff --git a/database/migrations/2024_12_27_060234_create_studies_table.php b/database/migrations/2024_12_27_060234_create_studies_table.php index d91731b..a0ce323 100644 --- a/database/migrations/2024_12_27_060234_create_studies_table.php +++ b/database/migrations/2024_12_27_060234_create_studies_table.php @@ -1,5 +1,6 @@ foreignIdFor(User::class, 'assigned_physician_id')->nullable()->constrained()->onDelete('set null'); $table->foreignIdFor(User::class, 'interpreting_physician_id')->nullable()->constrained()->onDelete('set null'); $table->foreignIdFor(User::class, 'referring_physician_id')->nullable()->constrained()->onDelete('set null'); + $table->unsignedTinyInteger('access_flags')->default(StudyAccessFlags::None->value); + $table->string('access_password')->nullable(); $table->timestamps(); $table->index(['referring_physician_id', 'receive_date']);