Installation
composer require digipolisgent/setting-bundle
Enable the bundle in config/bundles.php:
return [
// ...
DigipolisGent\SettingBundle\DigipolisGentSettingBundle::class => ['all' => true],
];
Define an Entity Type
Extend your entity with SettingImplementationTrait and implement getSettingImplementationName():
use DigipolisGent\SettingBundle\Model\SettingImplementationTrait;
class Product
{
use SettingImplementationTrait;
public function getSettingImplementationName(): string
{
return 'product'; // Unique identifier for this entity type
}
}
Create a Data Provider
Define settings dynamically via a service tagged as setting.data_provider:
# config/services.yaml
services:
App\Setting\ProductSettingsProvider:
tags:
- { name: 'setting.data_provider', entity: 'product' }
Implement SettingDataProviderInterface:
class ProductSettingsProvider implements SettingDataProviderInterface
{
public function getSettings(): array
{
return [
'discount_rate' => [
'type' => 'integer',
'label' => 'Discount Rate (%)',
'required' => true,
'validation' => ['min' => 0, 'max' => 100],
],
'is_featured' => [
'type' => 'boolean',
'label' => 'Featured Product',
],
];
}
}
Access Settings in Forms
Use the SettingType form field in your entity forms:
$builder->add('settings', SettingType::class, [
'entity' => new Product(), // or class name as string
]);
Add dynamic settings to a Product entity (e.g., discount rates, featured status) without modifying the database schema. Retrieve these settings anywhere in the app via the SettingManager service:
$product = $entityManager->getRepository(Product::class)->find(1);
$settings = $this->settingManager->getSettings($product);
// Returns: ['discount_rate' => 15, 'is_featured' => true]
ProductSettingsProvider for all product-related settings).entity value.dev_product_settings_provider).SettingType field dynamically builds forms based on your data provider’s definitions.shipping.rules) by using dot notation in the provider:
return [
'shipping.rules' => [
'type' => 'array',
'label' => 'Shipping Rules',
'entry_type' => 'text', // or custom form type
],
];
validation key in the provider.SettingManager to fetch settings for any entity:
$settings = $this->settingManager->getSetting($entity, 'discount_rate');
SettingManager:
$this->settingManager->getSetting($entity, 'is_featured', false);
ColorPickerType) and reference them in the provider:
'primary_color' => [
'type' => 'custom_color_picker',
'label' => 'Primary Color',
],
Register the type as a service with the tag setting.form.type.settings column (add this to your entity if missing):
/**
* @ORM\Column(type="json")
*/
private $settings = [];
settings column if retrofitting to existing entities.setting filter:
{% set discount = product|setting('discount_rate') %}
Price: {{ product.price * (1 - discount/100)|round(2) }}€
{% if product|setting('is_featured') %}
<div class="featured-badge">Featured</div>
{% endif %}
Serializer to normalize settings in API responses:
$serializer->normalize($product->getSettings());
settings field in your API resource.Data Provider Registration
setting.data_provider or using the wrong entity value.services.yaml and ensure getSettingImplementationName() matches the entity tag.digipolis_gent_setting.data_providers service container dump to confirm registration.Circular References in Settings
related_products) can cause serialization errors.$settings['related_products'] = array_map(fn($p) => $p->getId(), $relatedProducts);
Validation Overrides
validation keys sparingly or disable entity validation for the settings field:
/**
* @Assert\Valid
* @ORM\Column(type="json")
*/
private $settings;
Then handle validation purely in the provider.Performance with Large Settings
Setting entity.Case Sensitivity
Discount_Rate ≠ discount_rate).Check Registered Providers Dump all registered providers to verify configuration:
$providers = $container->getParameter('digipolis_gent_setting.data_providers');
dump($providers);
Inspect Stored Settings Query the database directly to verify settings are stored correctly:
SELECT settings FROM product WHERE id = 1;
Form Debugging
Enable form debugging in config/packages/dev/debug.yaml:
framework:
form: { enabled: true }
Then inspect the rendered form HTML for errors.
Event Listeners
Listen to SettingManagerEvents to debug setting retrieval:
$eventDispatcher->addListener(SettingManagerEvents::SETTING_PRE_LOAD, function (SettingEvent $event) {
error_log('Loading setting: ' . $event->getName());
});
Use Events for Side Effects
Trigger actions when settings change by listening to SettingManagerEvents:
$eventDispatcher->addListener(SettingManagerEvents::SETTING_POST_SAVE, function (SettingEvent $event) {
if ($event->getName() === 'is_featured' && $event->getValue()) {
$this->analyticsService->track('product_featured', $event->getEntity());
}
});
Localization Localize setting labels dynamically:
return [
'discount_rate' => [
'type' => 'integer',
'label' => 'app.settings.discount_rate', // Translatable key
'label_parameters' => ['%entity%' => $entity->getName()],
],
];
Use Symfony’s translation system to manage labels.
Soft Deletes
Handle soft-deleted entities by overriding the provider’s supports() method or filtering in getSettings().
Testing
Mock the SettingManager in
How can I help you explore Laravel packages today?