'integer', 'sort_order' => 'integer', 'is_active' => 'boolean', ]; /** * Feature types. */ public const TYPE_BOOLEAN = 'boolean'; public const TYPE_LIMIT = 'limit'; public const TYPE_UNLIMITED = 'unlimited'; /** * Reset types. */ public const RESET_NONE = 'none'; public const RESET_MONTHLY = 'monthly'; public const RESET_ROLLING = 'rolling'; /** * Packages that include this feature. */ public function packages(): BelongsToMany { return $this->belongsToMany(Package::class, 'entitlement_package_features', 'feature_id', 'package_id') ->withPivot('limit_value') ->withTimestamps(); } /** * Parent feature (for hierarchical limits / global pools). */ public function parent(): BelongsTo { return $this->belongsTo(Feature::class, 'parent_feature_id'); } /** * Child features (allowances within a global pool). */ public function children(): HasMany { return $this->hasMany(Feature::class, 'parent_feature_id'); } /** * Scope to active features. */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope to features in a category. */ public function scopeInCategory($query, string $category) { return $query->where('category', $category); } /** * Scope to root features (no parent). */ public function scopeRoot($query) { return $query->whereNull('parent_feature_id'); } /** * Check if this feature is a boolean toggle. */ public function isBoolean(): bool { return $this->type === self::TYPE_BOOLEAN; } /** * Check if this feature has a usage limit. */ public function hasLimit(): bool { return $this->type === self::TYPE_LIMIT; } /** * Check if this feature is unlimited. */ public function isUnlimited(): bool { return $this->type === self::TYPE_UNLIMITED; } /** * Check if this feature resets monthly. */ public function resetsMonthly(): bool { return $this->reset_type === self::RESET_MONTHLY; } /** * Check if this feature uses rolling window reset. */ public function resetsRolling(): bool { return $this->reset_type === self::RESET_ROLLING; } /** * Check if this is a child feature (part of a global pool). */ public function isChildFeature(): bool { return $this->parent_feature_id !== null; } /** * Get the global pool feature code (parent or self). */ public function getPoolFeatureCode(): string { return $this->parent?->code ?? $this->code; } }