Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
33.33% covered (danger)
33.33%
3 / 9
42.86% covered (danger)
42.86%
3 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
PlanFeature
33.33% covered (danger)
33.33%
3 / 9
42.86% covered (danger)
42.86%
3 / 7
26.96
0.00% covered (danger)
0.00%
0 / 1
 plan
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 feature
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 scopeEnabled
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 scopeForPlan
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 scopeForFeature
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getEffectiveValue
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
 newFactory
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Http\Models;
4
5use Database\Factories\Http\Models\PlanFeatureFactory;
6use Illuminate\Database\Eloquent\Factories\HasFactory;
7use Illuminate\Database\Eloquent\Relations\BelongsTo;
8
9/**
10 * PlanFeature pivot model for plan-feature relationships.
11 *
12 * Represents the many-to-many relationship between plans and features,
13 * allowing custom values to be set for each feature per plan.
14 *
15 * @property string $_id The plan feature ID
16 * @property string $plan_id The plan ID (reference to plans._id)
17 * @property string $feature_id The feature ID (reference to features._id)
18 * @property mixed $value The custom value for this feature on this plan (overrides feature default)
19 * @property bool $is_enabled Whether this feature is enabled for this plan
20 * @property \Carbon\Carbon|null $created_at
21 * @property \Carbon\Carbon|null $updated_at
22 * @property-read Plans|null $plan
23 * @property-read Feature|null $feature
24 */
25class PlanFeature extends Moloquent
26{
27    use HasFactory;
28
29    /**
30     * The collection associated with the model.
31     *
32     * @var string
33     */
34    protected $collection = 'plan_features';
35
36    /**
37     * The attributes that are mass assignable.
38     *
39     * @var array<string>
40     */
41    protected $fillable = [
42        'plan_id',
43        'feature_id',
44        'value',
45        'is_enabled',
46    ];
47
48    /**
49     * The attributes that should be cast.
50     *
51     * @var array<string, string>
52     */
53    protected $casts = [
54        'is_enabled' => 'boolean',
55    ];
56
57    /**
58     * The model's default values for attributes.
59     *
60     * @var array<string, mixed>
61     */
62    protected $attributes = [
63        'is_enabled' => true,
64    ];
65
66    /**
67     * Get the plan that this feature assignment belongs to.
68     *
69     * @return BelongsTo<Plans, PlanFeature>
70     */
71    public function plan(): BelongsTo
72    {
73        return $this->belongsTo(Plans::class, 'plan_id');
74    }
75
76    /**
77     * Get the feature that this assignment references.
78     *
79     * @return BelongsTo<Feature, PlanFeature>
80     */
81    public function feature(): BelongsTo
82    {
83        return $this->belongsTo(Feature::class, 'feature_id');
84    }
85
86    /**
87     * Scope a query to only include enabled features.
88     *
89     * @param  \Illuminate\Database\Eloquent\Builder<PlanFeature>  $query
90     * @return \Illuminate\Database\Eloquent\Builder<PlanFeature>
91     */
92    public function scopeEnabled($query)
93    {
94        return $query->where('is_enabled', true);
95    }
96
97    /**
98     * Scope a query to filter by plan ID.
99     *
100     * @param  \Illuminate\Database\Eloquent\Builder<PlanFeature>  $query
101     * @param  string  $planId  The plan ID to filter by
102     * @return \Illuminate\Database\Eloquent\Builder<PlanFeature>
103     */
104    public function scopeForPlan($query, string $planId)
105    {
106        return $query->where('plan_id', $planId);
107    }
108
109    /**
110     * Scope a query to filter by feature ID.
111     *
112     * @param  \Illuminate\Database\Eloquent\Builder<PlanFeature>  $query
113     * @param  string  $featureId  The feature ID to filter by
114     * @return \Illuminate\Database\Eloquent\Builder<PlanFeature>
115     */
116    public function scopeForFeature($query, string $featureId)
117    {
118        return $query->where('feature_id', $featureId);
119    }
120
121    /**
122     * Get the effective value for this feature assignment.
123     *
124     * Returns the assigned value if set, otherwise falls back to the feature's default value.
125     *
126     * @return mixed The effective value
127     */
128    public function getEffectiveValue(): mixed
129    {
130        if ($this->value !== null) {
131            return $this->value;
132        }
133
134        return $this->feature?->default_value;
135    }
136
137    /**
138     * Create a new factory instance for the model.
139     *
140     * @return PlanFeatureFactory
141     */
142    protected static function newFactory()
143    {
144        return PlanFeatureFactory::new();
145    }
146}