2lenet / config-bundle
Config Bundle
Requires
- php: ^8.4
- 2lenet/crudit-bundle: ^1.12
- doctrine/doctrine-bundle: ^2.0 || ^3.0
- doctrine/orm: ^2.6,>=2.6.3 || ^3.0
- doctrine/persistence: ^2.0 || ^3.0 || ^4.0
- symfony/framework-bundle: ^7.0 || ^8.0
- symfony/security-core: ^7.0 || ^8.0
- symfony/string: ^7.0 || ^8.0
- twig/twig: ^3.4 || ^4.0
Requires (Dev)
- 2lenet/credential-bundle: ^3.1
- ergebnis/phpstan-rules: ^2.1
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-doctrine: ^2.0
- phpstan/phpstan-mockery: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^10.0
- slevomat/coding-standard: ^8.0
- squizlabs/php_codesniffer: ^3.5
Suggests
- 2lenet/credential-bundle: Declares the ROLE_CONFIG_ACTION_* roles of the "group_roles" option (lle:credential:warmup)
Provides
None
Conflicts
None
Replaces
None
- dev-main
- 1.6.0
- 1.5.3
- 1.5.2
- 1.5.1
- 1.5.0
- 1.4.5
- 1.4.4
- 1.4.3
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.0
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.2
- 1.0.1
- 1.0.0
- dev-fix/config-table-name
- dev-feat/config-group-roles
- dev-fix/config-corrections
- dev-feat/config-sidebar
- dev-fix/libelle_nullable
- dev-feat/sf8
- dev-null-on-text
- dev-textarea
- dev-fix/transLabel
- dev-fix/translatableLabel
- dev-feature/translatable_field
- dev-password-set-empty
- dev-password-type
- dev-sebheitzmann-patch-1
- dev-feature/cache-multitenant
- dev-config_cache
- dev-config_warmup
- dev-ModifController
- dev-sf-7
- dev-majSfInsight
- dev-AddService
- dev-label_traductible
- dev-feature/add-twig-function
- dev-edit_in_place
- dev-initBundle
This package is auto-updated.
Last update: 2026-11-09 10:15:45 UTC
README
Symfony bundle that gives you an easy configuration for your app. Perfect to use with the famous CRUD Crudit
- Installation
- Customization
- Usage
- Initialise new configurations (Warm-up)
- Restrict access by group (roles)
Installation
The bundle is not yet on packagist make sure to add the following to your composer.json file:
{
"url": "https://github.com/2lenet/ConfigBundle",
"type": "git"
}
Install with composer:
composer require 2lenet/config-bundle
The bundle is flexible and built to suit your project it is shiped only with trait to use in your own config entity.
You will also get a Symfony Repository ready to use.
Create in your entity directory the class Config it has to implements the ConfigInterface if no customization is
needed you can use:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Lle\ConfigBundle\Traits\ConfigTrait; use App\Repository\ConfigRepository; use Lle\ConfigBundle\Contracts\ConfigInterface; /** * @ORM\Entity(repositoryClass=ConfigRepository::class) */ class Config implements ConfigInterface { use ConfigTrait; }
Your repository file has to extend the ConfigRepository from the bundle:
<?php namespace App\Repository; use App\Entity\Config; use Doctrine\Persistence\ManagerRegistry; use Lle\ConfigBundle\Repository\AbstractConfigRepository; use Lle\ConfigBundle\Service\CacheManager; /** * @method Config|null find($id, $lockMode = null, $lockVersion = null) * @method Config|null findOneBy(array $criteria, array $orderBy = null) * @method Config[] findAll() * @method Config[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ class ConfigRepository extends AbstractConfigRepository { public function __construct(ManagerRegistry $registry, CacheManager $cacheManager) { parent::__construct($cacheManager, $registry, Config::class); } ... }
In your project add the folowing to the config file: /config/packages/doctrine.yaml
doctrine: orm: resolve_target_entities: Lle\ConfigBundle\Contracts\ConfigInterface: App\Entity\Config
In /config/routes.yaml add:
lle_config: resource: "@LleConfigBundle/Resources/config/routes.yaml"
You can then create a migration
bin/console make:migration
Check the migration file created and ask doctrine to execute the migration :
bin/console doctrine:migrations:migrate
You are ready to go!
Customization
If you need more options or entity fields you can add them in your entity class:
<?php namespace App\Entity; use App\Repository\ConfigRepository; use Doctrine\ORM\Mapping as ORM; use Lle\ConfigBundle\Contracts\ConfigInterface; use Lle\ConfigBundle\Traits\ConfigTrait; /** * @ORM\Entity(repositoryClass=ConfigRepository::class) */ class Config implements ConfigInterface { use ConfigTrait; /** * @ORM\ManyToOne(targetEntity=Establishment::class, inversedBy="configs") * @ORM\JoinColumn(nullable=false) */ private ?Establishment $establishment; public function getEstablishment(): ?Establishment { return $this->establishment; } public function setEstablishment(?Establishment $establishment): self { $this->establishment = $establishment; return $this; } }
You may also need more options than the ones in the Repository file, in that case create a new repository class in your project. Don't forget to update the namspace used in your entity (see previous exemple).
Usage
General overview
To use the bundle, inject in your services the config repository and use one of the available methods. The bundle will check if the configuration exist otherwise a new configuration will be created.
Supported configurations
The bundle offers support for configuration in the following formats:
| Type | Constant | Stored in | Notes |
|---|---|---|---|
Bool |
ConfigInterface::BOOL |
valueBool |
Switch. |
String |
ConfigInterface::STRING |
valueString |
Short text. |
Text |
ConfigInterface::TEXT |
valueText |
Long text (textarea). |
Int |
ConfigInterface::INT |
valueInt |
Integer. |
Float |
ConfigInterface::FLOAT |
valueFloat |
Decimal number. |
Password |
ConfigInterface::PASSWORD |
valueString |
Secret: masked on the screen. See group roles. |
A Password is stored like a String (it is not encrypted in the database). The difference is on the screen: the value is
masked, never sent to the browser without the SECRET role of its group (when the group_roles option is enabled)
and it is edited in a password input.
Available methods
Every method belongs to your config repository (AbstractConfigRepository). The optional $tenantId is explained in
Reading and writing.
| Type | Read | Write | Initialise (keeps an existing value) |
|---|---|---|---|
Bool |
getBool($group, $label, bool $default, ?int $tenantId = null): bool |
setBool($group, $label, bool $value, ?int $tenantId = null): void |
initBool($group, $label, bool $default, ?int $tenantId = null): bool |
String |
getString($group, $label, string $default, ?int $tenantId = null): string |
setString($group, $label, string $value, ?int $tenantId = null): void |
initString($group, $label, string $default, ?int $tenantId = null): string |
Text |
getText($group, $label, string $default, ?int $tenantId = null): string |
setText($group, $label, string $value, ?int $tenantId = null): void |
initText($group, $label, string $default, ?int $tenantId = null): string |
Int |
getInt($group, $label, int $default, ?int $tenantId = null): int |
setInt($group, $label, int $value, ?int $tenantId = null): void |
initInt($group, $label, int $default, ?int $tenantId = null): int |
Float |
getFloat($group, $label, float $default = 0, ?int $tenantId = null): float |
setFloat($group, $label, float $value, ?int $tenantId = null): void |
initFloat($group, $label, float $default, ?int $tenantId = null): float |
Password |
getPassword($group, $label, string $default, ?int $tenantId = null): string |
setPassword($group, $label, string $value, ?int $tenantId = null): void |
initPassword($group, $label, string $default, ?int $tenantId = null): string |
$apiUrl = $configRepository->getString('Saferpay', 'url', 'https://example.test'); $secret = $configRepository->getPassword('Saferpay', 'password', ''); $configRepository->setBool('Mails', 'copy', true, $tenantId);
getPassword() returns the real value: the masking only concerns the configuration screen, not your code.
Twig integration
{{ get_config_value('type', 'group', 'label', 'default') }}
type is one of Bool, String, Text, Int, Float or Password. The default is converted to that type, and an unknown
type returns null.
Avoid printing a
Passwordin a template.
Initialise new configurations (Warm-up)
A command allows you to initialise new configurations. We suggest to execute it everytime your app starts.
bin/console lle:config:warmup
To configure the default values, create a class that implements WarmupInterface.
<?php namespace App\Warmup; use Lle\ConfigBundle\Contracts\WarmupInterface; use Lle\ConfigBundle\Repository\AbstractConfigRepository; class ConfigWarmup implements WarmupInterface { public function warmup(AbstractConfigRepository $configRepository): void { $configRepository->initBool('CONFIG', 'active', true); $configRepository->initPassword('CONFIG', 'api_secret', ''); } }
Do not use set*(), because it will overwrite defined configurations.
Reading and writing
- Without a
$tenantId, the methods read and write the global value only (tenantId IS NULL), never the value of a tenant. get*()andinit*()create a missing key with its default by a plainINSERTon the config table: they never flush the EntityManager, so the pending changes of the calling code are left untouched.set*()is a write: it flushes the EntityManager, as before.
Configuration screen
Values are edited in place on the list (/config), through the Crudit editdata route. With Crudit 1.21 or later
(lle_crudit.eip_strict, enabled by default), editdata only accepts the fields returned by getEipFields(): the bundle
declares there the value field of each type (valueBool, valueString for String and Password, valueText, valueInt,
valueFloat), editable only on a configuration of that type. Any other field (group, valueType, tri…) is refused
with a 403. Nothing to configure in the application.
The list displays up to 500 configurations on one page. Beyond that, the group sidebar only lists the groups of the current page.
Restrict access by group (roles)
By default everybody who can open the configuration screen sees and edits every configuration. With the group_roles
option, access is decided group by group (the group field of a configuration) with roles managed by the
credential bundle.
Enabling
# config/packages/lle_config.yaml lle_config: group_roles: true # default: false (everything allowed, as before)
The bundle works without the credential bundle while the option is disabled. To use the option, install it:
composer require 2lenet/credential-bundle
Roles
| Role | Effect |
|---|---|
ROLE_CONFIG_ACTION_SHOW_GROUP_<GROUP> |
The group is visible, in read only. |
ROLE_CONFIG_ACTION_EDIT_GROUP_<GROUP> |
The values of the group can be edited (implies SHOW). |
ROLE_CONFIG_ACTION_SECRET_GROUP_<GROUP> |
Passwords of the group can be read (SHOW) or edited (with EDIT). |
ROLE_CONFIG_ACTION_SHOW_ALL |
Same as SHOW, for every group. |
ROLE_CONFIG_ACTION_EDIT_ALL |
Same as EDIT, for every group. |
ROLE_CONFIG_ACTION_SECRET_ALL |
Same as SECRET, for every group. |
<GROUP> is the group name in upper case, slugged with _ as separator: Saferpay becomes SAFERPAY,
Payment Service becomes PAYMENT_SERVICE.
Accents and separators are dropped by the slug, so groups whose names only differ by them share their roles:
Généralités and Generalites, or Payment-Service and Payment Service. A group named with symbols only (***)
has an empty slug: it gets no group role and is only reached by the *_ALL roles.
Rules:
EDITimpliesSHOW.SECRETalone does not make a group visible: the group also needsSHOWorEDIT.- A Password configuration is masked (
••••••••) and never sent in the HTML withoutSECRET. WithSECRETandSHOWit is revealed on click, in read only. Editing it requiresEDITandSECRET. - A group without any role is not listed, and its configurations answer "not found" on a direct URL. The in-place edit of such a configuration answers 400 (bad request), not 403: the existence of the configuration is not revealed.
- Writes are checked on the server too: only the value field of the configuration type can change, with the rights above. A refused change is not saved: a configuration cannot be moved to another group, a Password cannot be turned into another type, and no other field of the entity can be written from the screen.
- The SecurityBundle is needed: without it, the option refuses everything.
Do not add these roles to role_hierarchy: the credential bundle manages them.
Declaring the roles
The roles are created in the credential bundle by the warm-up, one set per group found in the configuration table:
bin/console lle:credential:warmup
Run it again when a new group appears. The warm-up creates nothing while the option is disabled. Then grant the roles to
your groups in the credential screen. ROLE_SUPER_ADMIN gets everything.
The screen itself still needs the usual ROLE_CONFIG_INDEX, ROLE_CONFIG_SHOW and ROLE_CONFIG_EDIT credentials.