'array', 'is_default' => 'boolean', 'is_active' => 'boolean', 'sort_order' => 'integer', ]; /** * Boot the model. */ protected static function booted(): void { static::creating(function (self $namespace) { if (empty($namespace->uuid)) { $namespace->uuid = (string) Str::uuid(); } }); } // ───────────────────────────────────────────────────────────────────────── // Ownership Relationships // ───────────────────────────────────────────────────────────────────────── /** * Get the owner of the namespace (User or Workspace). */ public function owner(): MorphTo { return $this->morphTo(); } /** * Get the workspace for billing aggregation (if set). * * This is separate from owner - a user-owned namespace can still * have a workspace context for billing purposes. */ public function workspace(): BelongsTo { return $this->belongsTo(Workspace::class); } /** * Check if this namespace is owned by a user. */ public function isOwnedByUser(): bool { return $this->owner_type === User::class; } /** * Check if this namespace is owned by a workspace. */ public function isOwnedByWorkspace(): bool { return $this->owner_type === Workspace::class; } /** * Get the owner as User (or null if workspace-owned). */ public function getOwnerUser(): ?User { if ($this->isOwnedByUser()) { return $this->owner; } return null; } /** * Get the owner as Workspace (or null if user-owned). */ public function getOwnerWorkspace(): ?Workspace { if ($this->isOwnedByWorkspace()) { return $this->owner; } return null; } // ───────────────────────────────────────────────────────────────────────── // Entitlement Relationships // ───────────────────────────────────────────────────────────────────────── /** * Active package assignments for this namespace. */ public function namespacePackages(): HasMany { return $this->hasMany(NamespacePackage::class); } /** * Active boosts for this namespace. */ public function boosts(): HasMany { return $this->hasMany(Boost::class); } /** * Usage records for this namespace. */ public function usageRecords(): HasMany { return $this->hasMany(UsageRecord::class); } /** * Entitlement logs for this namespace. */ public function entitlementLogs(): HasMany { return $this->hasMany(EntitlementLog::class); } // ───────────────────────────────────────────────────────────────────────── // Settings & Configuration // ───────────────────────────────────────────────────────────────────────── /** * Get a setting value from the settings JSON column. */ public function getSetting(string $key, mixed $default = null): mixed { return data_get($this->settings, $key, $default); } /** * Set a setting value in the settings JSON column. */ public function setSetting(string $key, mixed $value): self { $settings = $this->settings ?? []; data_set($settings, $key, $value); $this->settings = $settings; return $this; } // ───────────────────────────────────────────────────────────────────────── // Scopes // ───────────────────────────────────────────────────────────────────────── /** * Scope to only active namespaces. */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope to order by sort order. */ public function scopeOrdered($query) { return $query->orderBy('sort_order'); } /** * Scope to namespaces owned by a specific user. */ public function scopeOwnedByUser($query, User|int $user) { $userId = $user instanceof User ? $user->id : $user; return $query->where('owner_type', User::class) ->where('owner_id', $userId); } /** * Scope to namespaces owned by a specific workspace. */ public function scopeOwnedByWorkspace($query, Workspace|int $workspace) { $workspaceId = $workspace instanceof Workspace ? $workspace->id : $workspace; return $query->where('owner_type', Workspace::class) ->where('owner_id', $workspaceId); } /** * Scope to namespaces accessible by a user (owned by user OR owned by user's workspaces). */ public function scopeAccessibleBy($query, User $user) { $workspaceIds = $user->workspaces()->pluck('workspaces.id'); return $query->where(function ($q) use ($user, $workspaceIds) { // User-owned namespaces $q->where(function ($q2) use ($user) { $q2->where('owner_type', User::class) ->where('owner_id', $user->id); }); // Workspace-owned namespaces (where user is a member) if ($workspaceIds->isNotEmpty()) { $q->orWhere(function ($q2) use ($workspaceIds) { $q2->where('owner_type', Workspace::class) ->whereIn('owner_id', $workspaceIds); }); } }); } // ───────────────────────────────────────────────────────────────────────── // Helper Methods // ───────────────────────────────────────────────────────────────────────── /** * Check if a user has access to this namespace. */ public function isAccessibleBy(User $user): bool { // User owns the namespace directly if ($this->isOwnedByUser() && $this->owner_id === $user->id) { return true; } // Workspace owns the namespace and user is a member if ($this->isOwnedByWorkspace()) { return $user->workspaces()->where('workspaces.id', $this->owner_id)->exists(); } return false; } /** * Get the billing context for this namespace. * * Returns workspace if set, otherwise falls back to owner's default workspace. */ public function getBillingContext(): ?Workspace { // Explicit workspace set for billing if ($this->workspace_id) { return $this->workspace; } // Workspace-owned: use the owner workspace if ($this->isOwnedByWorkspace()) { return $this->owner; } // User-owned: fall back to user's default workspace if ($this->isOwnedByUser() && $this->owner) { return $this->owner->defaultHostWorkspace(); } return null; } /** * Get the route key name for route model binding. */ public function getRouteKeyName(): string { return 'uuid'; } }