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