francescomalatesta/laravel-feature

一个用于在Laravel项目中管理功能标志的简单包。

3.0.0 2022-06-30 08:21 UTC

This package is auto-updated.

Last update: 2024-08-29 04:31:14 UTC


README

Latest Stable Version Build Status Code Coverage Scrutinizer Code Quality StyleCI

Laravel-Feature 是一个专注于在您的应用程序中进行功能切换的包,简单易用。当然,是为Laravel设计的。

它受到了 AdEspresso Feature Flag Bundle 的启发。

功能-是什么?

功能切换基本上是一种在您的应用程序中完全控制功能激活的方式。

让我们举几个例子来说明

  • 你刚刚完成了一个新功能的开发,并想将其推送到生产环境,但市场团队要求你在稍后时间再部署;
  • 新的杀手级功能已经准备好了,但你想只为特定用户集启用它;

使用 Laravel-Feature,您可以

  • 轻松地在应用程序中定义新功能;
  • 全局启用/禁用功能;
  • 为特定用户或任何您想要的对象启用/禁用功能;

关于功能切换有很多要了解的事情:请查看 这篇优秀的文章 了解更多信息。这是一次非常棒且实用的课程。

安装

您可以使用 Composer 安装 Laravel-Feature。

$ composer require francescomalatesta/laravel-feature

之后,您需要在 app.php 配置文件中添加 FeatureServiceProvider

...
LaravelFeature\Provider\FeatureServiceProvider::class,
...

现在,您需要运行迁移,以添加 Laravel-Feature 所需的表。

$ php artisan migrate

... 现在您可以开始了!

门面

如果您愿意,还可以在 app.php 配置文件的 aliases 数组中添加 Feature 门面。

...
'Feature' => \LaravelFeature\Facade\Feature::class,
...

如果您不喜欢门面,可以在任何需要的地方注入 FeatureManager 类!

配置文件

默认情况下,您可以直接使用 Laravel-Feature。但是,如果您想调整一些设置,您可以随时使用以下命令 发布配置文件

$ php artisan vendor:publish --provider="LaravelFeature\Provider\FeatureServiceProvider"

基本用法

您可以使用两种方式来使用功能:全局工作或为特定实体特定工作。

全局启用/禁用功能

声明新功能

假设您有一个新功能,您想在某个时刻之前将其隐藏。我们将称其为 "page_code_cleaner"。让我们 将其添加到我们的应用程序中

Feature::add('page_code_cleaner', false);

很简单,对吧?如您所想,第一个参数是功能名称。第二个参数是我们指定的布尔值,用于定义功能的当前状态。

  • true 表示 功能对所有用户都启用
  • false 表示 功能被隐藏,没有人可以使用它/看到它

就是这样。

检查功能是否启用

现在,让我们假设一个更好的例子。我们正在构建一个CMS,我们的 "page_code_cleaner" 用于... 清理我们的HTML代码。让我们假设我们有一个这样的控制器。

class CMSController extends Controller {
    public function getPage($pageSlug) {
        
        // here we are getting our page code from some service
        $content = PageService::getContentBySlug($pageSlug);
        
        // here we are showing our page code
        return view('layout.pages', compact('content'));
    }
}

现在,我们想部署新服务,但 我们不想让用户可以使用它,因为市场团队要求我们下周发布。LaravelFeature 帮助我们做到了这一点

class CMSController extends Controller {
    public function getPage($pageSlug) {
        
        // here we are getting our page code from some service
        $content = PageService::getContentBySlug($pageSlug);
        
        // feature flagging here!
        if(Feature::isEnabled('page_code_cleaner')) {
            $content = PageCleanerService::clean($content);
        }
        
        // here we are showing our page code
        return view('layout.pages', compact('content'));
    }
}

太棒了!现在,只有当 "page_code_cleaner" 功能被启用时,特定的服务代码才会执行

更改功能激活状态

显然,使用Feature类可以轻松切换功能的激活状态。

// release the feature!
Feature::enable('page_code_cleaner');

// hide the feature!
Feature::disable('page_code_cleaner');

删除一个功能

即使不太常用,您也可以轻松使用以下方式删除一个功能:

Feature::remove('page_code_cleaner');

警告:请确保您的操作。如果您从系统中删除了功能,如果代码库中仍存在对已删除功能的检查,您可能会遇到异常。

处理视图

我真的喜欢blade指令,它们帮助我编写更优雅的代码。我准备了一个自定义的blade指令,@feature

<div>This is an example template div. Always visible.</div>

@feature('my_awesome_feature')
    <p>This paragraph will be visible only if "my_awesome_feature" is enabled!</p>
@endfeature

<div>This is another example template div. Always visible too.</div>

一个非常方便的快捷方式!

为特定用户/实体启用/禁用功能

尽管我们之前看到的这些功能很有用,但LaravelFeature不仅仅是在功能上推送开/关按钮。有时,业务需求需要更多的灵活性。想想看一个金丝雀发布:我们只想将功能推广给特定用户。或者,也许,只是针对一个测试用户。

为特定用户启用功能管理

LaravelFeature使得这成为可能,并且就像添加一个特征到我们的User类一样简单。

实际上,您需要做的只是

  • LaravelFeature\Featurable\Featurable特征添加到User类中;
  • 让相同的类实现FeaturableInterface接口
...

