Skip to content

Commit

Permalink
v2
Browse files Browse the repository at this point in the history
  • Loading branch information
fabio-ivona committed Apr 19, 2024
1 parent d84a793 commit 99e34d1
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 128 deletions.
30 changes: 16 additions & 14 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"name": "defstudio/enum-features",
"description": "A simple trait to enable a feature system using Enums",
"description": "A simple trait to enable a feature system using Enums and Laravel Pennant",
"keywords": [
"defstudio",
"laravel",
"pennant",
"enum-features",
"enums",
"feature"
"features"
],
"homepage": "https://github.com/defstudio/enum-features",
"license": "MIT",
Expand All @@ -18,20 +19,21 @@
}
],
"require": {
"php": "^8.1",
"spatie/laravel-package-tools": "^1.14.0"
"php": "^8.2",
"spatie/laravel-package-tools": "^1.16.4",
"illuminate/support": "^v11.4.0",
"laravel/pennant": "^v1.7.0"
},
"require-dev": {
"laravel/pint": "^1.0",
"nunomaduro/collision": "^7.9",
"nunomaduro/larastan": "^2.0.1",
"orchestra/testbench": "^8.0",
"pestphp/pest": "^2.0",
"pestphp/pest-plugin-arch": "^2.0",
"pestphp/pest-plugin-laravel": "^2.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0"
"laravel/pint": "^v1.15.1",
"nunomaduro/collision": "^v8.1.1",
"larastan/larastan": "^v2.9.5",
"orchestra/testbench": "^v9.0.4",
"pestphp/pest": "^v2.34.7",
"pestphp/pest-plugin-laravel": "^v2.3.0",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan-deprecation-rules": "^1.1.4",
"phpstan/phpstan-phpunit": "^1.3.16"
},
"autoload": {
"psr-4": {
Expand Down
192 changes: 183 additions & 9 deletions src/Concerns/DefinesFeatures.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,201 @@

namespace DefStudio\EnumFeatures\Concerns;

use DefStudio\EnumFeatures\Exceptions\FeatureException;
use BackedEnum;
use Illuminate\Contracts\Auth\Authenticatable;
use Laravel\Pennant\Feature as Pennant;
use Laravel\Pennant\Middleware\EnsureFeaturesAreActive;

trait DefinesFeatures
{
public static function enabledFeatures(): array
public function define(): void
{
return config('app.features', []);
Pennant::define($this->featureName(), $this->resolve(...));
}

public function enabled(): bool
protected function featureName(): string
{
return in_array($this, self::enabledFeatures());
return $this instanceof BackedEnum ? $this->value : $this->name;
}

public function enforce(): void
public function active(?Authenticatable $scope = null): bool
{
throw_if(! $this->enabled(), FeatureException::notEnabled($this));
if ($scope) {
return Pennant::for($scope)->active($this->featureName());
}

return Pennant::active($this->featureName());
}

public function enabled(?Authenticatable $scope = null): bool
{
return $this->active($scope);
}

public function inactive(?Authenticatable $scope = null): bool
{
return ! $this->active($scope);
}

public function disabled(?Authenticatable $scope = null): bool
{
return $this->inactive($scope);
}

public function middleware(): string
{
return EnsureFeaturesAreActive::using($this->featureName());
}

public function purge(): void
{
Pennant::purge($this->featureName());
}

protected function resolve(?Authenticatable $scope = null): bool
{
$featureName = $this->featureName();
$camelFeatureName = str($this->featureName())->camel()->ucfirst();

$try_methods = [
"check_$featureName",
"check_{$featureName}_feature",
"has_$featureName",
"has_{$featureName}Feature",
"check$camelFeatureName",
"check{$camelFeatureName}Feature",
"has$camelFeatureName",
"has{$camelFeatureName}Feature",
];

foreach ($try_methods as $method) {
if (method_exists($this, $method)) {
return $this->{$method}($scope);
}
}

return false;
}

public function enforce(?Authenticatable $scope = null): void
{
if (! $this->active($scope)) {
abort(400);
}
}

public function activate(?Authenticatable $scope = null): void
{
if ($scope) {
Pennant::for($scope)->activate($this->featureName());

return;
}

Pennant::activate($this->featureName());
}

public function enable(?Authenticatable $scope = null): void
{
$this->activate($scope);
}

public function deactivate(?Authenticatable $scope = null): void
{
if ($scope) {
Pennant::for($scope)->deactivate($this->featureName());

return;
}

Pennant::deactivate($this->featureName());
}

public function disable(?Authenticatable $scope = null): void
{
$this->deactivate($scope);
}

public function forget(?Authenticatable $scope = null): void
{
if ($scope) {
Pennant::for($scope)->forget($this->featureName());

return;
}

Pennant::forget($this->featureName());
}

/**
* @param array<DefinesFeatures> $features
*/
public static function areAllActive(array $features): bool
{
return Pennant::allAreInactive(collect($features)
->map(fn (self $feature) => $feature->featureName())
->toArray());
}

/**
* @param array<DefinesFeatures> $features
*/
public static function someAreActive(array $features): bool
{
return Pennant::someAreActive(collect($features)
->map(fn (self $feature) => $feature->featureName())
->toArray());
}

/**
* @param array<DefinesFeatures> $features
*/
public static function areAllEnabled(array $features): bool
{
return self::areAllActive($features);
}

/**
* @param array<DefinesFeatures> $features
*/
public static function someAreEnabled(array $features): bool
{
return self::someAreActive($features);
}

/**
* @param array<DefinesFeatures> $features
*/
public static function areAllInactive(array $features): bool
{
return Pennant::allAreInactive(collect($features)
->map(fn (self $feature) => $feature->featureName())
->toArray());
}

/**
* @param array<DefinesFeatures> $features
*/
public static function someAreInactive(array $features): bool
{
return Pennant::someAreInactive(collect($features)
->map(fn (self $feature) => $feature->featureName())
->toArray());
}

/**
* @param array<DefinesFeatures> $features
*/
public static function areAllDisabled(array $features): bool
{
return self::areAllInactive($features);
}

public function disabled(): bool
/**
* @param array<DefinesFeatures> $features
*/
public static function someAreDisabled(array $features): bool
{
return ! $this->enabled();
return self::someAreInactive($features);
}
}
9 changes: 1 addition & 8 deletions src/Exceptions/FeatureException.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,7 @@

class FeatureException extends Exception
{
public static function notEnabled(UnitEnum $feature): FeatureException
{
$name = $feature instanceof BackedEnum ? $feature->value : $feature->name;

return new self("Feature [$name] is not enabled");
}

public static function invalid_feature_enum(UnitEnum $feature): FeatureException
public static function invalid_feature(UnitEnum $feature): FeatureException
{
$name = $feature instanceof BackedEnum ? $feature->value : $feature->name;

Expand Down
2 changes: 1 addition & 1 deletion src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function packageBooted(): void
{
Blade::if('feature', function (UnitEnum $feature) {
if (! class_uses($feature, DefinesFeatures::class)) {
throw FeatureException::invalid_feature_enum($feature);
throw FeatureException::invalid_feature($feature);
}

/** @var DefinesFeatures $feature */
Expand Down
5 changes: 0 additions & 5 deletions tests/ArchTest.php

This file was deleted.

23 changes: 0 additions & 23 deletions tests/BaseTest.php

This file was deleted.

23 changes: 0 additions & 23 deletions tests/CustomConfigTest.php

This file was deleted.

18 changes: 0 additions & 18 deletions tests/Fixtures/CustomFeature.php

This file was deleted.

14 changes: 0 additions & 14 deletions tests/Fixtures/Feature.php

This file was deleted.

13 changes: 0 additions & 13 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,8 @@

namespace DefStudio\EnumFeatures\Tests;

use DefStudio\EnumFeatures\Tests\Fixtures\CustomFeature;
use DefStudio\EnumFeatures\Tests\Fixtures\Feature;
use Orchestra\Testbench\TestCase as Orchestra;

class TestCase extends Orchestra
{
public function getEnvironmentSetUp($app): void
{
config()->set('app.features', [
Feature::multi_language,
Feature::welcome_email,
]);

config()->set('my_package.enabled_features', [
CustomFeature::guest_account,
]);
}
}

0 comments on commit 99e34d1

Please sign in to comment.