Problem/Motivation

It is currently not possible to iterate over a simple array of values. The 'sub_process' plugin only handles nested arrays where you can define a separate process pipeline for each sub-key. It is not currently possible to simply define a process pipeline and have that execute for each value in a list of values.

Note that despite the similar title this is not related to #2889717: Iterate through rows as far as I can tell.

Steps to reproduce

-

Proposed resolution

Add an 'iterate' process plugin.

Remaining tasks

  • Agree that this is useful
  • Write tests

User interface changes

-

API changes

A new 'iterate' process plugin.

Data model changes

-

CommentFileSizeAuthor
#2 3278748-2.patch4.81 KBtstoeckler

Comments

tstoeckler created an issue. See original summary.

tstoeckler’s picture

Status: Active » Needs review
StatusFileSize
new4.81 KB

Here we go. Had this locally for a project but ended up not needing this for various reasons and did not want to lose the effort. Did verify that it works and did go ahead and write some proper docs so to check off one requirement to get this in, unfortunately I did not - and probably will not - have the time to write some tests for this.

danflanagan8’s picture

This is pretty interesting to me. I'm interested in seeing better examples though. The first example:

+++ b/src/Plugin/migrate/process/Iterate.php
@@ -0,0 +1,157 @@
+ * @code
+ * process:
+ *   field_dates:
+ *     plugin: iterate
+ *     source: field_timestamps
+ *     process:
+ *       plugin: format_date
+ *       from_format: 'U'
+ *       to_format: 'Y-m-d\TH:i:s'
+ * @endcode

As far as I can tell, this is identical to the simpler:

field_dates:
  plugin: format_date
  source: field_timestamps
  from_format: 'U'
  to_format: 'Y-m-d\TH:i:s'

since format_date does not "handle_multiples".

The example using extract is more interesting because extract does "handle_multiples". Still, I think that gets us the same thing as this:

field_node_references:
  -
    plugin: explode
    delimiter: '/'
    source: field_links
  -
    plugin: sub_process
    process:
      '0': '2'
  -
    plugin: migration_lookup
    migration: node

I think more compelling examples would be good. This plugin strikes me as something I would potentially reach for, but I don't think I'd use it for either of these cases.

danflanagan8’s picture

I just put in a new issue with an alternative approach that manages to pass the complexity onto sub_process. #3314502: Add wrapper process plugin to wrap/unwrap values in arrays

luksak’s picture

Status: Needs review » Reviewed & tested by the community

This works like a charm! Thank you!

I think that for the specific use case of having an array with values this is the simpler and better solution than the approach of #3314502: Add wrapper process plugin to wrap/unwrap values in arrays.

luksak’s picture

Status: Reviewed & tested by the community » Needs review

Sorry, probably that needs a better review ;)

benjifisher’s picture

I think you can get the same effect using the build_array process plugin from #3440904: Process plugin: build an array from source, destination, pipeline.

Instead of this example from the doc block for iterate

process:
  field_dates:
    plugin: iterate
    source: field_timestamps
    process:
      plugin: format_date
      from_format: 'U'
      to_format: 'Y-m-d\TH:i:s'

you can use build_array to prepare the array of arrays that sub_process expects:

process:
  field_dates:
    - plugin: build_array
      source: field_timestamps
      template:
        - 'pipeline:'
    - plugin: sub_process
      process:
        plugin: format_date
        from_format: 'U'
        to_format: 'Y-m-d\TH:i:s'
        source: '0'

As @danflanagan8 pointed out in #3, it is much simpler in this case to let the Migrate API loop through the array for you, but I think this example shows that any time you want to use iterate, you can get the same effect with build_array and sub_process.

Many simple uses of sub_process can also be handled by build_array. The second example from #3 becomes

field_node_references:
  -
    plugin: explode
    delimiter: '/'
    source: field_links
  -
    plugin: build_array
    template:
      - pipeline:2
  -
    plugin: migration_lookup
    migration: node

The build_array plugin uses array_walk_recursive(), which is a lot simpler than sub_process and iterate, both of which create a separate process pipeline. So I prefer to use build_array when it can replace one of the others.

heddn’s picture

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

I'll take comment #7 as a good way to keep things a bit more DRY. If you still feel strongly about the addition of this feature, feel free to re-open and propose some alternatives.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.