Installation:
composer require rvanlaak/settings-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Rvanlaak\SettingsBundle\RvanlaakSettingsBundle::class => ['all' => true],
];
Database Migration:
Run the bundle’s migration to create the settings table:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First Use Case:
Inject SettingsManager in a controller/service:
use Rvanlaak\SettingsBundle\Manager\SettingsManagerInterface;
public function __construct(private SettingsManagerInterface $settingsManager) {}
public function configureSettings()
{
$this->settingsManager->set('site_name', 'MyApp');
$globalName = $this->settingsManager->get('site_name'); // 'MyApp'
}
Twig Integration:
Use the get_setting() function in templates:
<h1>{{ get_setting('site_name') }}</h1>
Global vs. User-Specific Settings:
set('key', 'value')/get('key') for app-wide settings.User object as the second argument:
$this->settingsManager->set('theme', 'dark', $user);
$userTheme = $this->settingsManager->get('theme', $user);
Validation with Forms: Define a form type for settings validation:
use Rvanlaak\SettingsBundle\Form\SettingsType;
$form = $this->createForm(SettingsType::class, $settingsData);
if ($form->isSubmitted() && $form->isValid()) {
$this->settingsManager->setMultiple($form->getData());
}
Serialization:
serialize() (compact, fast).config/packages/rvanlaak_settings.yaml:
rvanlaak_settings:
serialization: json
Caching: Enable PSR-6 cache (e.g., Symfony Cache) for performance:
rvanlaak_settings:
cache: cache.app
Scopes:
Use custom scopes (e.g., role, tenant) by extending the Scope class:
$this->settingsManager->set('max_uploads', 10, ['scope' => 'admin']);
$this->settingsManager->get('max_uploads', null, ['scope' => 'admin']);
Event Listeners:
Listen to settings.update or settings.delete events for side effects:
use Rvanlaak\SettingsBundle\Event\SettingsEvent;
public function onSettingsUpdate(SettingsEvent $event) {
// Log or notify when settings change
}
Dependency Injection: Prefer constructor injection over service locator:
public function __construct(
private SettingsManagerInterface $settingsManager,
private SettingsRepositoryInterface $settingsRepository
) {}
Testing:
Use the SettingsManager mock in tests:
$mockSettings = $this->createMock(SettingsManagerInterface::class);
$mockSettings->method('get')->willReturn('test_value');
CLI Management: Create a custom command to bulk-update settings:
use Rvanlaak\SettingsBundle\Manager\SettingsManagerInterface;
class UpdateSettingsCommand extends Command {
protected function execute(InputInterface $input, OutputInterface $output) {
$this->settingsManager->setMultiple([
'key1' => 'value1',
'key2' => 'value2',
]);
}
}
Serialization Conflicts:
serialize for non-PHP-standard types.Rvanlaak\SettingsBundle\Serializer\SerializerInterface.Cache Invalidation:
cache:clear or manually invalidate the cache tag:
$this->settingsManager->set('key', 'value', [], ['cache_tag' => 'settings']);
Scope Ambiguity:
user + role) may lead to unexpected precedence.$this->settingsManager->get('key', $user, ['scope' => 'user:premium']);
Doctrine Events:
prePersist, preUpdate, and preRemove events. Avoid infinite loops by not modifying settings in these events.Legacy dmissh/settings-bundle:
composer.json and autoloader reflect rvanlaak/settings-bundle.Query Logging: Enable Doctrine debug mode to inspect SQL queries:
doctrine:
dbal:
logging: true
profiling: true
Setting Existence: Check if a setting exists before fetching:
if ($this->settingsManager->has('key')) {
$value = $this->settingsManager->get('key');
}
Serialization Errors: Wrap JSON serialization in a try-catch:
try {
$this->settingsManager->set('data', $complexObject, null, [], 'json');
} catch (\RuntimeException $e) {
// Fallback to serialize or log the error
}
Custom Serializers:
Implement Rvanlaak\SettingsBundle\Serializer\SerializerInterface for custom formats (e.g., YAML):
use Rvanlaak\SettingsBundle\Serializer\SerializerInterface;
class YamlSerializer implements SerializerInterface {
public function serialize($data) { /* ... */ }
public function unserialize($data) { /* ... */ }
}
Register in services.yaml:
rvanlaak_settings.serializer.yaml:
class: App\Serializer\YamlSerializer
tags: ['rvanlaak_settings.serializer']
Custom Scopes:
Extend Rvanlaak\SettingsBundle\Model\Scope for multi-level scopes (e.g., tenant:user):
class TenantScope extends Scope {
public function getKey(): string {
return 'tenant:' . $this->getValue();
}
}
Validation Rules:
Add custom constraints to SettingsType:
use Symfony\Component\Validator\Constraints as Assert;
$builder->add('key', Assert\Type(['type' => 'string', 'message' => 'Must be a string']));
Event Subscribers:
Subscribe to SettingsEvents for real-time updates:
use Rvanlaak\SettingsBundle\Event\SettingsEvents;
public static function getSubscribedEvents() {
return [
SettingsEvents::SETTINGS_UPDATE => 'onSettingsUpdate',
];
}
Default Serialization:
The default (serialize) may not work for objects with circular references. Use JSON for such cases.
Cache TTL:
Configure cache lifetime in rvanlaak_settings.yaml:
rvanlaak_settings:
cache_ttl: 3600 # 1 hour
Environment-Specific Settings: Use Symfony’s parameter bag to override settings per environment:
# config/packages/dev/rvanlaak_settings.yaml
rvanlaak_settings:
default_values:
debug_mode: true
Doctrine Entity Manager:
Ensure the bundle uses the same EM as your app. Configure in config/packages/rvanlaak_settings.yaml:
rvanlaak_settings:
entity_manager: default # or 'custom_em'
How can I help you explore Laravel packages today?