Skip to content

Commit 99e34d1

Browse files
committed
v2
1 parent d84a793 commit 99e34d1

10 files changed

+201
-128
lines changed

composer.json

+16-14
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
{
22
"name": "defstudio/enum-features",
3-
"description": "A simple trait to enable a feature system using Enums",
3+
"description": "A simple trait to enable a feature system using Enums and Laravel Pennant",
44
"keywords": [
55
"defstudio",
66
"laravel",
7+
"pennant",
78
"enum-features",
89
"enums",
9-
"feature"
10+
"features"
1011
],
1112
"homepage": "https://github.com/defstudio/enum-features",
1213
"license": "MIT",
@@ -18,20 +19,21 @@
1819
}
1920
],
2021
"require": {
21-
"php": "^8.1",
22-
"spatie/laravel-package-tools": "^1.14.0"
22+
"php": "^8.2",
23+
"spatie/laravel-package-tools": "^1.16.4",
24+
"illuminate/support": "^v11.4.0",
25+
"laravel/pennant": "^v1.7.0"
2326
},
2427
"require-dev": {
25-
"laravel/pint": "^1.0",
26-
"nunomaduro/collision": "^7.9",
27-
"nunomaduro/larastan": "^2.0.1",
28-
"orchestra/testbench": "^8.0",
29-
"pestphp/pest": "^2.0",
30-
"pestphp/pest-plugin-arch": "^2.0",
31-
"pestphp/pest-plugin-laravel": "^2.0",
32-
"phpstan/extension-installer": "^1.1",
33-
"phpstan/phpstan-deprecation-rules": "^1.0",
34-
"phpstan/phpstan-phpunit": "^1.0"
28+
"laravel/pint": "^v1.15.1",
29+
"nunomaduro/collision": "^v8.1.1",
30+
"larastan/larastan": "^v2.9.5",
31+
"orchestra/testbench": "^v9.0.4",
32+
"pestphp/pest": "^v2.34.7",
33+
"pestphp/pest-plugin-laravel": "^v2.3.0",
34+
"phpstan/extension-installer": "^1.3.1",
35+
"phpstan/phpstan-deprecation-rules": "^1.1.4",
36+
"phpstan/phpstan-phpunit": "^1.3.16"
3537
},
3638
"autoload": {
3739
"psr-4": {

src/Concerns/DefinesFeatures.php

+183-9
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,201 @@
66

77
namespace DefStudio\EnumFeatures\Concerns;
88

9-
use DefStudio\EnumFeatures\Exceptions\FeatureException;
9+
use BackedEnum;
10+
use Illuminate\Contracts\Auth\Authenticatable;
11+
use Laravel\Pennant\Feature as Pennant;
12+
use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;
1013

1114
trait DefinesFeatures
1215
{
13-
public static function enabledFeatures(): array
16+
public function define(): void
1417
{
15-
return config('app.features', []);
18+
Pennant::define($this->featureName(), $this->resolve(...));
1619
}
1720

18-
public function enabled(): bool
21+
protected function featureName(): string
1922
{
20-
return in_array($this, self::enabledFeatures());
23+
return $this instanceof BackedEnum ? $this->value : $this->name;
2124
}
2225

23-
public function enforce(): void
26+
public function active(?Authenticatable $scope = null): bool
2427
{
25-
throw_if(! $this->enabled(), FeatureException::notEnabled($this));
28+
if ($scope) {
29+
return Pennant::for($scope)->active($this->featureName());
30+
}
31+
32+
return Pennant::active($this->featureName());
33+
}
34+
35+
public function enabled(?Authenticatable $scope = null): bool
36+
{
37+
return $this->active($scope);
38+
}
39+
40+
public function inactive(?Authenticatable $scope = null): bool
41+
{
42+
return ! $this->active($scope);
43+
}
44+
45+
public function disabled(?Authenticatable $scope = null): bool
46+
{
47+
return $this->inactive($scope);
48+
}
49+
50+
public function middleware(): string
51+
{
52+
return EnsureFeaturesAreActive::using($this->featureName());
53+
}
54+
55+
public function purge(): void
56+
{
57+
Pennant::purge($this->featureName());
58+
}
59+
60+
protected function resolve(?Authenticatable $scope = null): bool
61+
{
62+
$featureName = $this->featureName();
63+
$camelFeatureName = str($this->featureName())->camel()->ucfirst();
64+
65+
$try_methods = [
66+
"check_$featureName",
67+
"check_{$featureName}_feature",
68+
"has_$featureName",
69+
"has_{$featureName}Feature",
70+
"check$camelFeatureName",
71+
"check{$camelFeatureName}Feature",
72+
"has$camelFeatureName",
73+
"has{$camelFeatureName}Feature",
74+
];
75+
76+
foreach ($try_methods as $method) {
77+
if (method_exists($this, $method)) {
78+
return $this->{$method}($scope);
79+
}
80+
}
81+
82+
return false;
83+
}
84+
85+
public function enforce(?Authenticatable $scope = null): void
86+
{
87+
if (! $this->active($scope)) {
88+
abort(400);
89+
}
90+
}
91+
92+
public function activate(?Authenticatable $scope = null): void
93+
{
94+
if ($scope) {
95+
Pennant::for($scope)->activate($this->featureName());
96+
97+
return;
98+
}
99+
100+
Pennant::activate($this->featureName());
101+
}
102+
103+
public function enable(?Authenticatable $scope = null): void
104+
{
105+
$this->activate($scope);
106+
}
107+
108+
public function deactivate(?Authenticatable $scope = null): void
109+
{
110+
if ($scope) {
111+
Pennant::for($scope)->deactivate($this->featureName());
112+
113+
return;
114+
}
115+
116+
Pennant::deactivate($this->featureName());
117+
}
118+
119+
public function disable(?Authenticatable $scope = null): void
120+
{
121+
$this->deactivate($scope);
122+
}
123+
124+
public function forget(?Authenticatable $scope = null): void
125+
{
126+
if ($scope) {
127+
Pennant::for($scope)->forget($this->featureName());
128+
129+
return;
130+
}
131+
132+
Pennant::forget($this->featureName());
133+
}
134+
135+
/**
136+
* @param array<DefinesFeatures> $features
137+
*/
138+
public static function areAllActive(array $features): bool
139+
{
140+
return Pennant::allAreInactive(collect($features)
141+
->map(fn (self $feature) => $feature->featureName())
142+
->toArray());
143+
}
144+
145+
/**
146+
* @param array<DefinesFeatures> $features
147+
*/
148+
public static function someAreActive(array $features): bool
149+
{
150+
return Pennant::someAreActive(collect($features)
151+
->map(fn (self $feature) => $feature->featureName())
152+
->toArray());
153+
}
154+
155+
/**
156+
* @param array<DefinesFeatures> $features
157+
*/
158+
public static function areAllEnabled(array $features): bool
159+
{
160+
return self::areAllActive($features);
161+
}
162+
163+
/**
164+
* @param array<DefinesFeatures> $features
165+
*/
166+
public static function someAreEnabled(array $features): bool
167+
{
168+
return self::someAreActive($features);
169+
}
170+
171+
/**
172+
* @param array<DefinesFeatures> $features
173+
*/
174+
public static function areAllInactive(array $features): bool
175+
{
176+
return Pennant::allAreInactive(collect($features)
177+
->map(fn (self $feature) => $feature->featureName())
178+
->toArray());
179+
}
180+
181+
/**
182+
* @param array<DefinesFeatures> $features
183+
*/
184+
public static function someAreInactive(array $features): bool
185+
{
186+
return Pennant::someAreInactive(collect($features)
187+
->map(fn (self $feature) => $feature->featureName())
188+
->toArray());
189+
}
190+
191+
/**
192+
* @param array<DefinesFeatures> $features
193+
*/
194+
public static function areAllDisabled(array $features): bool
195+
{
196+
return self::areAllInactive($features);
26197
}
27198

28-
public function disabled(): bool
199+
/**
200+
* @param array<DefinesFeatures> $features
201+
*/
202+
public static function someAreDisabled(array $features): bool
29203
{
30-
return ! $this->enabled();
204+
return self::someAreInactive($features);
31205
}
32206
}

src/Exceptions/FeatureException.php

+1-8
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,7 @@
88

99
class FeatureException extends Exception
1010
{
11-
public static function notEnabled(UnitEnum $feature): FeatureException
12-
{
13-
$name = $feature instanceof BackedEnum ? $feature->value : $feature->name;
14-
15-
return new self("Feature [$name] is not enabled");
16-
}
17-
18-
public static function invalid_feature_enum(UnitEnum $feature): FeatureException
11+
public static function invalid_feature(UnitEnum $feature): FeatureException
1912
{
2013
$name = $feature instanceof BackedEnum ? $feature->value : $feature->name;
2114

src/ServiceProvider.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function packageBooted(): void
2020
{
2121
Blade::if('feature', function (UnitEnum $feature) {
2222
if (! class_uses($feature, DefinesFeatures::class)) {
23-
throw FeatureException::invalid_feature_enum($feature);
23+
throw FeatureException::invalid_feature($feature);
2424
}
2525

2626
/** @var DefinesFeatures $feature */

tests/ArchTest.php

-5
This file was deleted.

tests/BaseTest.php

-23
This file was deleted.

tests/CustomConfigTest.php

-23
This file was deleted.

tests/Fixtures/CustomFeature.php

-18
This file was deleted.

tests/Fixtures/Feature.php

-14
This file was deleted.

tests/TestCase.php

-13
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,8 @@
22

33
namespace DefStudio\EnumFeatures\Tests;
44

5-
use DefStudio\EnumFeatures\Tests\Fixtures\CustomFeature;
6-
use DefStudio\EnumFeatures\Tests\Fixtures\Feature;
75
use Orchestra\Testbench\TestCase as Orchestra;
86

97
class TestCase extends Orchestra
108
{
11-
public function getEnvironmentSetUp($app): void
12-
{
13-
config()->set('app.features', [
14-
Feature::multi_language,
15-
Feature::welcome_email,
16-
]);
17-
18-
config()->set('my_package.enabled_features', [
19-
CustomFeature::guest_account,
20-
]);
21-
}
229
}

0 commit comments

Comments
 (0)