helis / settings-manager-bundle
Provides a nice way to define variables and inject them into application parts
Installs: 53 273
Dependents: 0
Suggesters: 0
Security: 0
Stars: 28
Watchers: 5
Forks: 16
Open Issues: 7
Type:symfony-bundle
Requires
- php: ^8.1
- ext-json: *
- doctrine/collections: ^1.5
- symfony/config: ^5.4|^6.3
- symfony/console: ^5.4|^6.3
- symfony/dependency-injection: ^5.4|^6.3
- symfony/http-kernel: ^5.4|^6.3
- symfony/serializer: ^5.4|^6.3
- symfony/yaml: ^5.4|^6.3
Requires (Dev)
- aws/aws-sdk-php: ^3.48
- doctrine/doctrine-bundle: ^1.8|^2.0
- doctrine/doctrine-fixtures-bundle: ^3.0
- doctrine/orm: ^2.6
- enqueue/enqueue: ^0.10
- friendsofsymfony/jsrouting-bundle: ^3
- knplabs/knp-menu-bundle: ^3.2
- lcobucci/jwt: ^4.0
- liip/test-fixtures-bundle: ^2.0.0
- paragonie/paseto: ^1.0
- phpbench/phpbench: ^1.0
- phpstan/phpstan: ^1.0
- phpstan/phpstan-phpunit: ^1.0
- phpunit/phpunit: ^10.0
- predis/predis: ^1.1
- rector/rector: ^1.0
- symfony/asset: ^5.4|^6.3
- symfony/browser-kit: ^5.4|^6.3
- symfony/form: ^5.4|^6.3
- symfony/framework-bundle: ^5.4|^6.3
- symfony/http-foundation: ^5.4|^6.3
- symfony/lock: ^5.4|^6.3
- symfony/monolog-bundle: ~3.7.0
- symfony/phpunit-bridge: ^5.4|^6.3
- symfony/security-bundle: ^5.4|^6.3
- symfony/twig-bundle: ^5.4|^6.3
- symfony/validator: ^5.4|^6.3
- symfony/web-profiler-bundle: ^5.4|^6.3
Suggests
- aws/aws-sdk-php: Allows to use aws ssm setting provider
- doctrine/orm: Allows to use orm setting provider
- enqueue/enqueue: Allows to use consumption extension for warming up settings during messages
- friendsofsymfony/jsrouting-bundle: Required to fully use provided user interface
- knplabs/knp-menu-bundle: Required to fully use provided user interface
- predis/predis: Allows to use decorating predis settings provider
- symfony/cache: Required by some settings providers
- symfony/form: Required for CRUD to work
- symfony/framework-bundle: Required for CRUD to work
- symfony/lock: Required by some settings providers
- symfony/monolog-bundle: Allows more advanced logging
- symfony/twig-bundle: Required for CRUD to work
- symfony/validator: Required for CRUD to work
This package is auto-updated.
Last update: 2024-11-16 07:07:05 UTC
README
Provides a nice way to define variables and inject them into application parts.
- Supporting
bool
,string
,int
,float
,array
as setting values. - Multiple providers.
- User interface.
Jump to
Quick start
-
composer require helis/settings-manager-bundle
-
Register bundle to
AppKernel.php
(Symfony3) orconfig/bundles.php
(Symfony4)
<?php class AppKernel extends Kernel { public function registerBundles() { return [ new Helis\SettingsManagerBundle\HelisSettingsManagerBundle(), ]; } }
- Add an example configuration to
app/config/config.yml
(Symfony3) orconfig/packages/settings_manager.yaml
(Symfony4)
helis_settings_manager: settings: - name: foo description: 'foo desc' type: bool data: false tags: - 'super_switch' - name: baz description: 'master toggle for awesome new feature' type: string data: fish tags: - 'experimental' - 'poo'
- Now, the easiest way to get settings in your services is by using
SettingsRouterAwareTrait
. The service will be automatically injected by autowire. Then just ask for setting:
use Helis\SettingsManagerBundle\Settings\Traits\SettingsRouterAwareTrait; class MuchAmazingService { use SettingsRouterAwareTrait; public function doSmth() { if ($this->settingsRouter->getBool('foo')) { // do it } // just do it } }
Usage
To get settings into your services, you have a few choices:
SettingsRouter
SettingsRouter is pretty straight-forward. It has one main method, called $settingsRouter->get($settingName, $default = null)
, which returns a setting of any type. If the setting is missing, default value will be returned. Other getters are aliases for get
but with declared return types and appropriate default values.
Throw exception on miss
In some cases throwing exception if setting not found might be desired behaviour. For this purpose, SettingsRouter
has mustGet($settingName)
and mustGet...($settingName)
for each aliased getter.
Service Tag
If you don't want to inject SettingsRouter
or wish for a cleaner service, service tags are here to help. First of all, the service must have a setter, which can be used to inject a setting value. For bool values, the bundle provides the SwitchableTrait
, which adds setEnabled
and isEnabled
methods. Then add a tag on your service with attributes setting
for setting name and method
for method name. Example:
AppBundle\Service\AmazingService: tags: - { name: settings_manager.setting_aware, setting: foo, method: setEnabled }
or the must
version
AppBundle\Service\AmazingService: tags: - { name: settings_manager.setting_aware, setting: foo, method: setEnabled, must: true }
Models
Helis\SettingsManagerBundle\Model\SettingModel
Base setting model.
Helis\SettingsManagerBundle\Model\DomainModel
Domain is like a group for settings. Setting cannot exist without domain. The default is named default
, which is also always enabled. Domain can hold only one setting with the same name. Settings with the same names must be in different domains. When a setting is requested, the one from a higher priority domain will be returned.
Helis\SettingsManagerBundle\Model\Type
Enum which holds supported types for setting. Values:
- STRING
- BOOL
- INT
- FLOAT
- YAML
- CHOICE
Setting providers
Settings can be pulled from multiple sources. Currently, the bundle comes with 4 settings providers. They can be configured and prioritized. If a setting with the same name will come from >1 providers, setting from provider with higher priority will override settings from lower priority providers.
Settings can be easily mutated in providers using user interface.
Settings providers:
And additional decorating providers:
Simple settings provider
Helis\SettingsManagerBundle\Provider\SimpleSettingsProvider
This is a provider, which only holds settings collections. Currently, it's being used to hold settings from configuration, but many more can be configured.
To configure additional simple providers, factory is provided because provider can only accept already denormalized objects.
Configuration example:
setting_provider_factory.foo: class: Helis\SettingsManagerBundle\Provider\Factory\SimpleSettingsProviderFactory arguments: $serializer: '@settings_manager.serializer' $normalizedData: - - name: foo description: 'foo desc' type: bool domain: { name: default } data: { value: false } tags: [{ name: 'super_switch' }] tags: - { name: settings_manager.provider_factory, provider: foo, priority: 10 }
DoctrineORM settings provider
Helis\SettingsManagerBundle\Provider\DoctrineOrmSettingsProvider
This is a provider which reads and saves settings using EntityManagerInterface
.
Required libraries:
composer require doctrine/orm
Configuration example:
- Doctrine configuration
# Symfony3, app/config/config.yml # Symfony4, config/packages/doctrine.yaml doctrine: orm: mappings: HelisSettingsManagerBundle: type: xml is_bundle: true dir: "Resources/config/doctrine" alias: HelisSettingsManagerBundle prefix: Helis\SettingsManagerBundle
- Create setting entity
<?php declare(strict_types=1); namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Helis\SettingsManagerBundle\Model\SettingModel; #[ORM\Entity()] #[ORM\Table(name: "setting")] class Setting extends SettingModel { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column(type: "integer")] protected int $id; }
-
Update your doctrine schema.
-
Register settings provider:
Helis\SettingsManagerBundle\Provider\DoctrineOrmSettingsProvider: arguments: $entityManager: '@doctrine.orm.default_entity_manager' $settingsEntityClass: 'App\Entity\Setting' tags: - { name: settings_manager.provider, provider: orm, priority: 20 }
Paseto cookie settings provider
Helis\SettingsManagerBundle\Provider\PasetoCookieSettingsProvider
This is a provider, which only enables existing settings by using a cookie. Cookies are encoded, so that they could not be randomly enabled by users.
Required libraries:
composer require paragonie/paseto
Paseto
is used to encrypt cookies.
Configuration example:
Helis\SettingsManagerBundle\Provider\PasetoCookieSettingsProvider: arguments: $serializer: '@settings_manager.serializer' tags: - { name: settings_manager.provider, provider: cookie, priority: 30 } - { name: kernel.event_subscriber }
Asymmetric Paseto cookie settings provider
Helis\SettingsManagerBundle\Provider\AsymmetricPasetoCookieSettingsProvider
This is a provider, which only enables existing settings by using a cookie. Cookies are encoded with asymmetric private and public keys, so that they could not be randomly enabled by users.
Required libraries:
composer require paragonie/paseto
Paseto
is used to encrypt cookies.
Configuration example:
Helis\SettingsManagerBundle\Provider\AsymmetricPasetoCookieSettingsProvider: arguments: $serializer: '@settings_manager.serializer' tags: - { name: settings_manager.provider, provider: asymmetric_cookie, priority: 40 } - { name: kernel.event_subscriber }
JWT Cookie settings provider
Helis\SettingsManagerBundle\Provider\JwtCookieSettingsProvider
This is a provider, which only enables existing settings by using a cookie. Cookies are encoded with asymmetric private and public keys, so that they could not be randomly enabled by users.
Required libraries:
composer require lcobucci/jwt
JWT
is used to encrypt cookies.
Configuration example:
Helis\SettingsManagerBundle\Provider\JwtCookieSettingsProvider: arguments: $serializer: '@settings_manager.serializer' $publicKey: 'file://%kernel.project_dir%/config/keys/settings_cookie_public.key' $privateKey: 'file://%kernel.project_dir%/config/keys/settings_cookie_private.key' tags: - { name: settings_manager.provider, provider: jwt_cookie, priority: 50 } - { name: kernel.event_subscriber }
AWS SSM settings provider
Helis\SettingsManagerBundle\Provider\AwsSsmSettingsProvider
This is a provider, which is used only for reading and updating existing ssm parameters as settings.
Required libraries:
composer require aws/aws-sdk-php
Configuration example:
Helis\SettingsManagerBundle\Provider\AwsSsmSettingsProvider: arguments: - '@Aws\Ssm\SsmClient' - '@settings_manager.serializer' - ['amazing_parameter_name'] tags: - { name: settings_manager.provider, provider: aws_ssm }
Phpredis decorating settings provider
Helis\SettingsManagerBundle\Provider\DecoratingRedisSettingsProvider
This provider is used to cache other settings providers like DoctrineORM or AWS SSM. It uses Redis client, not doctrine/cache providers or symfony/cache adapters because we want to take advantage of redis data structures for simplier invalidation process.
Required extensions:
pecl install redis-5.3.7
Configuration example:
Helis\SettingsManagerBundle\Provider\DecoratingRedisSettingsProvider: decorates: 'Helis\SettingsManagerBundle\Provider\DoctrineOrmSettingsProvider' arguments: $decoratingProvider: 'Helis\SettingsManagerBundle\Provider\DecoratingRedisSettingsProvider.inner' $redis: '@settings.cache.redis' # you need to register your own \Redis client in container $serializer: '@settings_manager.serializer'
Predis decorating settings provider
Helis\SettingsManagerBundle\Provider\DecoratingPredisSettingsProvider
Same as phpredis decorating settings provider It just replaces the phpredis extension with predis.
Required libraries:
composer require predis/predis
Cache decorating provider
Helis\SettingsManagerBundle\Provider\DecoratingCacheSettingsProvider
This provider is used to cache other settings providers that implements ModificationAwareSettingsProviderInterface
. At the moment supports phpredis decorating settings provider and predis decorating settings provider. It uses Symfony PHP Files Cache Adapter. Single change in decorating provider causes whole cache to be invalidated.
Supports symfony cache component adapters
Required libraries and extensions:
composer require symfony/cache symfony/lock
Configuration example:
settings_manager.decorating_provider.cache: class: 'Helis\SettingsManagerBundle\Provider\DecoratingCacheSettingsProvider' decorates: 'Helis\SettingsManagerBundle\Provider\DecoratingRedisSettingsProvider' arguments: $decoratingProvider: '@settings_manager.decorating_provider.cache.inner' $serializer: '@settings_manager.serializer' $cache: '@cache.settings' $lockFactory: '@symfony_flock_factory'
Settings provider mock
This is a special provider supposed to be used in tests only. Useful, when there is a need to mock mustGet...
calls.
Configuration example:
settings_manager.provider.mock: class: Helis\SettingsManagerBundle\Test\Provider\SettingsProviderMock tags: - { name: settings_manager.provider, provider: mock, priority: 9999 }
Mocking:
... use SettingsIntegrationTrait; protected function setUp() { parent::setUp(); SettingsProviderMock::addSetting( (new SettingModel()) ->setName('awesome_setting') ->setDomain( (new DomainModel()) ->setName('some_domain') ->setEnabled(true) ) ); } ...
Configuration reference
helis_settings_manager: settings: - name: foo description: 'foo desc' domain: default # Used for grouping settings. type: bool data: false tags: [super_switch] settings_router: treat_as_default_providers: ['config'] profiler: enabled: false logger: enabled: false service_id: null # Psr\Log\LoggerInterface service id settings_files: # - '%kernel.root_dir%/config/extra_settings.yml'
User interface
User interface can be used to change setting values, enable or disable domains.
-
Bundled user interface requires knp-menu-bundle, jsrouting-bundle.
composer require symfony/form symfony/validator symfony/translation symfony/twig-bundle symfony/asset knplabs/knp-menu-bundle friendsofsymfony/jsrouting-bundle
-
Include routing file.
# <=Symfony3, app/config/routing.yml # >=Symfony4, config/routes/settings_manager.yaml settings_manager: resource: '@HelisSettingsManagerBundle/Resources/config/routing.yaml' prefix: /settings
That's it. Now go to the /settings
path and you will see the settings user interface.
Twig
The Twig extension is also added to get settings in your twig templates. Just like in SettingsRouter
, first argument is the setting name and the second sets default value.
{{ setting_get('foo', false) }}
Controller
Helis\SettingsManagerBundle\Controller\Traits\SettingsControllerTrait
Adds a method to deny access, unless a setting is enabled. It's using SettingsRouter
, which, again, will be injected by autowire.
public function indexAction(): Response { $this->denyUnlessEnabled('index_page'); ... }
Contribution
New feature branches should be created from the master branch.