antfroger/progressive

该库可以逐步、快速和简单地启用新功能

v1.2.1 2022-03-25 18:04 UTC

This package is auto-updated.

Last update: 2024-09-30 01:34:51 UTC


README

Progressive 是一个功能标志库 (也称为开关、切换等)
借助 Progressive,您可以 逐步快速简单 地启用新功能。(在紧急情况下可以快速禁用)

Build Status Latest Stable Version

安装

$ composer require antfroger/progressive

使用

// From a file
$config = \Symfony\Component\Yaml\Yaml::parseFile('/your-own-config-file.yaml');
// Content of /your-own-config-file.yaml
// features:
//   dark-theme: true
//   call-center: false
//   homepage-v2:
//     enabled: true

// Or from a PHP array
$config = [
    'features' => [
        'dark-theme'  => true,
        'call-center' => false,
        'homepage-v2' => [
            'enabled' => true
        ],
    ]
];

$progressive = new Progressive($config);
$progressive->isEnabled('dark-theme');    // true
$progressive->isEnabled('call-center');   // false
$progressive->isEnabled('homepage-v2');   // true

规则

内置

enabled: true|false

enabled 为所有人、所有地方、始终启用(或禁用)功能。
该值应为布尔值,true|false

// Short
$config = [
    'features' => [
        'dark-theme' => true
    ]
];

// Verbose
$config = [
    'features' => [
        'dark-theme'  => [
            'enabled' => true
        ]
    ]
];

自定义

您可能需要更多规则来满足您的需求和堆栈。

假设您想重新设计主页,并逐步显示以测试是否一切正常。
您首先在 dev 中启用它,然后是 preprod,然后是 prod,但只为开发者启用,然后是管理员,然后是 1% 的用户...
您如何实现这一点?

使用自定义规则!

$config = [
    'features' => [
        'homepage-v123'  => [
            'env' => ['DEV', 'PREPROD']
        ]
    ]
];
$progressive = new Progressive($config);

$progressive->addCustomRule('env', function (Context $context, array $envs) {
    return in_array(getenv('ENV'), $envs);
});

$progressive->isEnabled('homepage-v123'); // Returns true if ENV is DEV or PREPROD, otherwise returns false

(此 lambda 可以通过 上下文对象 进行改进 - 更多信息请参阅 此处

策略

规则很棒,但有时一个规则不足以决定是否启用功能。
您可能只想在 PROD 中为管理员启用功能,但在 DEVTESTPREPROD 中为所有人启用。
或者,您可能想为管理员和一定比例的用户启用功能。

这就是策略发挥作用的地方!

(策略只是嵌套规则的另一种名称。
就像规则一样,您还可以创建自己的策略!)

Progressive 随附两个内置策略

unanimous: []

unanimous 如果所有条件都满足,则启用功能。
该值应为 规则 数组。

$config = [
    'features' => [
        'translate-interface'  => [
            'unanimous' => [
                'env'   => ['DEV', 'PREPROD'],
                'roles' => ['ROLE_ADMIN', 'ROLE_TRANSLATOR']
            ]
        ]
    ]
];

在此示例中,翻译应用程序的界面仅在 DEVPREPROD 环境中向具有 ROLE_ADMINROLE_TRANSLATOR 角色的用户显示。
此策略可以定义为 AND

partial: []

partial 如果仅满足 一个 条件,则启用功能。
规则按顺序评估。功能将在某个规则为真时立即启用。
该值应为 规则 数组。

$config = [
    'features' => [
        'translate-interface'  => [
            'partial' => [
                'env'   => ['DEV', 'PREPROD'],
                'roles' => ['ROLE_ADMIN', 'ROLE_TRANSLATOR']
            ]
        ]
    ]
];

在此示例中,翻译应用程序的界面将在

  • DEVPREPROD 环境中显示(对所有用户)
  • 对于具有 ROLE_ADMINROLE_TRANSLATOR 角色的用户,无论环境如何。

此策略可以定义为 OR

上下文对象

Progressive 对您的应用程序逻辑代码一无所知(也不想知道)。
但您可能想在自定义规则中使用自己的逻辑。

在这种情况下,上下文对象是您的朋友!
它只是一个用户定义的数据包。

您可以使用它来改进我们之前的自定义规则

$context = new Context([
    'env' => getenv('ENV') ?: 'PROD'
]);

$config = [
    'features' => [
        'homepage-v123'  => [
            'env' => ['DEV', 'PREPROD']
        ]
    ]
];

$progressive = new Progressive($config, $context);
$progressive->addCustomRule('env', function (Context $context, array $envs) {
    return in_array($context->get('env'), $envs);
});

另一个常见示例是将当前用户存储在上下文中

$context = new Context(['user' => $user]);

$config = [
    'features' => [
        'homepage-v123'  => [
            'roles' => ['ROLE_ADMIN']
        ]
    ]
];

$progressive = new Progressive($config, $context);
$progressive->addCustomRule('roles', function (Context $context, array $roles) {
    $userRoles = $context->get('user')->getRoles();
    foreach ($roles as $role) {
        if (in_array($role, $userRoles) {
            return true;
        }
    }

    return false;
});

请求不存在的标志

无论何时您请求不存在的标志,isEnabled 都将返回 false。
该标志被视为禁用。

$config = [
    'features' => []
];

$progressive = new Progressive($config);
$progressive->isEnabled('dark-theme'); // false

将功能发布与代码部署分开

Progressive 接收一组配置数组,这使得将发布日历与代码部署解耦成为可能。
在这个例子中,我们使用 Symfony Yaml 组件从 YAML 文件中读取配置。

use Symfony\Component\Yaml\Yaml;

$config = Yaml::parseFile('/your-own-config-file.yaml');
// Content of /your-own-config-file.yaml
// features:
//   new-feature: false
$progressive = new Progressive($config);
$progressive->isEnabled('new-feature'); // false

想象一下,如果您能够独立于代码库部署配置文件,那么您就可以通过仅重新部署 /your-own-config-file.yaml 来发布新功能,而无需部署整个代码库。

// Content of /your-own-config-file.yaml
// features:
//   new-feature: true
$progressive->isEnabled('new-feature'); // true

您还可能希望将配置存储在数据库中,并将其作为数组传递给 Progressive。

在您的项目中使用 Progressive

Laurent Callarec 的 JavaScript 特性标志库 Banderole 启发。