Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / migrate_plus / src / Plugin / migrate_plus / data_parser / Json.php
1 <?php
2
3 namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser;
4
5 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
6 use Drupal\migrate_plus\DataParserPluginBase;
7
8 /**
9  * Obtain JSON data for migration.
10  *
11  * @DataParser(
12  *   id = "json",
13  *   title = @Translation("JSON")
14  * )
15  */
16 class Json extends DataParserPluginBase implements ContainerFactoryPluginInterface {
17
18   /**
19    * Iterator over the JSON data.
20    *
21    * @var \Iterator
22    */
23   protected $iterator;
24
25   /**
26    * Retrieves the JSON data and returns it as an array.
27    *
28    * @param string $url
29    *   URL of a JSON feed.
30    *
31    * @return array
32    *   The selected data to be iterated.
33    *
34    * @throws \GuzzleHttp\Exception\RequestException
35    */
36   protected function getSourceData($url) {
37     $response = $this->getDataFetcherPlugin()->getResponseContent($url);
38
39     // Convert objects to associative arrays.
40     $source_data = json_decode($response, TRUE);
41
42     // If json_decode() has returned NULL, it might be that the data isn't
43     // valid utf8 - see http://php.net/manual/en/function.json-decode.php#86997.
44     if (is_null($source_data)) {
45       $utf8response = utf8_encode($response);
46       $source_data = json_decode($utf8response, TRUE);
47     }
48
49     // Backwards-compatibility for depth selection.
50     if (is_int($this->itemSelector)) {
51       return $this->selectByDepth($source_data);
52     }
53
54     // Otherwise, we're using xpath-like selectors.
55     $selectors = explode('/', trim($this->itemSelector, '/'));
56     foreach ($selectors as $selector) {
57       if (!empty($selector)) {
58         $source_data = $source_data[$selector];
59       }
60     }
61     return $source_data;
62   }
63
64   /**
65    * Get the source data for reading.
66    *
67    * @param array $raw_data
68    *   Raw data from the JSON feed.
69    *
70    * @return array
71    *   Selected items at the requested depth of the JSON feed.
72    */
73   protected function selectByDepth(array $raw_data) {
74     // Return the results in a recursive iterator that can traverse
75     // multidimensional arrays.
76     $iterator = new \RecursiveIteratorIterator(
77       new \RecursiveArrayIterator($raw_data),
78       \RecursiveIteratorIterator::SELF_FIRST);
79     $items = [];
80     // Backwards-compatibility - an integer item_selector is interpreted as a
81     // depth. When there is an array of items at the expected depth, pull that
82     // array out as a distinct item.
83     $identifierDepth = $this->itemSelector;
84     $iterator->rewind();
85     while ($iterator->valid()) {
86       $item = $iterator->current();
87       if (is_array($item) && $iterator->getDepth() == $identifierDepth) {
88         $items[] = $item;
89       }
90       $iterator->next();
91     }
92     return $items;
93   }
94
95   /**
96    * {@inheritdoc}
97    */
98   protected function openSourceUrl($url) {
99     // (Re)open the provided URL.
100     $source_data = $this->getSourceData($url);
101     $this->iterator = new \ArrayIterator($source_data);
102     return TRUE;
103   }
104
105   /**
106    * {@inheritdoc}
107    */
108   protected function fetchNextRow() {
109     $current = $this->iterator->current();
110     if ($current) {
111       foreach ($this->fieldSelectors() as $field_name => $selector) {
112         $field_data = $current;
113         $field_selectors = explode('/', trim($selector, '/'));
114         foreach ($field_selectors as $field_selector) {
115           if (is_array($field_data) && array_key_exists($field_selector, $field_data)) {
116             $field_data = $field_data[$field_selector];
117                 }
118                 else {
119             $field_data = '';
120           }
121         }
122         $this->currentItem[$field_name] = $field_data;
123       }
124       if (!empty($this->configuration['include_raw_data'])) {
125         $this->currentItem['raw'] = $current;
126       }
127       $this->iterator->next();
128     }
129   }
130
131 }