Skip to content

[Config][RFC] EnumNode removes values based on loose comparison #48913

Closed
@kiler129

Description

@kiler129

Symfony version(s) affected

v2.1.0+

Description

In my use-case I have a node with enabled field, which can have 3 values:

  • true: always enable component
  • false: do not enable the component
  • null: enable if it's needed (dependent on rather complex logic, outside of the scope of config schema)

The issue is I cannot use booleanNode() as it is well... boolean.

How to reproduce

    ->children()
        ->enumNode('enabled')
            ->values([true, false, null])
            ->defaultNull()
    ->end()

While the code above "works", using bin/console config:dump-reference reveals that in fact the null is not an expected values:

 doctrine_changeset_marshaller:
     enabled:              null # One of true; false

Possible Solution

The issue stems from usage of array_unique() in two places:

class EnumNodeDefinition extends ScalarNodeDefinition
{
private $values;
public function values(array $values)
{
$values = array_unique($values);

class EnumNode extends ScalarNode
{
private $values;
public function __construct($name, NodeInterface $parent = null, array $values = array())
{
$values = array_unique($values);

The issue is, \array_unique() compares values according to their string representation. I believe this is less than idea in the case of EnumNode. The \array_unique(), unlike functions like \in_array() does not support $strict parameter (and the discussion on that died in 2013). Thus, to really solve this issue a custom strict function would need to be used:

However, this does not cover empty string case. Given the EnumNode usage of the array where keys in the array aren't important, I think the solution would be to replace \array_unique() call with a function like:

function arrayUniqueStrict(array $values): array
{
    $unique = [];
    foreach($values as $k => $v) {
        if (!\in_array($v, $unique, true)) {
            $unique[$k] = $v;
        }
    }

    return $unique;
}

Additional Context

If the intention of EnumNode to be type-loose, then my suggested fix is obviously a no-go. In such a case I think it should be noted in the docs.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions