|null $segments */ class TenantAnnouncement extends Model { /** @use HasFactory<\Database\Factories\TenantAnnouncementFactory> */ use HasFactory; protected $fillable = [ 'title', 'body', 'cta_label', 'cta_url', 'status', 'audience', 'segments', 'starts_at', 'ends_at', 'email_enabled', 'created_by', 'updated_by', ]; protected function casts(): array { return [ 'status' => TenantAnnouncementStatus::class, 'audience' => TenantAnnouncementAudience::class, 'segments' => 'array', 'email_enabled' => 'boolean', 'starts_at' => 'datetime', 'ends_at' => 'datetime', ]; } public function tenants(): BelongsToMany { return $this->belongsToMany(Tenant::class, 'tenant_announcement_targets') ->withTimestamps(); } public function deliveries(): HasMany { return $this->hasMany(TenantAnnouncementDelivery::class); } public function creator(): BelongsTo { return $this->belongsTo(User::class, 'created_by'); } public function updater(): BelongsTo { return $this->belongsTo(User::class, 'updated_by'); } public function scopeActive(Builder $query): void { $query->where('status', TenantAnnouncementStatus::ACTIVE->value) ->where(function (Builder $builder) { $builder->whereNull('starts_at') ->orWhere('starts_at', '<=', Carbon::now()); }) ->where(function (Builder $builder) { $builder->whereNull('ends_at') ->orWhere('ends_at', '>', Carbon::now()); }); } /** * @param array $segments */ public function matchesSegments(Tenant $tenant, array $segments): bool { if ($segments === []) { return true; } foreach ($segments as $segment) { $normalized = $segment instanceof TenantAnnouncementSegment ? $segment : TenantAnnouncementSegment::tryFrom((string) $segment); if (! $normalized) { continue; } if (! $this->matchesSegment($tenant, $normalized)) { return false; } } return true; } private function matchesSegment(Tenant $tenant, TenantAnnouncementSegment $segment): bool { return match ($segment) { TenantAnnouncementSegment::ACTIVE_PACKAGE => $tenant->activeResellerPackage()->exists(), TenantAnnouncementSegment::ACTIVE_STATUS => (bool) $tenant->is_active && ! (bool) $tenant->is_suspended && $tenant->pending_deletion_at === null && $tenant->anonymized_at === null, }; } }