Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the Class with a single value behavior an explicit option #546

Open
treuliaux opened this issue Jul 15, 2024 · 1 comment
Open

Make the Class with a single value behavior an explicit option #546

treuliaux opened this issue Jul 15, 2024 · 1 comment

Comments

@treuliaux
Copy link

treuliaux commented Jul 15, 2024

First things first: thank you for this amazing tool!

I'm using it extensively for a few months now, and I've encountered a usecase/behavior that I think could be slightly enhanced

To my understanding, the following snippet:

Note: this is a "mock" of an actual personal usecase, where I'm not in control of the source, and the only case (and data) that is useful for me to keep (and map), is when elementsOfTypeB is present - which is not the case everytime, and other unwanted fields may be present too.

$class = new class () {
    /** @var array<array{start: int, end: int}> */
    public array $elementsOfTypeB;
};

$source = json_decode(
    <<<JSON
        {
           "elementsOfTypeA":[
              {
                 "probability":0.9583,
                 "text":"Lorem ipsum"
              }
           ]
        }
    JSON,
    true,
);

try {
    $result = (new MapperBuilder())
        ->allowSuperfluousKeys()
        ->enableFlexibleCasting()
        ->mapper()
        ->map($class::class, $source)
    ;
} catch (MappingError $error) {
    $this->mappingFail($error);
}

var_dump($result);

... Should work perfectly fine, and dump:

object(class@anonymous)#1 (1) {
  ["elementsOfTypeB"]=>
  array(0) {
  }
}

The rationale of this expectation is that I've enabled:

  • allowSuperfluousKeys option, which allows the unexpected key elementsOfTypeA to be present in the source, and simply be ignored
  • enableFlexibleCasting option, which should simply convert the absence of an array under the name elementsOfTypeB into an empty array (or null, iirc)

However

Due to the "flattening" default behavior induced by Class with a single value, source value is converted to

{
    "elementsOfTypeB": {
        "elementsOfTypeA": [
            {
                "probability": 0.9583,
                "text": "Lorem ipsum"
            }
        ]
    }
}

... which obvisouly make the whole mapping process to fail

I fully understand the pros of having such a behavior (as explained in the docs), but it really feels like it could be explicitely enabled (or at least disabled), just like allowSuperfluousKeys or enableFlexibleCasting (or maybe some other more clever "magic" way?)

I have a few workarounds to solve this atm:

  • Add a prop elementsOfTypeA to my mapped class (or basically any non-existing nullable prop, with enableFlexibleCasting enabled - so that ArgumentsValues::transformValueForSingleArgument() first condition is triggered)
  • Create a Modifier that checks and forces the presence of my only wanted field in the source
  • ...

All those workarounds just do not feel like they're "the right" solution to this situation.

WDYT? Am I missing an important "way of working w/ Valinor" here? If not, is there a better solution that comes to your mind than the one I suggested here above?
I could probably make a PR suggestion if necessary.

Thanks for your time and for your work!

@KmeCnin
Copy link

KmeCnin commented Jul 15, 2024

Good idea! It would be a very useful addition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants