3 namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser;
5 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
6 use Drupal\migrate_plus\DataParserPluginBase;
9 * Obtain JSON data for migration.
13 * title = @Translation("JSON")
16 class Json extends DataParserPluginBase implements ContainerFactoryPluginInterface {
19 * Iterator over the JSON data.
26 * Retrieves the JSON data and returns it as an array.
32 * The selected data to be iterated.
34 * @throws \GuzzleHttp\Exception\RequestException
36 protected function getSourceData($url) {
37 $response = $this->getDataFetcherPlugin()->getResponseContent($url);
39 // Convert objects to associative arrays.
40 $source_data = json_decode($response, TRUE);
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);
49 // Backwards-compatibility for depth selection.
50 if (is_int($this->itemSelector)) {
51 return $this->selectByDepth($source_data);
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];
65 * Get the source data for reading.
67 * @param array $raw_data
68 * Raw data from the JSON feed.
71 * Selected items at the requested depth of the JSON feed.
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);
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;
85 while ($iterator->valid()) {
86 $item = $iterator->current();
87 if (is_array($item) && $iterator->getDepth() == $identifierDepth) {
98 protected function openSourceUrl($url) {
99 // (Re)open the provided URL.
100 $source_data = $this->getSourceData($url);
101 $this->iterator = new \ArrayIterator($source_data);
108 protected function fetchNextRow() {
109 $current = $this->iterator->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];
122 $this->currentItem[$field_name] = $field_data;
124 if (!empty($this->configuration['include_raw_data'])) {
125 $this->currentItem['raw'] = $current;
127 $this->iterator->next();