By default ArrayNode does not provide this features, but we can extend the feature.
<?php
namespace AndyTruong\Config\Definition;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
class RadioArrayNodeDefinition extends ArrayNodeDefinition
{
private $radioOptions = [];
public function mustFillOnlyOneOfTheseKeys(array $keys)
{
$this->radioOptions[] = $keys;
}
protected function createNode()
{
$node = parent::createNode();
$node->setFinalValidationClosures([
[$this, 'validateRadioOptions']
]);
return $node;
}
public function validateRadioOptions($value)
{
foreach ($this->radioOptions as $radioOptions) {
$count = 0;
foreach ($radioOptions as $radioKey) {
if (!is_null($value[$radioKey])) {
$count++;
}
}
switch ($count) {
case 1:
return $value;
case 0:
throw new InvalidConfigurationException('One of these keys is required but none given: ' . implode(', ', $radioOptions));
default:
throw new InvalidConfigurationException('Only one of these keys is allowed: ' . implode(', ', $radioOptions));
}
}
}
}
Then, we can use new definition as follow:
<?php
use Symfony\Component\Config\Definition\Builder\NodeBuilder;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('routing');
/* @var $route_item NodeBuilder */
$route_item = $rootNode->children()
->setNodeClass('radioArray', 'AndyTruong\Config\Definition\RadioArrayNodeDefinition')
->arrayNode('routes')
->prototype('radioArray');
$route_item->mustFillOnlyOneOfTheseKeys(['content', 'template']);