Message-ID: <1187710670.2770.1485850748945.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_2769_982210258.1485850748928" ------=_Part_2769_982210258.1485850748928 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
Symfony Config component makes it possible to define semantic c=
onfiguration, exposed to the end developer. This configuration is vali=
dated by rules you define, e.g. validating type (string, array, integer, bo=
olean, etc.). Usually, once validated and processed, this semantic configur=
ation is then mapped to internal key/value parameters st=
ored in the ServiceContainer
.
eZ Platform uses this for its core configuration, but adds another confi=
guration level, the siteaccess. For each defined siteacces=
s, we need to be able to use the same configuration tree in order to define=
siteaccess-specific config. These settings then need to be mapped to sitea=
ccess-aware internal parameters that you can retrieve via the Co=
nfigResolver
. For this, internal keys need to follow the format =
;<namespace>.<scope>.<parameter_name>
, =
namespace
being specific to your app/bundle, s=
cope
being the siteaccess, siteaccess group, default=
or global
, parameter_name
&=
nbsp;being the actual setting identifier.
For more information on ConfigResolve= r, namespaces and scopes, see <= a href=3D"https://doc.ez.no/display/DEVELOPER/SiteAccess#SiteAccess-Configu= ration" rel=3D"nofollow">eZ Platform configuration basics.
The goal of this feature is to make it easy to implement a = siteaccess-aware semantic configuration and its mapping= to internal config for any eZ bundle developer.
An abstract Configuration
&nbs=
p;class has been added, simplifying the way to add a siteaccess settings tr=
ee like the following:
acme_demo: system: my_siteaccess: hello: "world" foo_setting: an_integer: 456 enabled: true my_siteaccess_group: hello: "universe" foo_setting: foo: "bar" some: "thing" an_integer: 123 enabled: false=20
Class FQN is eZ\Bundle\EzPublishCoreBundle\Depen=
dencyInjection\Configuration\SiteAccessAware\Configuration
.
All you have to do is to ex=
tend it and use $this-&=
gt;generateScopeBaseNode()
:<=
/span>
namespace Acme\DemoBundle\DependencyInjection; use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAcc= essAware\Configuration as SiteAccessConfiguration; use Symfony\Component\Config\Definition\Builder\NodeBuilder; use Symfony\Component\Config\Definition\Builder\TreeBuilder; class Configuration extends SiteAccessConfiguration { public function getConfigTreeBuilder() { $treeBuilder =3D new TreeBuilder(); $rootNode =3D $treeBuilder->root( 'acme_demo' ); // $systemNode will then be the root of siteaccess aware settings. $systemNode =3D $this->generateScopeBaseNode( $rootNode ); $systemNode ->scalarNode( 'hello' )->isRequired()->end() ->arrayNode( 'foo_setting' ) ->children() ->scalarNode( "foo" )->end() ->scalarNode( "some" )->end() ->integerNode( "an_integer" )->end() ->booleanNode( "enabled" )->end() ->end() ->end(); return $treeBuilder; } }=20
Default name for the siteaccess r=
oot node is system
, but you can customize it. F=
or this, just pass the name you want to use as a second argument of
Semantic configuration must always be mapped to inter=
nal key/value settings within the ServiceCont=
ainer
. This is usually done in the DIC extension.
For siteaccess-aware settings, new ConfigurationProcessor and
Contextualizer
classes have been introd=
uced to ease the process.
namespace Acme\DemoBundle\DependencyInjection; use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAcc= essAware\ConfigurationProcessor; use eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\SiteAcc= essAware\ContextualizerInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; /** * This is the class that loads and manages your bundle configuration * * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles= /extension.html} */ class AcmeDemoExtension extends Extension { public function load( array $configs, ContainerBuilder $container ) { $configuration =3D $this->getConfiguration( $configs, $container= ); $config =3D $this->processConfiguration( $configuration, $config= s ); $loader =3D new Loader\YamlFileLoader( $container, new FileLocator(= __DIR__.'/../Resources/config' ) ); $loader->load( 'default_settings.yml' ); // "acme_demo" will be the namespace as used in ConfigResolver form= at. $processor =3D new ConfigurationProcessor( $container, 'acme_demo' = ); $processor->mapConfig( $config, // Any kind of callable can be used here. // It will be called for each declared scope/SiteAccess. function ( $scopeSettings, $currentScope, ContextualizerInterfa= ce $contextualizer ) { // Will map "hello" setting to "acme_demo.<$currentScope= >.hello" container parameter // It will then be possible to retrieve this parameter thro= ugh ConfigResolver in the application code: // $helloSetting =3D $configResolver->getParameter( 'hel= lo', 'acme_demo' ); $contextualizer->setContextualParameter( 'hello', $curre= ntScope, $scopeSettings['hello'] ); } ); // Now map "foo_setting" and ensure keys defined for "my_siteaccess= " overrides the one for "my_siteaccess_group" // It is done outside the closure as it is needed only once. $processor->mapConfigArray( 'foo_setting', $config ); } }=20
You can map simple settings by calling $processor->mapSetting()=
, without having to call $processor->mapConfig()
wit=
h a callable.
$processor =3D new ConfigurationProcessor( $container, 'acme_demo' = ); $processor->mapSetting( 'hello', $config );=20
Important
Always ensure you have defined and loaded default settings.
parameters: acme_demo.default.hello: world acme_demo.default.foo_setting: foo: ~ some: ~ planets: [Earth] an_integer: 0 enabled: false j_adore: les_sushis=20
When you define a hash as semantic config, you sometimes don't want the =
siteaccess settings to replace the default or group values, but en=
rich them by appending new entries. This is made possible by usin=
g $processor->mapConfigArray()
, which needs to be call=
ed outside the closure (before or after), in order to be called only once.<=
/p>
Consider the following default config:
parameters: acme_demo.default.foo_setting: foo: ~ some: ~ planets: [Earth] an_integer: 0 enabled: false j_adore: les_sushis=20
And then this semantic config:
acme_demo: system: sa_group: foo_setting: foo: bar some: thing an_integer: 123 # Assuming "sa1" is part of "sa_group" sa1: foo_setting: an_integer: 456 enabled: true j_adore: le_saucisson=20
What we want here is that keys defined for foo_s=
etting
are merged between default/group/siteaccess:
parameters: acme_demo.sa1.foo_setting: foo: bar some: thing planets: [Earth] an_integer: 456 enabled: true j_adore: le_saucisson=20
In the example above, entries were merged in respect to the scope order =
of precedence. However, if we define the planets
key=
forsa1
, it will completely override the default value since t=
he merge process is done at only 1 level.
You can add another level by passing ContextualizerInterface:=
:MERGE_FROM_SECOND_LEVEL
as an option (3rd argument) to$c=
ontextualizer->mapConfigArray()
.
parameters: acme_demo.default.foo_setting: foo: ~ some: ~ planets: [Earth] an_integer: 0 enabled: false j_adore: [les_sushis]=20
acme_demo: system: sa_group: foo_setting: foo: bar some: thing planets: [Mars, Venus] an_integer: 123 # Assuming "sa1" is part of "sa_group" sa1: foo_setting: an_integer: 456 enabled: true j_adore: [le_saucisson, la_truite_a_la_vapeur]=20
Result of using ContextualizerInterface::MERGE_FROM_SECOND_LE=
VEL
option:
parameters: acme_demo.sa1.foo_setting: foo: bar some: thing planets: [Earth, Mars, Venus] an_integer: 456 enabled: true j_adore: [les_suhis, le_saucisson, la_truite_a_la_vapeur]=20
There is also another option, ContextualizerInterface::UNIQUE, to be used when you want to ensure your array setting has unique values=
. It will only work on normal arrays though, not hashes.
A few limitation exist with this scope hash merge:
ContextualizerInterface::MERGE_FROM_SECOND_LEVEL
optio=
n.Instead of passing a callable to $processor->mapConf=
ig()
, an instance of eZ\Bundle\EzPublishCoreBundle\Depend=
encyInjection\Configuration\SiteAccessAware\ConfigurationMapperInterface can be passed.
This can be useful if you have a lot of configuration to map and d= on't want to pollute your DIC extension class (better for maintenance).
As specified above, $contextualizer->ma=
pConfigArray()
is not to be used within the <=
em>scope loop, like for simple values. When using a closure/call=
able, you usually call it before or after $processor->=
mapConfig()
. For mapper objects, a dedicated interface can be =
used: HookableConfigurationMapperInterface
, =
which defines 2 methods: preMap()
and&n=
bsp;postMap()
.