static_map process plugin returns array in case of default_value but string/integer in case it finds the mapped key/value

Created on 5 April 2023, over 1 year ago
Updated 22 June 2023, over 1 year ago

Problem/Motivation

Initially i wanted to write a migration from 1 source paragraph in D7 to 2 different paragraph bundles in D9 depending if the D7 paragraph had an image or not.

The issue is that when i use the static_map plugin, in case it finds the value, it returns an array. If it doesnt find it and falls back to the default_value, it returns a string.
Should we normalise the end result to be of the same type?

e.g i wanted to use the end result to set dhe type: @pseudo_bundle that the static_map plugin returned.

Steps to reproduce

Source is a paragraph that has an image field.

I created the following:

  pseudo_test_img_source:
    -
      plugin: default_value
      source: field_wms_bg_image
      default_value: para_cta

# IF source image field was empty, this pseudo-field defaults to para_cta (paragraph with no image in D9)

  pseudo_bundle:
    -
      plugin: static_map
      source: '@pseudo_test_img_source'
      map:
        'para_cta': para_cta
      default_value: 'para_cta_img'

# here i wanted to test the first pseudofield and set either para_cta or para_cta_img (paragraph with image) and use it below to set the destination bundle

type: '@pseudo_bundle'

The problem is as follows with my current setup:

When source had an empty image
"field_wms_bg_image" => []

Then my process would produce the following:

"pseudo_test_img_source" => "para_cta"
"pseudo_bundle" => "para_cta" # STRING as desired.

However when source had an image:

"field_wms_bg_image" => array:1 [
    0 => array:5 [
      "fid" => "4343"
      "alt" => ""
      "title" => ""
      "width" => "3264"
      "height" => "2448"
    ]

Then my process would produce the following:

"pseudo_test_img_source" => array:1 [
    0 => array:5 [
      "fid" => "4343"
      "alt" => ""
      "title" => ""
      "width" => "3264"
      "height" => "2448"
    ]
  ]
  "pseudo_bundle" => array:1 [
    0 => "para_cta_img"
  ]

When using the @pseudo_bundle to set the default type i get an error when the result is an array.
I tried chaining the extract option but that would fail when there was no array.

Should the static_map return the same data type either when it finds the key or when it returns the default value?

Thanks

πŸ› Bug report
Status

Closed: works as designed

Version

9.5

Component
MigrationΒ  β†’

Last updated 1 day ago

Created by

πŸ‡¦πŸ‡±Albania elvin - albania drupal developer

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • πŸ‡¦πŸ‡±Albania elvin - albania drupal developer

    I did end up solving my issue by updating the mapping to return an array as well and used extraxt to get either value

      pseudo_test_img_source:
        -
          plugin: default_value
          source: field_wms_bg_image
          default_value: para_cta
      pseudo_bundle:
        -
          plugin: static_map
          source: '@pseudo_test_img_source'
          map:
            'para_cta':
              -
                para_cta
          default_value: 'para_cta_img'
        -
          plugin: extract
          index:
            - 0
      type: '@pseudo_bundle'
    

    Still wonder if static_map should get altered -_-

  • Status changed to Closed: works as designed over 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States mikelutz Michigan, USA

    Static map doesn't change it's return value based on whether it finds a value or not, your result is expected behavior due to the way the two plugins handle multiple valued fields. Default value handles multiple valued arrays all at once, static map acts once per each array item. (This is intentional and a feature of process plugins)

    In your case, practically this means in the first case, default value sees an empty array, determines that it needs to set a default value and sets pseudo_image_test_source to a string. In the second case, it sees the whole array, determines that it doesn't need to set a default, and sets pseudo_image_test_source to the same multi-valued array it was called with.

    Then you get to static map. In the first case, static map sees a string, and replaces the value as expected.
    In the second cases, the system sees that the input is a multi-valued array (with one item, but still a multi-valued array from the processors standpoint) and that static_map has asked to receive each array item one by one in the case of a multi-valued array.

    So instead of static_map seeing

     array:1 [
        0 => array:5 [
          "fid" => "4343"
          "alt" => ""
          "title" => ""
          "width" => "3264"
          "height" => "2448"
        ]
      ]

    The system loops through the outer array and passes the first element to static_map

    array:5 [
          "fid" => "4343"
          "alt" => ""
          "title" => ""
          "width" => "3264"
          "height" => "2448"
        ]

    The map sees this isn't in its list so it returns the default, which the system properly inserts in the same spot in the original array.

    In your case, to make what you have work, I would run this:

      pseudo_test_img_source:
        -
          plugin: default_value
          source: field_wms_bg_image<strong>/0/fid</strong>
          default_value: para_cta
    
      pseudo_bundle:
        -
          plugin: static_map
          source: '@pseudo_test_img_source'
          map:
            'para_cta': para_cta
          default_value: 'para_cta_img'
    
      type: '@pseudo_bundle'
    

    or my personal preference on this situation (note: this isn't better or worse than the corrected version of your way, I think I just like having an excuse to use null_coalesce)

    source:
      constants:
        para_cta:para_cta
        para_cta_img: para_cta_img
    process:
      _has_img:
        -
          plugin: skip_on_empty
          source: field_wms_bg_image/0/fid
          method: process
        -
          plugin: get
          source: constants/para_cta_img
      type:
        plugin: null_coalesce
        source:
          - "@_has_img"
          - constants/para_cta
    

    Also the Migrate Conditions β†’ module has some nice process plugins to deal with this type of conditional processing as well.

    Also to note, the #migration slack channel is a good place to try to get help with this type of debugging in real time if you haven't been there. They can talk you through the issue and help determine if there's something to fix in your migration or a real bug that needs to have an issue filed.

  • πŸ‡¦πŸ‡±Albania elvin - albania drupal developer

    Thanks a lot @mikeluts for the time and thorough reply! I did not think of using null_coalesce
    I did lots of trial and error till i reached my end solution and stuck with that as it did get the job done fine at the moment.

Production build 0.71.5 2024