0

I'm looking for a clean solution to transform a nested array.

Here is what I'm trying to achieve...

Original array:

  $map = array(
    'name' => 'super test',
    'machine_name' => 'super_test',
    'class' => 'openlayers_map_map',
    'options' => array(
      'width' => 'auto',
      'height' => '300px',
      'contextualLinks' => 1,
      'provideBlock' => 1,
      'view' => array(
        'center' => array(
          'lat' => '0',
          'lon' => '0',
        ),
        'rotation' => '0',
        'zoom' => '2',
      ),
      'layers' => array(
        '0' => array(
          'name' => 'Ma super layer',
          'machine_name' => 'plouf',
          'class' => 'openlayers_layer_tile',
          'options' => array(
            'source' => array(
              'name' => 'Ma super layer',
              'machine_name' => 'plouf',
              'class' => 'openlayers_source_osm'
            ),
            'param1' => 'ca roule'
          )
        ),
      ),
      'controls' => array(
        'control_mouseposition',
        '0' => array(
          'name' => 'Control attribution',
          'machine_name' => 'openlayers_control_attribution',
          'class' => 'openlayers_control_attribution',
          'options' => array(
            'collapsible' => 1
          )
        ),
        'control_rotate',
        'control_zoom',
      ),
      'interactions' => array(
        'interaction_doubleclickzoom',
        'interaction_dragpan',
        'interaction_dragrotateandzoom',
        'interaction_mousewheelzoom',
      ),
    )
  );

Final array:

  $map = array(
    'name' => 'super test',
    'machine_name' => 'super_test',
    'class' => 'openlayers_map_map',
    'options' => array(
      'width' => 'auto',
      'height' => '300px',
      'contextualLinks' => 1,
      'provideBlock' => 1,
      'view' => array(
        'center' => array(
          'lat' => '0',
          'lon' => '0',
        ),
        'rotation' => '0',
        'zoom' => '2',
      ),
      'layers' => array(
        '0' => (object) openlayers_layer_tile
          'name' => 'Ma super layer',
          'machine_name' => 'plouf',
          'class' => 'openlayers_layer_tile',
          'options' => array(
            'source' => (object) openlayers_source_osm
              'name' => 'Ma super layer',
              'machine_name' => 'plouf',
              'class' => 'openlayers_source_osm'
            ),
            'param1' => 'ca roule'
          )
        ),
      ),
      'controls' => array(
        'control_mouseposition',
        '0' => (object) openlayers_control_attribution
          'name' => 'Control attribution',
          'machine_name' => 'openlayers_control_attribution',
          'class' => 'openlayers_control_attribution',
          'options' => array(
            'collapsible' => 1
          )
        ),
        'control_rotate',
        'control_zoom',
      ),
      'interactions' => array(
        'interaction_doubleclickzoom',
        'interaction_dragpan',
        'interaction_dragrotateandzoom',
        'interaction_mousewheelzoom',
      ),
    )
  );

Basically, I need to traverse the array, find all children with the 'class' key and transform them into objects of the same name.

2 Answers 2

1

If you don't have the classes ready to be instantiated, this code will create anonymous objects instead. (The class name still being present as a property.)

function class_to_object (&$arr) {

  if (is_array($arr)) {
    foreach ($arr as $key => &$val) {
      class_to_object($val);
    }

    if (isset($arr['class'])) {
      $arr = (object) $arr;
    }
  }

}

class_to_object($map);

Result :

(Notice that the first array is turned into an object, since it contains the field "class" too. I guess you can tweak the function easily enough if you don't want that behavior)

stdClass Object
(
    [name] => super test
    [machine_name] => super_test
    [class] => openlayers_map_map
    [options] => Array
        (
            [width] => auto
            [height] => 300px
            [contextualLinks] => 1
            [provideBlock] => 1
            [view] => Array
                (
                    [center] => Array
                        (
                            [lat] => 0
                            [lon] => 0
                        )

                    [rotation] => 0
                    [zoom] => 2
                )

            [layers] => Array
                (
                    [0] => stdClass Object
                        (
                            [name] => Ma super layer
                            [machine_name] => plouf
                            [class] => openlayers_layer_tile
                            [options] => Array
                                (
                                    [source] => stdClass Object
                                        (
                                            [name] => Ma super layer
                                            [machine_name] => plouf
                                            [class] => openlayers_source_osm
                                        )

                                    [param1] => ca roule
                                )

                        )

                )

            [controls] => Array
                (
                    [0] => stdClass Object
                        (
                            [name] => Control attribution
                            [machine_name] => openlayers_control_attribution
                            [class] => openlayers_control_attribution
                            [options] => Array
                                (
                                    [collapsible] => 1
                                )

                        )

                    [1] => control_rotate
                    [2] => control_zoom
                )

            [interactions] => Array
                (
                    [0] => interaction_doubleclickzoom
                    [1] => interaction_dragpan
                    [2] => interaction_dragrotateandzoom
                    [3] => interaction_mousewheelzoom
                )

        )

)
Sign up to request clarification or add additional context in comments.

Comments

0

This totally untested recursive function may get you on the right track:

function recursive_hydrate_array($arr)
{
  if(!is_array($arr) || !isset($arr["class"]))
  {
    throw new Exception("Argument is not an array or does not have a 'class' key.");
  }

  $klass = $arr["class"];
  unset($arr["class"]);

  $obj = new $klass();

  foreach($arr as $k => $v)
  {
    if(is_array($arr[$k]) && isset($arr[$k]["class"]))
    {
      $obj->{$k} = recursive_hydrate_array($arr[$k]);
    }
    else
    {
      $obj->{$k} = $arr[$k];
    }
  }

  return $obj;
}

Note that I am making three assumptions here:

  1. The classes in question already exist.
  2. Each class can be instantiated without passing any parameters to its constructor.
  3. All relevant properties of each class are public and can be set from outside of the class.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.