francescomalatesta / laravel-feature
一个用于在Laravel项目中管理功能标志的简单包。
Requires
- php: ^7.4|^8.1
- illuminate/database: ^8.0|^9.0
- illuminate/support: ^8.0|^9.0
Requires (Dev)
- mockery/mockery: ^1.0
- orchestra/database: ^6.0|^7.0
- orchestra/testbench: ^6.0|^7.0
- phpunit/phpunit: ^8.0|^9.0
- squizlabs/php_codesniffer: ^3.3
README
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
贡献
请参阅CONTRIBUTING 和 CONDUCT 了解详细信息。
安全性
如果您发现任何与安全相关的问题,请通过电子邮件francescomalatesta@live.it 而不是使用问题跟踪器。
鸣谢
许可协议
MIT许可协议(MIT)。请参阅许可文件 了解更多信息。