agence-adeliom/easy-config-bundle
Symfony bundle for EasyAdmin that adds a simple configuration manager stored in the database. Manage key/value settings from your EasyAdmin dashboard, include ready-made menu entry via a trait, and read values in Twig with easy_config().
Installation:
composer require agence-adeliom/easy-config-bundle
Ensure your config/packages/easy_config.yaml exists (created automatically by Flex).
Database Setup: Run migrations:
php bin/console doctrine:migration:diff
php bin/console doctrine:migration:migrate
Or update schema directly:
php bin/console doctrine:schema:update --force
First Use Case:
Define a configuration entity (e.g., app/config/Config.php):
namespace App\Config;
use Adeliom\EasyConfigBundle\Entity\Config;
class MyConfig extends Config
{
// Custom fields (e.g., public properties or getters/setters)
public string $mySetting;
}
Register it in config/packages/easy_config.yaml:
adeliom_easy_config:
configs:
my_config: App\Config\MyConfig
Accessing Config:
Inject the ConfigManager service and fetch your config:
use Adeliom\EasyConfigBundle\Manager\ConfigManager;
class MyService
{
public function __construct(private ConfigManager $configManager) {}
public function getSetting(): string
{
return $this->configManager->get('my_config')->mySetting;
}
}
CRUD via EasyAdmin:
config/easyadmin.yaml:
easy_admin:
entities:
App\Config\MyConfig:
class: Adeliom\EasyConfigBundle\EasyAdmin\ConfigCrudController
label: 'My Config'
Configuration Hierarchy:
global, tenant) to manage multi-environment configs:
$configManager->get('my_config', 'tenant_123');
easy_config.yaml:
adeliom_easy_config:
configs:
my_config:
class: App\Config\MyConfig
scopes: ['global', 'tenant']
Validation and Defaults:
Assert\NotBlank).ConfigManager:
$config = $configManager->get('my_config', 'default');
$config->mySetting = $config->mySetting ?? 'default_value';
$configManager->save($config);
Event Listeners:
ConfigUpdatedEvent) to react to changes:
use Adeliom\EasyConfigBundle\Event\ConfigUpdatedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MySubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
ConfigUpdatedEvent::class => 'onConfigUpdated',
];
}
public function onConfigUpdated(ConfigUpdatedEvent $event): void
{
// Handle updates (e.g., cache invalidation)
}
}
Dependency Injection:
ConfigManager over service locator:
// Good
public function __construct(private ConfigManager $configManager) {}
// Avoid
$this->configManager = $container->get(ConfigManager::class);
Caching:
# config/packages/easy_config.yaml
adeliom_easy_config:
cache: true
cache_lifetime: 3600 # 1 hour
php bin/console cache:clear
Environment-Specific Configs:
%env% placeholders in config values:
class MyConfig extends Config
{
public string $apiKey = '%env(API_KEY)%';
}
Testing:
ConfigManager in tests:
$mockConfig = $this->createMock(MyConfig::class);
$mockConfig->method('getMySetting')->willReturn('test_value');
$configManager = $this->createMock(ConfigManager::class);
$configManager->method('get')->with('my_config')->willReturn($mockConfig);
Migration Conflicts:
Config entity (e.g., add fields), run:
php bin/console doctrine:migration:diff
Circular Dependencies:
ConfigA uses ConfigB), load them in a specific order:
$configA = $configManager->get('config_a');
$configB = $configManager->get('config_b');
$configA->setDependency($configB); // Safe after both are loaded
EasyAdmin Overrides:
use Adeliom\EasyConfigBundle\EasyAdmin\ConfigCrudController;
class CustomConfigCrudController extends ConfigCrudController
{
public static function getEntityFqcn(): string
{
return MyConfig::class;
}
public function configureFields(string $pageName): iterable
{
return [
// Custom fields here
];
}
}
easyadmin.yaml:
easy_admin:
entities:
App\Config\MyConfig:
class: App\EasyAdmin\CustomConfigCrudController
Scopes and Fallbacks:
global if not specified. Ensure fallback logic:
$tenantConfig = $configManager->get('my_config', 'tenant_123');
if (!$tenantConfig->isValid()) {
$tenantConfig = $configManager->get('my_config', 'global');
}
Performance with Large Configs:
// Bad: Loads all configs
$allConfigs = $configManager->getAll();
// Good: Load specific config
$config = $configManager->get('my_config');
Enable Debug Mode:
debug: true in easy_config.yaml to log config operations:
adeliom_easy_config:
debug: true
Check Database:
adeliom_easy_config_config table:
SELECT * FROM adeliom_easy_config_config WHERE name = 'my_config';
Event Dispatching:
services.yaml:
services:
App\EventSubscriber\MySubscriber:
tags: ['kernel.event_subscriber']
Clear Cache:
php bin/console cache:clear
Custom Config Storage:
ConfigStorageInterface:
use Adeliom\EasyConfigBundle\Storage\ConfigStorageInterface;
class CustomConfigStorage implements ConfigStorageInterface
{
public function save(Config $config): void
{
// Custom logic (e.g., Redis, API)
}
public function get(string $name, ?string $scope = null): ?Config
{
// Custom logic
}
}
easy_config.yaml:
adeliom_easy_config:
storage: App\Storage\CustomConfigStorage
Dynamic Configs:
ConfigManager to generate configs dynamically:
$config = new MyConfig();
$config->name = 'dynamic_' . uniqid();
$configManager->save($config);
Serialization:
Config to handle complex data (e.g., arrays) via __serialize()/__unserialize():
class ComplexConfig extends Config
{
private array $nestedData = [];
public function __serialize(): array
{
return ['nestedData' => $this->nestedData];
}
public function __unserialize(array $data): void
{
$this->nestedData = $data['nestedData'];
}
}
How can I help you explore Laravel packages today?