2016-08-19 5 views
0

Я извлекаю многомерный массив из внешнего API, и мне нужно сохранить результаты в моей таблице mysql, но я не могу понять, как это сделать. Я попробовал несколько вариантов, но не могу добиться успеха.Подготовить многомерный массив для mysql

Вот массив, который приходит из API:

Array 
(
    [per_page] => 100 
    [total] => 69 
    [data] => Array 
     (
      [0] => Array 
       (
        [total_time] => 374 
        [href] => https://api.surveymonkey.net/v3/surveys/###### 
        [custom_variables] => Array 
         (
          [ref] => 38i7zw 
         ) 

        [ip_address] => 198.x.x.x 
        [id] => 4917 
        [logic_path] => Array 
         (
         ) 

        [date_modified] => 2016-08-18T10:04:26+00:00 
        [response_status] => completed 
        [custom_value] => 
        [pages] => Array 
         (
          [0] => Array 
           (
            [id] => 249 
            [questions] => Array 
             (
             ) 

           ) 

          [1] => Array 
           (
            [id] => 247 
            [questions] => Array 
             (
              [0] => Array 
               (
                [id] => 985 
                [answers] => Array 
                 (
                  [0] => Array 
                   (
                    [choice_id] => 103 
                   ) 

                  [1] => Array 
                   (
                    [choice_id] => 107 
                   ) 

                 ) 

               ) 

              [1] => Array 
               (
                [id] => 985 
                [answers] => Array 
                 (
                  [0] => Array 
                   (
                    [choice_id] => 1037 
                   ) 

                 ) 

               ) 

             ) 

           ) 

          [2] => Array 
           (
            [id] => 249 
            [questions] => Array 
             (
             ) 

           ) 

То, что я хотел бы сделать, это вставить некоторые из элементов массива в таблицу следующим образом:

ref  | survey_id | question_id | answer_id 
38i7zw | 4917  | 985   | 103 

Это означает, что Мне необходимо отобразить несколько элементов следующим образом:

  • "survey_id": "id", расположенный после "данных"
  • «question_id»: «идентификатор» находится после «вопросов»
  • «answer_id» является «choice_id»

Мое предположение, что мне нужно, чтобы преобразовать массив в указанном ниже формате, после чего я могу вставьте данные в мой стол - но я не могу понять, как это сделать:

array (
    [0] => [ 
     'ref' => 'abc', 
     'survey_id' = '123', 
     'question_id' => '234', 
     'answer_id' => '345' 
    ], 
    [1] => [ 
     ... 

Любая помощь наиболее ценится. Спасибо

+0

Попробуйте что-то вроде этого Еогеасп ($ массив как $ ключ => $ значение) {если ( is_array ($ value)) { foreach ($ value as $ key => $ value) { echo $ key. "". $ value. "
"; } } echo "
"; } и добавьте вставку sql внутри – Oncodeeater

+0

Я хочу, чтобы решение было настолько простым. См. Ниже класс, который я должен был создать. – DrBorrow

ответ

0

После большого тестирования, вот мой ответ - я надеюсь, что кто-то еще найдет это полезным (я использую структуру Yii2).

Класс преобразует массив так:

Array 
(
    [per_page] => 100 
    [total] => 69 
    [data] => Array 
     (
      [0] => Array 
       (
        [total_time] => 374 
        [href] => https://api.surveymonkey.net/v3/surveys/###### 
        [custom_variables] => Array 
         (
          [ref] => 38i7zw 
         ) 

        [ip_address] => 198.x.x.x 
        [id] => 4917 
        [logic_path] => Array 
         (
         ) 

        [date_modified] => 2016-08-18T10:04:26+00:00 
        [response_status] => completed 
        [custom_value] => 
        [pages] => Array 
         (
          [0] => Array 
           (
            [id] => 249 
            [questions] => Array 
             (
             ) 

В то вроде этого:

Array 
(
    [0] => Array 
     (
      [answer_id] => 10375872133 
      [question_id] => 985997023 
      [question_text] => Who was the contact? 
     ) 

    [1] => Array 
     (
      [answer_id] => 10375872147 
      [question_id] => 985997023 
      [question_text] => Which group did you use? 
     ) 

Красота этого решения заключается в том, что это не имеет значения, насколько глубоко массив или если столбцы не существуют во всех вложенных массивах - класс будет последовательно возвращать данные в том же формате.

Вот как его использовать:

1) экземпляр класса и передать массив к нему:

$obj = new ArrayToolkit($array) 

2) Вывести список элементов, которые существуют в массиве. Элементы возвращаются в формате «разделенные точкой» и действуют как система индексирования.

$list = $obj->getListOfKeys(); 
echo "<pre>" . print_r($list, 1) . "</pre>"; 

список будет выглядеть примерно так (номер по праву является число появлений этого элемента в массиве вы прошли к классу):

Array 
(
    [data.total_time] => 69 
    [data.href] => 69 
    [data.custom_variables.ref] => 69 
    [data.ip_address] => 69 
    [data.id] => 69 
    [data.date_modified] => 69 
    [data.response_status] => 69 
    [data.custom_value] => 69 
    [data.analyze_url] => 69 
    [data.pages.id] => 1311 

2) определить и переименовать элементы, которые вы хотите вернулись:

$obj->keysToFind([ 
      'answer_id'=>'data.pages.questions.answers.choice_id', 
      'question_id'=>'data.pages.questions.id', 
      'question_text' => 'placeholder' 
     ]); 

В приведенном выше примере, класс будет возвращать три элемента: answer_id, question_id, question_text

пара интересных моментов об этой функции:

  • Это будет переименовывать элемент в нечто более подходящее для вас
  • Вы можете вставить заполнители, даже если вы знаете, что данные не существуют в массиве
  • Вы можете выбрать, какие элементы вы хотите вернуть, он будет не возвращать все элементы, если они вам не нужны.
  • Выход соответствует, даже если один суб-массив не все элементы

4) Получить данные обратно:

$arr = $obj->target([ 
    'answer_id'=>'data.pages.questions.answers.choice_id', 
]); 

«целевой» Важно: Это ключ/ценность пара вы больше всего заботитесь. Функция ищет массив, чтобы найти этот ключ. Как только он найдет ключ, он возвращает значение, а затем все остальные запрошенные вами данные (т. Е. Нужные вам родительские элементы).

Примечание. Он не возвращает дочерние элементы, только родительские элементы, но если у вас есть дочерний элемент в «ключах для поиска», он будет равен нулю. По этой причине цель должна быть самым глубоким дочерним элементом, но не обязательно. Вы можете задаться вопросом, почему я бы его проектировал так, но я сделал это, потому что функция позволяет вам добавить другую цель.

Например, если вы сейчас гласил:

$arr = $obj->target([ 
    'question_id'=>'data.pages.questions.id', 
]); 

Результаты будут добавлены к существующей продукции. Это очень важно для плохо сконструированных массивов (как в случае с массивом, с которым я работаю).

В конце концов, вы получаете хороший чистый массив для пакетных вставок!

Надеюсь, это поможет. Вот код

PS: ссылка на Toolkit :: PrintObj() эквивалентно

echo "<pre>" . print_r($var, 1) . "</pre>"; 



<?php 

namespace app\models; 

use Yii; 
use yii\helpers\ArrayHelper; 

/** 
* Class ArrayToolkit 
* @package app\models 
*/ 
class ArrayToolkit extends \yii 
{ 

    // This holds the data for this class 
    public $model = array(); 

    /** 
    * model constructor. 
    * @param $array 
    */ 
    function __construct($array) 
    { 
     $this->getArrayIndex($array); 
    } 

    /** 
    * @return array 
    */ 
    public function getListOfKeys() 
    { 
     //Toolkit::printObject($this->model['list_of_keys']); 
     return $this->model['list_of_keys']; 
    } 

    /** 
    * @return mixed 
    */ 
    public function getIndex() 
    { 
     return $this->model['index']; 
    } 


    // This is the heart of the function. "KeysToFind" is the list of keys it will search for 
    // These keys will allways be in the same order and will exist even if a particular key is empty 
    // This is needed for batch inserts into mysql 
    public function keysToFind($arr) 
    { 
     $this->model['keys_to_find']['all'] = $arr; 
     foreach ($arr as $key => $value) { 
      $this->model['keys_to_find']['temp'][$key] = null; 
     } 
    } 

    // this function is the function which kicks off the search to populate the data 
    // this function is additive! ie new results are added to old results. To clear the cache, 
    // you need to clear $this->model['mysql_array'] 
    public function target($target) 
    { 
     $this->model['keys_to_find']['target']['name'] = key($target); 
     $this->model['keys_to_find']['target']['key'] = array_values($target)[0]; 
     $this->buildMysqlArray(); 
     return $this->model['mysql_array']; 
    } 


    /** 
    * This function will create an array of elements suitable for mysql insert 
    * User simply loops over the array and inserts into table 
    */ 
    private function buildMysqlArray() 
    { 
     // name = the new name assigned by user 
     // key = string eg pages.questions.answers.id 
     // index is the indexing id eg [0.12] or [0.1.2.3] 
     // levelCount is the number of levels within the index 
     // For example [0] = 1 level, [0.0] = 2 levels, [0.0.0] = 3 levels 

     // Target is the value the user is looking for 
     // For example: The answer ID 
     $target_key = $this->model['keys_to_find']['target']['key']; 
     $target_name = $this->model['keys_to_find']['target']['name']; 
     $target_levelCount = $this->model['index'][$target_key]['index_levelCount']; 
     $target_array = $this->model['index'][$target_key]['members']; 

     // Other is all the other supporting values (typically foreign keys) 
     // For example: Survey ID, Question ID etc 

     $other = $this->model['keys_to_find']['all']; 

     // Toolkit::printObject($this->model); 
     // loop through the target array eg pages.questions.answers.id 
     foreach ($target_array as $target_index => $target_value) { 
      $temp = $this->model['keys_to_find']['temp']; // this ensures that all keys are present in the output 
      // for each answer, assign the value 
      $temp[$target_name] = $target_value; 

      // now loop through all the other keys the users wants 
      if ($other !== null) { 
       foreach ($other as $other_name => $other_key) { 
        if (isset($this->model['index'][$other_key]['members']) && $other_key != $target_key) { 
         // "members" is the array of answers or pages etc 
         $other_array = $this->model['index'][$other_key]['members']; 
         $other_levelCount = $this->model['index'][$other_key]['index_levelCount']; 
         // if the question_id is 1.2.3.4 then it has 4 levels. 
         // however a page might be on 1.2.3 (ie 3 levels) 
         // To find the page for our question, we simply shorten the question index to the same number of levels 
         // ie 1.2.3.4 becomes 1.2.3 
         // and now we can easily find the page by using the key: page['1.2.3'] 
         if ($other_levelCount < $target_levelCount) { 
          $indexToFind = substr($target_index, 0, $this->strposX($target_index, ".", $other_levelCount)); 
         } else { 
          $indexToFind = $target_index; 
         } 
         if (isset($other_array[$indexToFind])) { 
          $temp[$other_name] = $other_array[$indexToFind]; 
         } 
        } 
       } 
      } 
      $this->model['mysql_array'][] = $temp; 
      $temp = null; 
     } 
    } 

    /** 
    * @param $array 
    * @param string $prefix 
    * @param bool $recursive 
    * @return array 
    */ 
    private function getArrayIndex($array, $prefix = '', $recursive = false) 
    { 
     $result = array(); 
     foreach ($array as $key => $value) { 
      if (is_array($value)) { // $value is another array - we will need to do a recursive loop 
       if (is_int($key)) { // incremental key eg [0] or [1] etc 
        // The format is as follows: 
        // pages[0]['questions'][1]['id'][2] becomes... 
        // 0.1.2-pages.questions.id 
        // With each loop of this function, I explode the string on "-" and then add the new index 
        // 0.1.2- becomes 0.1.2.3- 
        if (strpos($prefix, "-")) { 
         $arr = explode("-", $prefix); 
         $result = $result + $this->getArrayIndex($value, $arr[0] . "." . $key . '-' . $arr[1], true); 
        } else { 
         $result = $result + $this->getArrayIndex($value, $key . '-' . $prefix, true); 
        } 
       } else {// key is not an integer. It is a string eg "questions". Append it to the $prefix 
        $result = $result + $this->getArrayIndex($value, $prefix . $key . '.', true); 
       } 
      } else { // $value is not an array, it is the actual value 
       if (strpos($prefix, "-")) { 
        $temp = explode("-", $prefix); 
        $this->model['index'][$temp[1] . $key]['index_levelCount'] = substr_count($temp[0], ".") + 1; 
        $this->model['index'][$temp[1] . $key]['members'][$temp[0]] = $value; 
       } 
       $result[$prefix . $key] = $value; 
      } 
     } 
     // CLEANUP: 
     // We don't want to process every recursive loop, only the final array being returned. 
     if ($recursive === false) { // This is the final return 
      $list_of_keys = array(); 
      foreach ($result as $str => $val) { 
       if (strpos($str, "-")) { 
        $temp = explode("-", $str); 
        if (isset($list_of_keys[$temp[1]])) { 
         $list_of_keys[$temp[1]] = $list_of_keys[$temp[1]] + 1; 
        } else { 
         $list_of_keys[$temp[1]] = 1; 
        } 
       } 
      } 
      $this->model['list_of_keys'] = $list_of_keys; 
     } 

     return $result; 
    } 


    /** 
    * @param $haystack 
    * @param $needle 
    * @param $number 
    * @return bool|int 
    * This function will get the n'th occurrence of the needle 
    */ 
    private function strposX($haystack, $needle, $number) 
    { 
     if ($number == '1') { 
      return strpos($haystack, $needle); 
     } elseif ($number > '1') { 
      return strpos($haystack, $needle, $this->strposX($haystack, $needle, $number - 1) + strlen($needle)); 
     } else { 
      $this->model['ERR'][] = ['strposX' => 'Value for parameter $number is out of range']; 
      return false; 
     } 
    } 


} 
Смежные вопросы