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 * The request headers passed to the data fetcher.
23 protected $headers = [];
26 * Iterator over the JSON data.
33 * Retrieves the JSON data and returns it as an array.
39 * The selected data to be iterated.
41 * @throws \GuzzleHttp\Exception\RequestException
43 protected function getSourceData($url) {
44 $response = $this->getDataFetcherPlugin()->getResponseContent($url);
46 // Convert objects to associative arrays.
47 $source_data = json_decode($response, TRUE);
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);
56 // Backwards-compatibility for depth selection.
57 if (is_int($this->itemSelector)) {
58 return $this->selectByDepth($source_data);
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];
72 * Get the source data for reading.
74 * @param array $raw_data
75 * Raw data from the JSON feed.
78 * Selected items at the requested depth of the JSON feed.
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);
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;
92 while ($iterator->valid()) {
93 $item = $iterator->current();
94 if (is_array($item) && $iterator->getDepth() == $identifierDepth) {
105 protected function openSourceUrl($url) {
106 // (Re)open the provided URL.
107 $source_data = $this->getSourceData($url);
108 $this->iterator = new \ArrayIterator($source_data);
115 protected function fetchNextRow() {
116 $current = $this->iterator->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];
124 $this->currentItem[$field_name] = $field_data;
126 if (!empty($this->configuration['include_raw_data'])) {
127 $this->currentItem['raw'] = $current;
129 $this->iterator->next();