*/ use HasFactory, SoftDeletes; protected $fillable = [ 'domain_hash', 'name', 'allowed_types', 'is_active', 'is_archived', ]; protected function casts(): array { return [ 'allowed_types' => 'array', 'is_active' => 'boolean', 'is_archived' => 'boolean', ]; } protected static function booted(): void { static::creating(function (Domain $domain) { if (empty($domain->domain_hash)) { $domain->domain_hash = bin2hex(random_bytes(32)); } }); } public function mailboxes() { return $this->hasMany(Mailbox::class, 'domain_hash', 'domain_hash'); } /** * Scope to domains accessible by the given user tier. * For guests (null user), only 'public' domains are returned. * * Uses MySQL's JSON_CONTAINS to check if the domain's `allowed_types` * array includes ANY of the user's allowed types. * * Usage: * Domain::accessibleBy(auth()->user())->get(); // logged-in * Domain::accessibleBy(null)->get(); // guest * Domain::accessibleBy($user)->where('is_active', true)->get(); */ public function scopeAccessibleBy(Builder $query, ?User $user = null): Builder { $types = $user ? $user->allowedDomainTypes() : User::guestDomainTypes(); return $query->where(function (Builder $q) use ($types) { foreach ($types as $type) { $q->orWhereJsonContains('allowed_types', $type); } }); } }