0

I've following data in my Database :

| meta_key                          | meta_value |
|-----------------------------------|------------|
| foo                               | bar        |
| hello                             | world      |
| testimonials_0_category           | category0  |
| testimonials_0_comments_0_message | message0   |
| testimonials_0_comments_1_message | message1   |

Some of the meta_key will be string and some of the meta_key will be nested array base on the _{N}_ pattern.

I've successfully extract & render the data as I wanted with eval(); method, but i don't think eval is a good solution for this.

I'm just wondering do we have alternative solution on this (eg : using recursive or other kind of array loop method?)

You may refer below for my sample codes:

<?php
$database = array();
$database[] = array('meta_key' => 'foo','meta_value'=>'bar');
$database[] = array('meta_key' => 'hello','meta_value'=>'world');
$database[] = array('meta_key' => 'testimonials_0_category','meta_value'=>'category0');
$database[] = array('meta_key' => 'testimonials_0_comments_0_message','meta_value'=>'message0');
$database[] = array('meta_key' => 'testimonials_0_comments_1_message','meta_value'=>'message1');

$output = array();
// echo'<pre>';print_r($database);die;

foreach($database as $d)
{
    if (preg_match('(_\d+_)',$d['meta_key']))
    {
        //nested array
        preg_match_all('(_\d+_)',$d['meta_key']."_9999_x",$matches);
        $splits = preg_split('(_[0-9]_)', $d['meta_key']);
        $str    = '';

        foreach($matches[0] as $j => $match)
        {
            $i = filter_var($match,FILTER_SANITIZE_NUMBER_INT);
            $str.= "['{$splits[$j]}'][{$i}]";
        }
        $str = Str_replaceLast('[9999]','',$str);
        eval('$output'.$str." = '{$d['meta_value']}';");
    }else{
        //string
        $output[$d['meta_key']] = $d['meta_value'];
    }
}

echo'<pre>';print_r($output);

//Helper
function Str_replaceLast($search, $replace, $subject)
{
    $position = strrpos($subject, $search);

    if ($position !== false) {
        return substr_replace($subject, $replace, $position, strlen($search));
    }

    return $subject;
}
?>

The result/output I want would be like below format:

Array
(
    [foo] => bar
    [hello] => world
    [testimonials] => Array
        (
            [0] => Array
                (
                    [category] => category0
                    [comments] => Array
                        (
                            [0] => Array
                                (
                                    [message] => message0
                                )

                            [1] => Array
                                (
                                    [message] => message1
                                )

                        )

                )

        )

)
3
  • 1
    What's your expected output? Commented Aug 9, 2019 at 12:19
  • Is that data format your own creation? Because that looks a lot like what WordPress / the ACF plugin uses to store meta data, so perhaps you can get some inspiration from there … Commented Aug 9, 2019 at 12:22
  • 1
    Or, if you simply split this at the _, you could probably implement a solution similar to this, stackoverflow.com/questions/28926424/… Commented Aug 9, 2019 at 12:23

1 Answer 1

1

This recursive function will give you the results you want. It splits the meta_key value into three parts around and including the number and uses that to create a new entry in the output array. If there is more than 1 part of the key remaining, the function recurses to the next level on the part of the key after the digit, otherwise it assigns the meta_value to that part of the key:

function split_word($word, $value, $output) {
    $parts = preg_split('/_(\d)+_/', $word, 2, PREG_SPLIT_DELIM_CAPTURE);
    if (count($parts) > 1) {
        if (isset($output[$parts[0]][$parts[1]])) {
            $output[$parts[0]][$parts[1]] = array_merge($output[$parts[0]][$parts[1]], split_word($parts[2], $value, $output[$parts[0]][$parts[1]]));
        }
        else {
            $output[$parts[0]][$parts[1]] = split_word($parts[2], $value, array());
        }
    }
    else {
        $output = array_merge($output, array($word => $value));
    }
    return $output;
}

$output = array();
foreach ($database as $d) {
    $output = array_merge($output, split_word($d['meta_key'], $d['meta_value'], $output));
}
print_r($output);

Output:

Array
(
    [foo] => bar
    [hello] => world
    [testimonials] => Array
        (
            [0] => Array
                (
                    [category] => category0
                    [comments] => Array
                        (
                            [0] => Array
                                (
                                    [message] => message0
                                )
                            [1] => Array
                                (
                                    [message] => message1
                                )
                        )
                )
        )
)

Demo on 3v4l.org

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

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.