class User extends Authenticatable implements FeaturableInterface
{
    use Notifiable, Featurable;
    
...

这就结束了!LaravelFeature现在已经知道该做什么了。

状态优先级

请记住,从现在开始,如果您已经全局启用了功能,所有这些都将不再有效。要为特定用户激活功能,您首先需要禁用它。

Laravel-Feature首先检查功能是否已全局启用,然后进入实体级别。

为特定用户启用/禁用功能

$user = Auth::user();

// now, the feature "my.feature" is enabled ONLY for $user!
Feature::enableFor('my.feature', $user);

// now, the feature "my.feature" is disabled for $user!
Feature::disableFor('my.feature', $user);

检查特定用户是否已启用功能

$user = Auth::user();

if(Feature::isEnabledFor('my.feature', $user)) {
    
    // do amazing things!
    
}

其他注意事项

LaravelFeature还提供了一个Blade指令来检查功能是否为特定用户启用。您可以使用@featurefor blade标签。

@featurefor('my.feature', $user)
    
    // do $user related things here!
    
@endfeaturefor

高级功能

好吧,现在我们已经了解了基础知识,让我们提高标准!

为其他实体启用功能管理

正如我之前所说,您可以通过使用Featurable特征和在User模型中实现FeaturableInterface来轻松添加用户的功能管理。然而,在结构关系时,我决定实现一个多对多关联关系。这意味着您可以为任何模型添加功能管理!

让我们举一个例子:假设您有一个Role模型,您使用它为您的用户实现基本的角色系统。这是因为您有管理员和普通用户。

所以,您推出了一个惊人的杀手级功能,但您只想为管理员启用它。如何做到这一点?很简单。总结

  • Featurable特征添加到Role模型中;
  • 确保Role模型实现了FeaturableInterface

让我们将角色-用户关系视为一对一关系。

您在User类上可能有一个role()方法,对吗?很好。您已经知道其余的部分了

// $role is the admin role!
$role = Auth::user()->role;

...

Feature::enableFor('my.feature', $role);

...

if(Feature::isEnabledFor('my.feature', $role)) {

    // this code will be executed only if the user is an admin!
    
}

扫描目录以查找功能

在我制作此包时启发的包之一的好处之一是能够“扫描”视图,查找@feature声明,然后添加这些已扫描的功能,如果它们尚未在系统中存在。

我创建了一个简单的artisan命令来完成此操作。

$ php artisan feature:scan

该命令将使用一个专门的服务来获取resources/views文件夹,扫描每个Blade视图以查找@feature指令。然后,它会输出搜索结果。

试试吧,你会喜欢的!

注意:如果您已发布配置文件,您将能够 更改已扫描目录的列表

使用自定义功能存储库

想象一下,您想 更改存储功能的位置或方式。出于某种疯狂的原因,您想将其存储在静态文件或Dropbox上。

现在,Eloquent没有Dropbox驱动程序,因此您无法使用此包。 再见。

开玩笑的!在制作这个包时,我想确保如果开发者不再使用Eloquent,也能创建一个完全可重用的逻辑。

为此,我创建了一个很好的Job接口,并在Laravel服务容器中创建了一些绑定。实际上并不复杂。

我正在谈论的接口是 FeatureRepositoryInterface

<?php

namespace LaravelFeature\Domain\Repository;

use LaravelFeature\Domain\Model\Feature;
use LaravelFeature\Featurable\FeaturableInterface;

interface FeatureRepositoryInterface
{
    public function save(Feature $feature);

    public function remove(Feature $feature);

    public function findByName($featureName);

    public function enableFor($featureName, FeaturableInterface $featurable);

    public function disableFor($featureName, FeaturableInterface $featurable);

    public function isEnabledFor($featureName, FeaturableInterface $featurable);
}

该接口有一些方法。让我们快速解释一下

  • save:此方法用于在系统尚未存在的情况下保存新功能;
  • remove:此方法用于从系统中删除功能;
  • findByName:此方法用于根据名称在系统中查找功能;
  • enableFor:用于为特定的 Featurable 实体启用功能;
  • disableFor:用于为特定的 Featurable 实体禁用功能;
  • isEnabledFor:用于检查功能是否为特定的 Featurable 实体启用;

因此,您需要创建一个新的 DropboxFeatureRepository,该类实现 FeatureRepositoryInterface,并包含您刚刚看到的所有方法。

最后,您必须更改配置文件 features.php 中的存储库绑定

'repository' => LaravelFeature\Repository\EloquentFeatureRepository::class

将变为...

'repository' => My\Wonderful\DropboxFeatureRepository::class

完成!顺便说一句,别忘了让需要实现的实体 实现 FeaturableInterface

<?php

namespace LaravelFeature\Featurable;

interface FeaturableInterface
{
    public function hasFeature($featureName);
}

这里唯一的方法是 hasFeature。它用于定义给定的功能是否为该实体启用。

为了更好地了解机制,您可以查看我构建的Eloquent实现中的 EloquentFeatureRepository 类和 Featurable 特性。

更改日志

请参阅CHANGELOG 了解最近更改的详细信息。

测试

您可以使用简单的

$ phpunit

或者,也可以

$ composer test

有两个独立的测试套件

  • 单元测试;
  • 集成测试;
$ phpunit --testsuite=unit
$ phpunit --testsuite=integration

贡献

请参阅CONTRIBUTINGCONDUCT 了解详细信息。

安全性

如果您发现任何与安全相关的问题,请通过电子邮件francescomalatesta@live.it 而不是使用问题跟踪器。

鸣谢

许可协议

MIT许可协议(MIT)。请参阅许可文件 了解更多信息。