Score:1

How to use migrate process plugin concat on multiple values?

bv flag

I am trying to import from a csv that has multiple files in the same column, e.g.

title,gallery,tag
node1,img1.jpg|img2.jpg|img3.jpg,2
node2,img4.jpg,2
node3,img5.jpg|img6.jpg,3

I need to prepend the path to these file names to get something of the form /path/to/file/img4.jpg.

I have written a process pipeline similar to the following (which doesn't work):

source:
  constants:
    file_source: '/import/images/'
    file_destination: '/path/to/file/'
process:
  title: title
  field_gallery:
    -
      plugin: explode
      source: gallery
      delimiter: '|'
    -
      plugin: concat
      source:
        - constants/file_source
        -
    -
      plugin: image_import
      destination: constants/file_destination

The failure comes because the Concat plugin implodes the array containing a string and an array to give an output in the form /path/to/file/Array.

I suspect there is a process plugin that I can insert between explode and concat that will solve this, but I can't work out what it is.

I have tried combinations of the plugins single_value and multiple_values from the Migrate Plus module, but that has not worked either.

For now I have written a custom process plugin to replace concat, but I would prefer a pipeline using pre-existing plugins.

Score:1
ru flag

I don't think this is possible with concat in a single pipe, because you need to define two sources for concat, and AFAIK you can't fill the source partly with the result from the previous section and partly with a completely new value.

Workaround: Use the str_replace plugin instead, which is a wrapper for PHP's preg_replace.

preg_replace will detect if source respectively $subject is an string or an array. If the $subject is an array, all elements will be updated, so you can replace all beginnings of a string ^ with /some/path/

Something like this:

  field_gallery:
    -
      plugin: str_replace
      regex: true
      source: gallery
      search: '/^/'
      replace: '/some/path/'

(Note that the slashes in search are not path delimiters, they are the enclosing symbol for the regex pattern)

bv flag
Thanks @Hudri, I definitely prefer using the `str_replace` process plugin over a custom plugin. Can you think of a way to use a source constant, i.e. `constants/file_source` rather than hard-coding the value of `replace` to `'/some/path/'`?
ru flag
Not really, this is by design of the Migrate module. Only the `source:` is treated like a reference, all other keys are config and used like a value.
Score:0
bv flag

Here are the highlights of the process plugin I wrote, in case anyone is interested in a custom solution:

class Prepend extends ProcessPluginBase {

  public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
    $return = [];
    foreach ($value as $item) {
      $return[] = implode($item);
    }
    return $return;
  }

  public function multiple() {
    return TRUE;
  }

}

Note: an important difference between this and the concat process plugin is the addition of the multiple() function that returns TRUE.

It can be used as follows:

field_gallery:
  -
    plugin: explode
    source: gallery_images
    delimiter: '|'
  -
    plugin: prepend
    source:
      - constants/file_source
      -
  -
    plugin: image_import
    destination: constants/file_destination
    uid: '@uid'
    skip_on_missing_source: true

EDIT: FWIW I have chosen to use the solution suggested by @Hudri.

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.