Instead of providing a fixed default value it would be nice to get it from a source field. For example if you want to set a destination field_nickname which should get the value from source_nickname, but if that is empty it should get the value from source_name.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

osopolar created an issue. See original summary.

osopolar’s picture

Status: Active » Needs review
FileSize
1.95 KB
heddn’s picture

I feel like this could be done with skip_on_value, which is already in migrate_plus.

mikeryan’s picture

Yes, this seems unnecessary. It's not really getting a default value, it's saying use the first non-empty value among these source properties, which can be done with skip_on_value, or something like

process:
  field_example:
    -
      plugin: get
      source:
        - source_nickname
        - source_name
    -
      plugin: callback
      callable: array_filter
    -
      plugin: callback
      callable: reset

Alright, that was more elaborate than I expected, skip_on_value makes more sense...

osopolar’s picture

Thanks for your help. I have searched for process plugins. The only one which seemed helpful was the array merge plugin, but it seemed to complicate to build the migration that way. I was not aware of skip_on_value, and now I am, but not sure on how to use it (in above example). Would be nice if you may explain the use of that plugin here and/or in the plugin documentation.

My actual use case (to migrate content access settings) looks a bit more complicated and with #4 it might be even harder to understand what's going on there. That's why I wrote the get_default_value process plugin, and thought there could be some common use for it.

process:
  default_content_access_view:
    source: post_type
    plugin: static_map
    map:
      page:
        - anonymous
        - authenticated
        - administrator
      post:
        - authenticated
        - administrator
  content_access_view_legacy_unblock:
    -
      source: unblock
      plugin: static_map
      bypass: true
      map:
        1:
          - anonymous
          - authenticated
          - administrator
    -
      plugin: get_default_value
      source: '@default_content_access_view'
  'content_access_settings/view':
    -
      source: _wpmem_block
      plugin: static_map
      bypass: true
      map:
        0:
          - anonymous
          - authenticated
          - administrator
        1:
          - authenticated
          - administrator
    -
      plugin: get_default_value
      source: '@content_access_view_legacy_unblock'
osopolar’s picture

I rewrote my migration with the information in #4 and it does not look that bad ;) ... but it don't work, ans it gives me the error:

Parameter 1 to reset() expected to be a reference, value given Callback.php:54

That's because reset() expects a reference to actually reset the array pointer and call_user_func used in Callback.php only passes parameters by value. Hopefully the the pointer is already at the first element so the current callback could be used:

      plugin: callback
      callable: current

Anyway, I would like to see how to implement #4 using the skip_on_value plugin. Maybe it would be helpful for others too, as there is not much documentation about it.

heddn’s picture

Status: Needs review » Closed (won't fix)

Based on the gist here from @osopolar, it doesn't seem like this is necessary: https://gist.github.com/osopolar/4604995624932507654f42f655ae979e

osopolar’s picture

Content of above mentioned gist:

  'content_access_settings/view':
    -
      plugin: get
      source:
        - '@content_access_view_legacy_unblock'
        - '@content_access_view_wpmem_block'
        - '@default_content_access_view'
    -
      # Filter out empty sources
      plugin: callback
      callable: array_filter
    -
      # Use the first none empty source
      plugin: callback
      callable: 'current'

I like that solution, which is based on input from #4 (thank you mikeryan), as it is very clean.

Anyway, the get_default_value Plugin, which just combines the get and the default_value plugins, is still useful to me. I'll add it to my custom migrate module. Here the source code, if anybody else needs it:

namespace Drupal\migrate_plus\Plugin\migrate\process;

use Drupal\migrate\Plugin\migrate\process\Get;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\Row;

/**
 * Returns a different source value as fallback if the input is empty.
 *
 * The get_default_value process plugin provides the ability to set a different
 * source value if the input value is considered empty (NULL, FALSE, 0, '0',
 * an empty string, or an empty array).
 * The strict configuration key can be used to set the default only when the
 * incoming value is NULL.
 *
 * Available configuration keys:
 * - source: The sorce for the default value.
 * - strict: (optional) Use strict value checking. Defaults to false.
 *   - FALSE: Apply default when input value is empty().
 *   - TRUE: Apply default when input value is NULL.
 *
 * Example:
 *
 * @code
 * process:
 *   field_nickname:
 *     -
 *       plugin: get
 *       source: nick_name
 *     -
 *       plugin: get_default_value
 *       source: name
 * @endcode
 *
 * This will look up the source value of nick_name and if not found, set the
 * source value of name.
 *
 * @see \Drupal\migrate\Plugin\MigrateProcessInterface
 *
 * @MigrateProcessPlugin(
 *   id = "get_default_value"
 * )
 */
class GetDefaultValue extends Get {

  /**
   * {@inheritdoc}
   */
  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    if (!empty($this->configuration['strict'])) {
      return isset($value) ? $value : parent::transform($value, $migrate_executable, $row, $destination_property);
    }
    return $value ?: parent::transform($value, $migrate_executable, $row, $destination_property);
  }
}
osopolar’s picture

Status: Closed (won't fix) » Closed (duplicate)
Related issues: +#2821349: Is there any fallback value process plugin ?

Actually it's a duplicate of.