Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony OptionsResolver multidimensional array of array

Tags:

php

symfony4

i have a rest api request response in this form

{
    "first_field": null,
    "elements": [
        {
            "type": "type_1",
            "quantity": 234
        },
        {
            "type": "type_2",
            "quantity": 432
        },
        {
            "type": "type_3",
            "quantity": 112
        },
        {
            "type": "type_4",
            "quantity": 212
        }
    ],
    "third_field": {
        "option1": value1,
        "option2": "value2",
        "option3": "value3",
        "option4": "value4"
    }
}

I would like to pass it to a constructor to create an object. I thought to use the Symfony4 OptionsResolver to configure it.

Dummy and incomplete example

    class Status{

      public function __construct(array $options){
        $resolver = new OptionsResolver();
        $this->configureOptions($resolver);

        $this->options = $resolver->resolve($options);
        $this->init();
      }

     protected function init(){
       foreach($this->options['elements'] as $element){
         switch($element['type']){
           case 'type_1'
             $this->type1 = $element['quantity'];
             break;
           // And so on
         }
       }
     }

    }

How can i define in OptionsResolver the elements array? For third field the solution is the nested options, but it is an array of options, not an array of array of options...

Thanks in advance

EDIT To instantiate a new object from a Json Object a fine solution can be the karriere/json-decoder

like image 281
Jack Skeletron Avatar asked May 20 '26 10:05

Jack Skeletron


1 Answers

If someone still needs a way to do that, here is a possible implementation

<?php

class Status
{
    public function __construct(array $options)
    {
        $resolver = new OptionsResolver();
        $this->configureOptions($resolver);

        $this->options = $resolver->resolve($options);
        $this->init();
    }

    protected function init()
    {
        foreach($this->options['elements'] as $element) {
            switch($element['type']) {
                case 'type_1':
                    $this->type1 = $element['quantity'];
                    break;
                // And so on
            }
        }
    }

    private function configureOptions(OptionsResolver $resolver)
    {
        $resolver->define('elements')
            ->allowedTypes('array[]')
            ->allowedValues(static function (array &$elements): bool {
                $subResolver = new OptionsResolver();

                $subResolver->define('type')
                    ->required()
                    ->allowedTypes('string');

                $subResolver->define('quantity')
                    ->required()
                    ->allowedTypes('int');

                // Trick is here: use array_map to resolve each elements one by one.
                $elements = array_map([$subResolver, 'resolve'], $elements);
                return true;
            });
    }
}
like image 157
niconoe Avatar answered May 23 '26 02:05

niconoe