定制 fedale/setting-bundle 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

fedale/setting-bundle

Composer 安装命令:

composer require fedale/setting-bundle

包简介

Symfony bundle for runtime, multi-tenant application settings stored in the database

README 文档

README

Multi-tenant application settings stored in the database and editable at runtime — not Symfony parameters compiled into the container.

  • Per-tenant fallback: tenant Ntenant 0 (global) → caller-provided default.
  • Layered PSR-6 cache, automatically invalidated on every write.
  • Abstract storage (SettingStorageInterface): a Doctrine ORM bridge is included, but it can be swapped (API, file, Mongo, ...).
  • Free-form keys: no closed set, any string is a valid key.

Installation

composer require fedale/setting-bundle

Register the bundle (Symfony Flex does it for you):

// config/bundles.php
return [
    Fedale\SettingBundle\FedaleSettingBundle::class => ['all' => true],
];

Configuration (optional, defaults shown):

# config/packages/fedale_setting.yaml
fedale_setting:
    cache:
        enabled: true
        pool: cache.app
        ttl: null        # seconds; null = no expiry
    provider: doctrine   # or the id of a custom SettingStorageInterface service

Database schema

The bundle auto-registers the ORM mapping of the Setting entity; generate the migration in your app with php bin/console make:migration. Equivalent schema:

CREATE TABLE setting (
    id          INT AUTO_INCREMENT NOT NULL,
    tenant_id   INT NOT NULL,
    name        VARCHAR(255) NOT NULL,
    value       LONGTEXT NOT NULL,
    type        VARCHAR(20) NOT NULL DEFAULT 'string',
    active      TINYINT(1) NOT NULL DEFAULT 1,
    created_at  DATETIME NOT NULL,
    updated_at  DATETIME NOT NULL,
    PRIMARY KEY (id),
    UNIQUE KEY uniq_setting_tenant_name (tenant_id, name),
    KEY idx_setting_tenant_active (tenant_id, active)
);

tenant_id = 0 holds the global default configuration; tenant_id > 0 holds the per-tenant overrides.

value is stored as a string; type (string|int|float|bool|json) drives the (de)serialization: scalars stay human-readable (123, not "123"), complex values are stored as JSON under type = 'json'.

Usage

use Fedale\SettingBundle\Contract\SettingsManagerInterface;

final class GeneralController
{
    public function __construct(
        private readonly SettingsManagerInterface $settings,
    ) {
    }

    public function index(): Response
    {
        // tenant 12: "Cliente XYZ" if an override exists, otherwise the global default
        $title = $this->settings->get('general.title', 'Gestionale');
        $theme = $this->settings->get('general.theme', 'classic'); // inherited from tenant 0
        $useCache = $this->settings->get('general.useCache', false); // already a bool

        // write (current tenant, resolved by the TenantProvider)
        $this->settings->set('general.footer', '(c) 2026', type: 'string');
        $this->settings->set('general.useCache', true, type: 'bool');

        // write explicitly to a tenant / to the global scope
        $this->settings->set('general.title', 'Cliente XYZ', tenantId: 12);
        $this->settings->set('general.theme', 'dark', tenantId: 0); // default for everyone

        // ...
    }
}

Reading settings in Twig

When TwigBundle is installed, the bundle registers a setting() function. It is read-only — writes are done in PHP via SettingsManagerInterface::set().

Signature:

setting(key, default = null, tenantId = null)

Examples:

{# simple read with a default #}
<title>{{ setting('general.title', 'Gestionale') }}</title>

<footer>{{ setting('general.footer', '') }}</footer>

{# the value comes back already typed: a bool is a real bool #}
{% if setting('general.useCache', false) %}
    <meta name="cache" content="on">
{% endif %}

{# a 'json' value comes back as a navigable array/object #}
<ul>
{% for item in setting('menu.items', []) %}
    <li>{{ item.label }}</li>
{% endfor %}
</ul>

{# explicit tenant (usually unnecessary: the TenantProvider resolves it) #}
{{ setting('general.theme', 'classic', 12) }}

Key points:

  • The key is a free-form string — any setting created at runtime (including from an admin UI) is readable, with no registration required anywhere.
  • The per-tenant fallback applies: current tenant first, then tenant 0 (global), finally the default you pass in the template.
  • The function exists only if Twig is installed. In a Symfony app with TwigBundle that is already guaranteed; registration is conditional, see FedaleSettingBundle::loadExtension().

Multi-tenant: resolving the current tenant

When tenantId is not passed, the bundle uses TenantProviderInterface. By default (DefaultTenantProvider) the current tenant is always 0. Multi-tenant apps register their own implementation:

// src/Setting/RequestTenantProvider.php
use Fedale\SettingBundle\Contract\TenantProviderInterface;

final class RequestTenantProvider implements TenantProviderInterface
{
    public function __construct(private readonly RequestStack $stack) {}

    public function getCurrentTenantId(): int
    {
        return (int) $this->stack->getCurrentRequest()?->attributes->get('_tenant_id', 0);
    }
}
# config/services.yaml
Fedale\SettingBundle\Contract\TenantProviderInterface:
    alias: App\Setting\RequestTenantProvider

Custom storage

To use a source other than Doctrine, implement Fedale\SettingBundle\Contract\SettingStorageInterface and point fedale_setting.provider at the service id. Caching and the per-tenant fallback are still handled by the bundle.

Cache

The settings.0 and settings.{tenantId} layers are cached separately and merged in memory on each read. A set() only invalidates the layer it touches: changing a global default (tenant 0) therefore propagates to all tenants by invalidating a single entry.

License

MIT.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 1
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-25

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固