Developed with love by KnpLabs Hire us for your project!
34

settings-manager-bundle

by HelisLT

Symfony bundle to define variables and inject them into application parts

Helis Settings Manager Bundle

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.

Build Status
Latest Stable Version
License

Jump to

Quick start

  1. composer require helis/settings-manager-bundle

  2. Register bundle to AppKernel.php (Symfony3) or config/bundles.php (Symfony4)

<?php

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        return [
            new Helis\SettingsManagerBundle\HelisSettingsManagerBundle(),
        ];
    }
}
  1. Add an example configuration to app/config/config.yml (Symfony3) or config/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'
  1. 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.

Method name Default value Declared return type
getString '' string
getBool false bool
getInt 0 int
getFloat 0.0 float
getArray [] array

Service Tag

If you dont 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.setting_aware, setting: foo, method: setEnabled }

Models

Helis\SettingsManagerBundle\Model\SettingModel

Base setting model.

Property Type Description
$name string Setting name
$description string Setting descrption
$domain DomainModel Domain model
$tags Collection[Tag] Collection of tags
$type Enum[Type] Determines setting value type
$data array Holds actual value for setting
$providerName string Internal field to know from which provider this setting is

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.

Property Type Description
$name string Domain name
$priority int (default: 0) Domain priority
$enabled bool (default: false) Is domain enabled indication
$readOnly bool (default: false) is domain only readable indication

Helis\SettingsManagerBundle\Model\Type

Enum which holds supported types for setting. Values:

  • STRING
  • BOOL
  • INT
  • FLOAT
  • YAML

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 2 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\AwsSsmSettingsProvider

This is a provider which reads and saves settings using EntityManagerInterface.

Required libraries:

Configuration example:

  1. Doctrine configuration
# Symfony3, app/config/config.yml
# Symfony4, config/packages/doctrine.yaml
doctrine:
    orm:
        mappings:
            HelisSettingsManagerBundle:
                type: yml
                is_bundle: true
                dir: "Resources/config/doctrine"
                alias: HelisSettingsManagerBundle
                prefix: Helis\SettingsManagerBundle
  1. 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
{
    /**
     * @var int
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    protected $id;
}
  1. Update your doctrine schema.

  2. 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 }

Cookie settings provider

Helis\SettingsManagerBundle\Provider\CookieSettingsProvider

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:

  • paragonie/paseto

    composer require paragonie/paseto

    Paseto is used to encrypt cookies.

    Configuration example:

Helis\SettingsManagerBundle\Provider\CookieSettingsProvider:
    arguments:
        $serializer: '@settings_manager.serializer'
    tags:
        - { name: settings_manager.provider, provider: cookie, priority: 30 }
        - { 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:

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:

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:

Configuration reference

helis_settings_manager:
    settings:
        -
            name: foo
            description: 'foo desc'
            domain: default # Used for grouping settings.
            type: bool
            data: false
            tags: [super_switch]
    profiler:
        enabled: false
    logger:
        enabled: false
        service_id: null # Psr\Log\LoggerInterface service id
    access_control:
        enabled: false
    settings_files:
        # - '%kernel.root_dir%/config/extra_settings.yml'

User interface

User interface can be used to change setting values, enable or disable domains.

  1. Bundled user interface requires knp-menu-bundle, jsrouting-bundle.

    composer require knplabs/knp-menu-bundle friendsofsymfony/jsrouting-bundle

  2. Include routing file.

# Symfony3, app/config/routing.yml 
# Symfony4, config/routes/settings_manager.yaml

settings_manager:
    resource: '@HelisSettingsManagerBundle/Resources/config/routing.yml'
    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.

Copyright 2018 Helis LT

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

  • Merge pull request #18 from martiis/switchable-command-controller
    By web-flow, 27 days ago
  • Merge pull request #19 from klizas/master
    By web-flow, 27 days ago
  • Moved additional parameters from constructor to setters.
    By , 27 days ago
  • Added ability to change cookie's path and domain.
    By klizas, 27 days ago
  • added SwitchableControllerSubscriberTest
    By martiis, 27 days ago
  • tests refactoring, added SwitchableCommandSubscriberTest
    By martiis, 27 days ago
  • added switchable command and controller interfaces
    By martiis, 28 days ago
  • Merge pull request #14 from martiis/redis-decorators-fix
    By web-flow, 28 days ago
  • added setting name check in ssm provider before save
    By martiis, 28 days ago
  • making sure all keys are namespaced in redis decorators
    By martiis, 28 days ago
  • Merge pull request #13 from asilgalis/aws-ssm-provider-no-fetch-cache
    By web-flow, 1 month ago
  • Update AwsSsmSettingsProvider to fetch parameters from Aws Ssm on every time setting is requested
    By Andrius Šilgalis, 1 month ago
  • Add test for save parameter to aws ssm
    By Andrius Šilgalis, 1 month ago
  • Add tests to make sure calls aws sms client only once
    By Andrius Šilgalis, 1 month ago
  • Additional tests with multiple parameters
    By Andrius Šilgalis, 1 month ago
  • Update tests for AwsSsmSettingsProvider
    By Andrius Šilgalis, 1 month ago
  • Add test for AwsSsmSettingsProvider with single parameter
    By Andrius Šilgalis, 1 month ago
  • Add initial unit test for AwsSsmSettingsProvider
    By Andrius Šilgalis, 1 month ago
  • Merge pull request #11 from martiis/full-settings-in-cookies
    By web-flow, 1 month ago
  • Settings are now fully saved into cookies
    By martiis, 1 month ago
  • Merge pull request #10 from martiis/doctrine-entity-save-fix
    By web-flow, 1 month ago
  • tag test fixtures
    By martiis, 1 month ago
  • Doctrine provider entity save fix
    By martiis, 1 month ago
  • Merge pull request #9 from andrius-kulbis/fix-orm-provider-tags
    By web-flow, 2 months ago
  • Fix ORM provider tag entity class injection
    By Andrius Kulbis, 2 months ago
  • Merge pull request #8 from martiis/master
    By web-flow, 3 months ago
  • Tests reorganization
    By martiis, 3 months ago
  • Updated README.md with packagist badges
    By web-flow, 3 months ago
  • Merge pull request #7 from martiis/liip-bundle-update
    By web-flow, 3 months ago
  • Update liip/functional-test-bundle
    By martiis, 3 months ago