unleash / symfony-client-bundle
Requires
- php: ^8.2
- nyholm/psr7: ^1.0
- symfony/cache: ^5.0 | ^6.0 | ^7.0
- symfony/event-dispatcher: ^5.0 | ^6.0 | ^7.0
- symfony/framework-bundle: ^5.0 | ^6.0 | ^7.0
- symfony/http-client: ^5.0 | ^6.0 | ^7.0
- unleash/client: ^2.4
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.15
- jetbrains/phpstorm-attributes: ^1.0
- phpstan/phpstan: ^1.10
- rector/rector: ^0.15.23
- symfony/expression-language: ^5.0 | ^6.0 | ^7.0
- symfony/security-core: ^5.0 | ^6.0 | ^7.0
- symfony/yaml: ^6.3 | ^7.0
- twig/twig: ^3.3
Suggests
- symfony/expression-language: For integration of expression language in custom properties in Unleash context
- symfony/security-bundle: For integration of Symfony users into Unleash context
- dev-main
- v0.11.382
- v0.11.381
- v0.11.380
- v0.11.374
- v0.11.373
- v0.11.282
- v0.11.281
- v0.11.280
- v0.11.274
- v0.11.273
- v0.11.182
- v0.11.181
- v0.11.180
- v0.11.174
- v0.11.173
- v0.11.082
- v0.11.081
- v0.11.080
- v0.11.074
- v0.11.073
- v0.10.382
- v0.10.381
- v0.10.380
- v0.10.374
- v0.10.373
- v0.10.282
- v0.10.281
- v0.10.280
- v0.10.274
- v0.10.273
- v0.10.182
- v0.10.181
- v0.10.180
- v0.10.174
- v0.10.173
- v0.10.082
- v0.10.081
- v0.10.080
- v0.10.074
- v0.10.073
- v0.9.1480
- v0.9.1474
- v0.9.1473
- v0.9.1380
- v0.9.1374
- v0.9.1373
- v0.9.1280
- v0.9.1274
- v0.9.1273
- v0.9.1180
- v0.9.1174
- v0.9.1173
- v0.9.1080
- v0.9.1074
- v0.9.1073
- v0.9.980
- v0.9.974
- v0.9.973
- v0.9.880
- v0.9.874
- v0.9.873
- v0.9.780
- v0.9.774
- v0.9.773
- v0.9.680
- v0.9.674
- v0.9.673
- v0.9.580
- v0.9.574
- v0.9.573
- v0.9.480
- v0.9.474
- v0.9.473
- v0.9.380
- v0.9.374
- v0.9.373
- v0.9.280
- v0.9.274
- v0.9.273
- v0.9.180
- v0.9.174
- v0.9.173
- v0.9.080
- v0.9.074
- v0.9.073
- dev-feat/env-processors
- dev-php-7.3
- dev-php-8.0
- dev-php-8.1
- dev-php-7.4
This package is auto-updated.
Last update: 2024-09-06 10:45:34 UTC
README
这是一个用于PHP实现的Unleash协议(也称为GitLab中的功能标志)的Symfony包。您可以在Unleash官网或GitLab文档中查看更多信息。
Unleash允许您在基于多种策略(如仅向特定用户或向用户基数的百分比发布)进行完整发布之前,逐步发布您的应用功能。有关更多信息,请参阅上述链接文档。
需要php 7.3或更高版本。
要了解方法的通用描述,请阅读独立包的文档,本README将重点介绍Symfony特定内容
安装
composer require unleash/symfony-client-bundle
如果您使用flex,则捆绑包将自动启用,否则请将
Unleash\Client\Bundle\UnleashSymfonyClientBundle
添加到您的config/bundles.php
基本用法
首先配置基本参数,可以使用DSN或作为单独的参数
unleash_client: dsn: http://localhost:4242/api?instance_id=myCoolApp-Server1&app_name=myCoolApp
或
unleash_client: app_url: http://localhost:4242/api instance_id: myCoolApp-Server1 app_name: myCoolApp
提示:通过运行
php bin/console config:dump unleash_client > config/packages/unleash_client.yaml
来生成默认配置,这将创建默认配置文件,然后您可以对其进行修改
<?php use Unleash\Client\Unleash; class MyService { public function __construct(Unleash $unleash) { if ($unleash->isEnabled('someFeatureName')) { // todo } } }
控制器属性
您还可以使用#[IsEnabled]
和#[IsNotEnabled]
属性在控制器上检查功能标志。您可以在整个控制器类以及具体方法上使用它。
<?php use Unleash\Client\Bundle\Attribute\IsEnabled; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; #[IsEnabled('my_awesome_feature')] final class MyController { #[IsEnabled('another_awesome_feature', Response::HTTP_BAD_REQUEST)] #[Route('/my-route')] public function myRoute(): Response { // todo } #[Route('/other-route')] public function otherRoute(): Response { // todo } }
在上面的示例中,在/my-route
上的用户需要同时启用my_awesome_feature
和another_awesome_feature
(因为类和方法的属性),而/other-route
只需要启用my_awesome_feature
(因为类属性)。
<?php use Unleash\Client\Bundle\Attribute\IsNotEnabled; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; #[IsNotEnabled('kill_switch')] final class MyHeavyController { #[Route('/my-route')] public function myRoute(): Response { // todo } }
在第二个示例中,只有当kill_switch
未启用时,/my-route
路由才启用。
您还可以注意到,其中一个属性指定了第二个可选的状态码参数。支持的状态码有:
404
-NotFoundHttpException
403
-AccessDeniedHttpException
400
-BadRequestHttpException
401
-UnauthorizedHttpException
带有消息“未授权”。503
-ServiceUnavailableHttpException
默认状态码是404
。如果您使用不受支持的状态码,将抛出InvalidValueException
。
为属性设置自定义异常
如果您想在基于属性拒绝用户访问的情况下使用自定义异常,可以监听事件
<?php use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Unleash\Client\Bundle\Event\UnleashEvents; use Unleash\Client\Bundle\Event\BeforeExceptionThrownForAttributeEvent; use Symfony\Component\HttpFoundation\Response; final class MySubscriber implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ UnleashEvents::BEFORE_EXCEPTION_THROWN_FOR_ATTRIBUTE => 'handleException', ]; } public function handleException(BeforeExceptionThrownForAttributeEvent $event): void { $statusCode = $event->getErrorCode(); switch ($statusCode) { case Response::HTTP_NOT_FOUND: $exception = new CustomException('Custom message'); break; default: $exception = null; } // the exception can be a Throwable or null, null means that this bundle reverts // to its own default exceptions $event->setException($exception); } }
上下文
上下文对象为Unleash提供额外的参数,并支持Symfony的功能。此上下文还注入到Unleash
服务中,而不是通用服务。
<?php use Unleash\Client\Configuration\Context; use Unleash\Client\Enum\ContextField; class MyService { public function __construct(Context $context) { $context->getCurrentUserId(); $context->getSessionId(); $context->getIpAddress(); $context->hasCustomProperty('someProperty'); $context->getCustomProperty('someProperty'); $context->hasMatchingFieldValue('someProperty', ['someValue1', 'someValue2']); $context->findContextValue(ContextField::USER_ID); } }
如果已安装Symfony Security
组件,将自动分配当前用户ID。您可以通过配置来指定用于用户ID的字段,默认情况下,它使用Symfony\Component\Security\Core\User\UserInterface::getUserIdentifier()
或Symfony\Component\Security\Core\User\UserInterface::getUsername()
。
unleash_client: context: user_id_field: id
使用此配置,此包将使用id
属性来分配用户ID。此属性不必为公共属性。
此包还会自动集成到Symfony的请求堆栈中,从中获取IP地址和会话ID,如果您位于代理后面并且它在您的信任代理列表中,这可能特别有用。
上下文环境默认值为kernel.environment
参数的值。
自定义属性
您还可以定义自己的属性,这些属性将存在于上下文中。如果您使用Symfony表达式语言
,您还可以在这些属性中使用表达式。如果值是表达式,则必须以>
字符开头。如果想要您的值以>
开头但不作为表达式,请使用\
进行转义。所有表达式都可以访问user
变量,该变量是用户对象或null。
unleash_client: context: custom_properties: myCustomProperty: someValue # just a good old string myOtherProperty: '> 1+1' # starts with >, it will be turned into expression, meaning the value will be 2 myEscapedProperty: '\> someValue' # will be turned into '> someValue' someUserField: '> user.getCustomField()' # will be the result of the getCustomField() method call safeUserField: '> user ? user.getCustomField() : null'
如果您不想在配置中嵌入逻辑,您也可以监听事件
<?php use Unleash\Client\Bundle\Event\UnleashEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Unleash\Client\Bundle\Event\ContextValueNotFoundEvent; class MyListener implements EventSubscriberInterface { public static function getSubscribedEvents(): array { return [ UnleashEvents::CONTEXT_VALUE_NOT_FOUND => 'handleNotFoundContextValue', ]; } public function handleNotFoundContextValue(ContextValueNotFoundEvent $event) { switch ($event->getContextName()) { case 'myProperty': $value = '...'; // dynamically create the value $event->setValue($value); break; } } }
事件
有两种类型的事件,来自基本Unleash PHP SDK和来自此Symfony包的事件。
基础SDK事件
\Unleash\Client\Event\UnleashEvents::FEATURE_TOGGLE_NOT_FOUND
\Unleash\Client\Event\UnleashEvents::FEATURE_TOGGLE_DISABLED
\Unleash\Client\Event\UnleashEvents::FEATURE_TOGGLE_MISSING_STRATEGY_HANDLER
有关更多信息,请参阅基础SDK中的文档。
Symfony包事件
\Unleash\Client\Bundle\Event\UnleashEvents::CONTEXT_VALUE_NOT_FOUND
\Unleash\Client\Bundle\Event\UnleashEvents::BEFORE_EXCEPTION_THROWN_FOR_ATTRIBUTE
事件在README的相关部分中进行了说明。
Twig
如果您使用twig,可以利用函数、过滤器、测试和自定义标签。名称是通用的,因此您可以在它们与您自己的函数/过滤器/测试/标签冲突时禁用它们中的任何一个。
默认情况下,如果安装了twig,则所有内容都启用。
unleash_client: twig: functions: true filters: true tests: true tags: true
Twig函数
有两个函数:feature_is_enabled()
和feature_variant()
。
第一个返回一个布尔值,第二个返回一个Unleash\Client\DTO\Variant
实例。
{% if feature_is_enabled('featureName') %} {% set variant = feature_variant('featureName') %} {% if variant.enabled %} {{ variant.name }} {% endif %} {% endif %}
Twig过滤器
您可以使用具有相同名称的过滤器来代替函数。
{% if 'featureName'|feature_is_enabled %} {% set variant = 'featureName' | feature_variant %} {# Do something #} {% endif %}
Twig测试
您还可以使用名为enabled
的测试。
{% if 'featureName' is enabled %} {# Do something #} {% endif %}
Twig标签
此标签是实验性的,可能在未来的版本中删除
您可以使用自定义的feature
标签。如果特征被启用,则将处理标签体内的任何内容。您还可以访问隐式variant
变量。
{% feature 'featureName' %} {{ variant.name }} {# Implicit variant variable that only exists in the scope of feature block #} {% endfeature %}
自定义策略
定义自定义策略非常简单,因为它们会自动注入,您只需要创建一个实现Unleash\Client\Strategy\StrategyHandler
(或扩展Unleash\Client\Strategy\AbstractStrategyHandler
)的类。
<?php use Unleash\Client\Strategy\AbstractStrategyHandler; use Unleash\Client\DTO\Strategy; use Unleash\Client\Configuration\Context; class MyCustomStrategy extends AbstractStrategyHandler { public function getStrategyName() : string { return 'my_custom_strategy'; } public function isEnabled(Strategy $strategy, Context $context) : bool { $someCustomProperty = $this->findParameter('customProperty', $strategy); if ($someCustomProperty === false) { return false; } // assume it's a list $someCustomProperty = array_map('trim', explode(',', $someCustomProperty)); $enabled = $context->hasMatchingFieldValue('customProperty', $someCustomProperty); // check if the constraints are valid using the abstract class' method if (!$enabled || !$this->validateConstraints($strategy, $context)) { return false; } return true; } }
就是这样,由于实现了接口(通过扩展抽象类),您的类自动注册为策略处理器,并且Unleash
服务可以处理它。
如果您想使用其中一个默认策略,您可以这样做,所有这些策略都支持自动装配。
禁用内置策略
如果您出于某种原因想要禁用任何内置策略,您可以在配置中这样做。
unleash_client: disabled_strategies: - default - remoteAddress
缓存和http
默认情况下,服务设置为使用symfony/http-client
、nyholm/psr7
和symfony/cache
。
您可以在配置中覆盖默认值
unleash_client: http_client_service: my_custom_http_client_service request_factory_service: my_custom_request_factory_service cache_service: my_custom_cache_service
HTTP客户端服务必须实现Psr\Http\Client\ClientInterface
或Symfony\Contracts\HttpClient\HttpClientInterface
。
请求工厂服务必须实现Psr\Http\Message\RequestFactoryInterface
。
缓存服务必须实现Psr\SimpleCache\CacheInterface
或Psr\Cache\CacheItemPoolInterface
(这通过扩展意味着它可以实现标准Symfony\Component\Cache\Adapter\AdapterInterface
,它扩展了它)。
引导
您可以为SDK设置默认响应,以防由于某种原因无法联系Unleash服务器。
您可以使用文件或实现\Unleash\Client\Bootstrap\BootstrapProvider
的服务进行引导。
服务
<?php use Unleash\Client\Bootstrap\BootstrapProvider; final class MyBootstrap implements BootstrapProvider { public function getBootstrap() : array|JsonSerializable|Traversable|null{ // TODO: Implement getBootstrap() method. } }
unleash_client: bootstrap: '@MyBootstrap'
提示:如果您只创建一个实现
BootstrapProvider
的服务,它将被自动注入。如果您创建多个,您需要像上面示例中那样手动选择一个引导。
文件
假设您在配置目录中创建了一个名为 bootstrap.json
的文件,这样您就可以将其作为 Unleash 引导注入。
unleash_client: bootstrap: 'file://%kernel.project_dir%/config/bootstrap.json'
注意:所有文件都必须以
file://
前缀开始。
禁用与 Unleash 服务器通信
对于本地开发和使用引导,禁用与 Unleash 服务器的通信可能很有用。
请注意,当您禁用与 Unleash 的通信并且没有提供引导时,将抛出一个异常。
提示:将缓存间隔设置为 0 以始终使用最新的引导内容。
当禁用通信时,通常所需的参数(应用名称、实例 ID、应用 URL)是不需要的。
unleash_client: bootstrap: '@MyBootstrap' cache_ttl: 0 fetching_enabled: false
测试命令
如果您需要快速测试您的标志将评估为什么,您可以使用内置命令 unleash:test-flag
。
该命令有文档说明,以下是 ./bin/console unleash:test-flag --help
的输出。
Description:
Check the status of an Unleash feature
Usage:
unleash:test-flag [options] [--] <flag>
Arguments:
flag The name of the feature flag to check the result for
Options:
-f, --force When this flag is present, fresh results without cache will be forced
--user-id=USER-ID [Context] Provide the current user's ID
--ip-address=IP-ADDRESS [Context] Provide the current IP address
--session-id=SESSION-ID [Context] Provide the current session ID
--hostname=HOSTNAME [Context] Provide the current hostname
--environment=ENVIRONMENT [Context] Provide the current environment
--current-time=CURRENT-TIME [Context] Provide the current date and time
--custom-context=CUSTOM-CONTEXT [Context] Custom context values in the format [contextName]=[contextValue], for example: myCustomContextField=someValue (multiple values allowed)
--expected=EXPECTED For use in testing, if this option is present, the exit code will be either 0 or 1 depending on whether the expectation matches the result
-h, --help Display help for the given command. When no command is given display help for the list command
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi|--no-ansi Force (or disable --no-ansi) ANSI output
-n, --no-interaction Do not ask any interactive question
-e, --env=ENV The Environment name. [default: "dev"]
--no-debug Switch off debug mode.
--profile Enables profiling (requires debug).
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
配置参考
这是自动生成的配置转储(通过运行 php bin/console config:dump unleash_client
)。
# Default configuration for extension with alias: "unleash_client" # Default configuration for extension with alias: "unleash_client" unleash_client: # You can provide the connection details as a DSN instead of app_url, instance_id and app_name. DSN takes precedence over individual parameters. dsn: null # Example: 'https://localhost:4242/api?instance_id=myCoolApp-Server1&app_name=myCoolApp' # The application api URL app_url: null # The instance ID, for Unleash it can be anything, for GitLab it must be the generated value instance_id: null # Application name, for Unleash it can be anything, for GitLab it should be a GitLab environment name app_name: null context: # The field name to use as user id, if set to null getUserIdentifier() or getUsername() method will be called user_id_field: null # Any additional context properties custom_properties: [] # Whether to enable communication with Unleash server or not. If you set it to false you must also provide a bootstrap. fetching_enabled: true # The http client service, must implement the Psr\Http\Client\ClientInterface or Symfony\Contracts\HttpClient\HttpClientInterface interface http_client_service: psr18.http_client # The request factory service, must implement the Psr\Http\Message\RequestFactoryInterface interface. Providing null means autodetect between supported default services. request_factory_service: null # The cache service, must implement the Psr\SimpleCache\CacheInterface or Psr\Cache\CacheItemPoolInterface interface cache_service: cache.app # Default bootstrap in case contacting Unleash servers fails. Can be a path to file (prefixed with file://) or a service implementing Unleash\Client\Bootstrap\BootstrapProvider (prefixed with @) bootstrap: null # Disabled default strategies, must be one of: default, flexibleRollout, gradualRolloutRandom, gradualRolloutSessionId, gradualRolloutUserId, remoteAddress, userWithId, applicationHostname disabled_strategies: [] # The interval at which to send metrics to the server in milliseconds metrics_send_interval: 30000 # Whether to allow sending feature usage metrics to your instance of Unleash, set this to false for GitLab metrics_enabled: true # Whether to allow automatic client registration on client initialization, set this to false for GitLab auto_registration: true # The time in seconds the features will stay valid in cache cache_ttl: 30 # The maximum age (in seconds) old features will be served from cache if http request fails for some reason stale_ttl: 1800 # Additional headers to use in http client, for Unleash "Authorization" is required custom_headers: [] # Enable or disable twig function/filter/tests twig: # Enables the "feature_is_enabled" and "feature_variant" twig functions functions: false # Enables the "feature_is_enabled" and "feature_variant" filters filters: false # Enables the "enabled" test, allowing you to write {% if "featureName" is enabled %} tests: false # Enables the "feature" twig tag tags: false