Merge branch '2.7' into 2.8
* 2.7: [Validator] add Indonesian translation fixed CS [config] Fix issue when key removed and left value only [Security] AbstractVoter method supportsAttribute gives false positive if attribute is zero (0)
This commit is contained in:
commit
839c0836ee
@ -29,6 +29,10 @@ class PrototypedArrayNode extends ArrayNode
|
||||
protected $minNumberOfElements = 0;
|
||||
protected $defaultValue = array();
|
||||
protected $defaultChildren;
|
||||
/**
|
||||
* @var NodeInterface[] An array of the prototypes of the simplified value children
|
||||
*/
|
||||
private $valuePrototypes = array();
|
||||
|
||||
/**
|
||||
* Sets the minimum number of elements that a prototype based node must
|
||||
@ -194,9 +198,9 @@ class PrototypedArrayNode extends ArrayNode
|
||||
}
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
$this->prototype->setName($k);
|
||||
$prototype = $this->getPrototypeForChild($k);
|
||||
try {
|
||||
$value[$k] = $this->prototype->finalize($v);
|
||||
$value[$k] = $prototype->finalize($v);
|
||||
} catch (UnsetKeyException $e) {
|
||||
unset($value[$k]);
|
||||
}
|
||||
@ -250,8 +254,18 @@ class PrototypedArrayNode extends ArrayNode
|
||||
}
|
||||
|
||||
// if only "value" is left
|
||||
if (1 == count($v) && isset($v['value'])) {
|
||||
if (array_keys($v) === array('value')) {
|
||||
$v = $v['value'];
|
||||
if ($this->prototype instanceof ArrayNode && ($children = $this->prototype->getChildren()) && array_key_exists('value', $children)) {
|
||||
$valuePrototype = current($this->valuePrototypes) ?: clone $children['value'];
|
||||
$valuePrototype->parent = $this;
|
||||
$originalClosures = $this->prototype->normalizationClosures;
|
||||
if (is_array($originalClosures)) {
|
||||
$valuePrototypeClosures = $valuePrototype->normalizationClosures;
|
||||
$valuePrototype->normalizationClosures = is_array($valuePrototypeClosures) ? array_merge($originalClosures, $valuePrototypeClosures) : $originalClosures;
|
||||
}
|
||||
$this->valuePrototypes[$k] = $valuePrototype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,11 +278,11 @@ class PrototypedArrayNode extends ArrayNode
|
||||
}
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
$prototype = $this->getPrototypeForChild($k);
|
||||
if (null !== $this->keyAttribute || $isAssoc) {
|
||||
$normalized[$k] = $this->prototype->normalize($v);
|
||||
$normalized[$k] = $prototype->normalize($v);
|
||||
} else {
|
||||
$normalized[] = $this->prototype->normalize($v);
|
||||
$normalized[] = $prototype->normalize($v);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,10 +336,54 @@ class PrototypedArrayNode extends ArrayNode
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->prototype->setName($k);
|
||||
$leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
|
||||
$prototype = $this->getPrototypeForChild($k);
|
||||
$leftSide[$k] = $prototype->merge($leftSide[$k], $v);
|
||||
}
|
||||
|
||||
return $leftSide;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a prototype for the child node that is associated to $key in the value array.
|
||||
* For general child nodes, this will be $this->prototype.
|
||||
* But if $this->removeKeyAttribute is true and there are only two keys in the child node:
|
||||
* one is same as this->keyAttribute and the other is 'value', then the prototype will be different.
|
||||
*
|
||||
* For example, assume $this->keyAttribute is 'name' and the value array is as follows:
|
||||
* array(
|
||||
* array(
|
||||
* 'name' => 'name001',
|
||||
* 'value' => 'value001'
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* Now, the key is 0 and the child node is:
|
||||
* array(
|
||||
* 'name' => 'name001',
|
||||
* 'value' => 'value001'
|
||||
* )
|
||||
*
|
||||
* When normalizing the value array, the 'name' element will removed from the child node
|
||||
* and its value becomes the new key of the child node:
|
||||
* array(
|
||||
* 'name001' => array('value' => 'value001')
|
||||
* )
|
||||
*
|
||||
* Now only 'value' element is left in the child node which can be further simplified into a string:
|
||||
* array('name001' => 'value001')
|
||||
*
|
||||
* Now, the key becomes 'name001' and the child node becomes 'value001' and
|
||||
* the prototype of child node 'name001' should be a ScalarNode instead of an ArrayNode instance.
|
||||
*
|
||||
* @param string $key The key of the child node
|
||||
*
|
||||
* @return mixed The prototype instance
|
||||
*/
|
||||
private function getPrototypeForChild($key)
|
||||
{
|
||||
$prototype = isset($this->valuePrototypes[$key]) ? $this->valuePrototypes[$key] : $this->prototype;
|
||||
$prototype->setName($key);
|
||||
|
||||
return $prototype;
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Config\Tests\Definition;
|
||||
use Symfony\Component\Config\Definition\PrototypedArrayNode;
|
||||
use Symfony\Component\Config\Definition\ArrayNode;
|
||||
use Symfony\Component\Config\Definition\ScalarNode;
|
||||
use Symfony\Component\Config\Definition\VariableNode;
|
||||
|
||||
class PrototypedArrayNodeTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -177,4 +178,164 @@ class PrototypedArrayNodeTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that when a key attribute is mapped, that key is removed from the array.
|
||||
* And if only 'value' element is left in the array, it will replace its wrapper array.
|
||||
*
|
||||
* <things>
|
||||
* <option id="option1" value="value1">
|
||||
* </things>
|
||||
*
|
||||
* The above should finally be mapped to an array that looks like this
|
||||
* (because "id" is the key attribute).
|
||||
*
|
||||
* array(
|
||||
* 'things' => array(
|
||||
* 'option1' => 'value1'
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* It's also possible to mix 'value-only' and 'non-value-only' elements in the array.
|
||||
*
|
||||
* <things>
|
||||
* <option id="option1" value="value1">
|
||||
* <option id="option2" value="value2" foo="foo2">
|
||||
* </things>
|
||||
*
|
||||
* The above should finally be mapped to an array as follows
|
||||
*
|
||||
* array(
|
||||
* 'things' => array(
|
||||
* 'option1' => 'value1',
|
||||
* 'option2' => array(
|
||||
* 'value' => 'value2',
|
||||
* 'foo' => 'foo2'
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* The 'value' element can also be ArrayNode:
|
||||
*
|
||||
* <things>
|
||||
* <option id="option1">
|
||||
* <value>
|
||||
* <foo>foo1</foo>
|
||||
* <bar>bar1</bar>
|
||||
* </value>
|
||||
* </option>
|
||||
* </things>
|
||||
*
|
||||
* The above should be finally be mapped to an array as follows
|
||||
*
|
||||
* array(
|
||||
* 'things' => array(
|
||||
* 'option1' => array(
|
||||
* 'foo' => 'foo1',
|
||||
* 'bar' => 'bar1'
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* If using VariableNode for value node, it's also possible to mix different types of value nodes:
|
||||
*
|
||||
* <things>
|
||||
* <option id="option1">
|
||||
* <value>
|
||||
* <foo>foo1</foo>
|
||||
* <bar>bar1</bar>
|
||||
* </value>
|
||||
* </option>
|
||||
* <option id="option2" value="value2">
|
||||
* </things>
|
||||
*
|
||||
* The above should be finally mapped to an array as follows
|
||||
*
|
||||
* array(
|
||||
* 'things' => array(
|
||||
* 'option1' => array(
|
||||
* 'foo' => 'foo1',
|
||||
* 'bar' => 'bar1'
|
||||
* ),
|
||||
* 'option2' => 'value2'
|
||||
* )
|
||||
* )
|
||||
*
|
||||
*
|
||||
* @dataProvider getDataForKeyRemovedLeftValueOnly
|
||||
*/
|
||||
public function testMappedAttributeKeyIsRemovedLeftValueOnly($value, $children, $expected)
|
||||
{
|
||||
$node = new PrototypedArrayNode('root');
|
||||
$node->setKeyAttribute('id', true);
|
||||
|
||||
// each item under the root is an array, with one scalar item
|
||||
$prototype = new ArrayNode(null, $node);
|
||||
$prototype->addChild(new ScalarNode('id'));
|
||||
$prototype->addChild(new ScalarNode('foo'));
|
||||
$prototype->addChild($value);
|
||||
$node->setPrototype($prototype);
|
||||
|
||||
$normalized = $node->normalize($children);
|
||||
$this->assertEquals($expected, $normalized);
|
||||
}
|
||||
|
||||
public function getDataForKeyRemovedLeftValueOnly()
|
||||
{
|
||||
$scalarValue = new ScalarNode('value');
|
||||
|
||||
$arrayValue = new ArrayNode('value');
|
||||
$arrayValue->addChild(new ScalarNode('foo'));
|
||||
$arrayValue->addChild(new ScalarNode('bar'));
|
||||
|
||||
$variableValue = new VariableNode('value');
|
||||
|
||||
return array(
|
||||
array(
|
||||
$scalarValue,
|
||||
array(
|
||||
array('id' => 'option1', 'value' => 'value1'),
|
||||
),
|
||||
array('option1' => 'value1'),
|
||||
),
|
||||
|
||||
array(
|
||||
$scalarValue,
|
||||
array(
|
||||
array('id' => 'option1', 'value' => 'value1'),
|
||||
array('id' => 'option2', 'value' => 'value2', 'foo' => 'foo2'),
|
||||
),
|
||||
array(
|
||||
'option1' => 'value1',
|
||||
'option2' => array('value' => 'value2', 'foo' => 'foo2'),
|
||||
),
|
||||
),
|
||||
|
||||
array(
|
||||
$arrayValue,
|
||||
array(
|
||||
array(
|
||||
'id' => 'option1',
|
||||
'value' => array('foo' => 'foo1', 'bar' => 'bar1'),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'option1' => array('foo' => 'foo1', 'bar' => 'bar1'),
|
||||
),
|
||||
),
|
||||
|
||||
array($variableValue,
|
||||
array(
|
||||
array(
|
||||
'id' => 'option1', 'value' => array('foo' => 'foo1', 'bar' => 'bar1'),
|
||||
),
|
||||
array('id' => 'option2', 'value' => 'value2'),
|
||||
),
|
||||
array(
|
||||
'option1' => array('foo' => 'foo1', 'bar' => 'bar1'),
|
||||
'option2' => 'value2',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ abstract class AbstractVoter implements VoterInterface
|
||||
*/
|
||||
public function supportsAttribute($attribute)
|
||||
{
|
||||
return in_array($attribute, $this->getSupportedAttributes());
|
||||
return in_array($attribute, $this->getSupportedAttributes(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,9 @@ use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
*/
|
||||
class AbstractVoterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var TokenInterface
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
protected function setUp()
|
||||
@ -25,6 +28,9 @@ class AbstractVoterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTests()
|
||||
{
|
||||
return array(
|
||||
@ -55,4 +61,69 @@ class AbstractVoterTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getSupportsAttributeData()
|
||||
{
|
||||
return array(
|
||||
'positive_string_edit' => array(
|
||||
'expected' => true,
|
||||
'attribute' => 'EDIT',
|
||||
'message' => 'expected TRUE given as attribute EDIT is supported',
|
||||
),
|
||||
'positive_string_create' => array(
|
||||
'expected' => true,
|
||||
'attribute' => 'CREATE',
|
||||
'message' => 'expected TRUE as given attribute CREATE is supported',
|
||||
),
|
||||
|
||||
'negative_string_read' => array(
|
||||
'expected' => false,
|
||||
'attribute' => 'READ',
|
||||
'message' => 'expected FALSE as given attribute READ is not supported',
|
||||
),
|
||||
'negative_string_random' => array(
|
||||
'expected' => false,
|
||||
'attribute' => 'random',
|
||||
'message' => 'expected FALSE as given attribute "random" is not supported',
|
||||
),
|
||||
'negative_string_0' => array(
|
||||
'expected' => false,
|
||||
'attribute' => '0',
|
||||
'message' => 'expected FALSE as given attribute "0" is not supported',
|
||||
),
|
||||
// this set of data gives false positive if in_array is not used with strict flag set to 'true'
|
||||
'negative_int_0' => array(
|
||||
'expected' => false,
|
||||
'attribute' => 0,
|
||||
'message' => 'expected FALSE as given attribute 0 is not string',
|
||||
),
|
||||
'negative_int_1' => array(
|
||||
'expected' => false,
|
||||
'attribute' => 1,
|
||||
'message' => 'expected FALSE as given attribute 1 is not string',
|
||||
),
|
||||
'negative_int_7' => array(
|
||||
'expected' => false,
|
||||
'attribute' => 7,
|
||||
'message' => 'expected FALSE as attribute 7 is not string',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getSupportsAttributeData
|
||||
*
|
||||
* @param bool $expected
|
||||
* @param string $attribute
|
||||
* @param string $message
|
||||
*/
|
||||
public function testSupportsAttribute($expected, $attribute, $message)
|
||||
{
|
||||
$voter = new AbstractVoterTest_Voter();
|
||||
|
||||
$this->assertEquals($expected, $voter->supportsAttribute($attribute), $message);
|
||||
}
|
||||
}
|
||||
|
@ -310,6 +310,10 @@
|
||||
<source>This value does not match the expected {{ charset }} charset.</source>
|
||||
<target>Nilai ini tidak memenuhi set karakter {{ charset }} yang diharapkan.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="81">
|
||||
<source>This is not a valid Business Identifier Code (BIC).</source>
|
||||
<target>Ini bukan Business Identifier Code (BIC) yang sah.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
||||
|
Reference in New Issue
Block a user