The requirements for the first alpha release of the 8.x-3.0 series are:

  1. Have an usable CSV parser UI that operates without errors.
  2. Have an usable XML parser UI that operates without errors.
  3. Have a working tamper module with at least one tamper plugin.

Optional:

  1. Functional tests for the Feeds UI.

The CSV parser UI should be fixed in the Feeds module itself. The other two should be fixed in contrib: the XML parser UI in Feeds extensible parsers and the tamper module in a combination of Tamper and Feeds Tamper. However, it's likely that in order for the XML and tamper requirements to be fixed, changes are needed in Feeds, hence why they are listed here.

The plan

The first thing to complete is the CSV parser UI, because it will define the path for how the XML parser UI should be made. Feeds Tamper's architecture can be developed simultaneously, however it's UI may depend on how the UI for the CSV parser is built.

Tasks

This are the tasks to be done for the first alpha release. The red tasks are required, the yellow tasks are optional.

Task Issue Depends on
Decide how the UI should look like for the CSV parser (more or less done) #2917405: UI designs - none -
Fix the CSV parser UI #2669974: Implement the CSV parser UI UI decision
Fix the XML parser UI #2917924: Implement the XML Xpath parser UI CSV parser UI
Develop Tamper architecture #2921727: Full release of Tamper
#2917926: Port Feeds Tamper to D8
- none -
Develop bridge between Tamper and Feeds in Feeds Tamper #2917926: Port Feeds Tamper to D8 Tamper module
Create an UI for Feeds Tamper #2937728: Add an UI
#2953361: Allow Tamper plugins to be reordered
#2953362: Allow Tamper plugins to be enabled/disabled
Tamper module, Feeds Tamper architecture, possibly UI for managing custom sources
A base for functional tests #2917925: Port remaining methods from test base class in D7 - none -
Fix update existing items when not mapping to Feeds item #2857692: Update existing nodes fails when not mapping to "Feeds Item: Item URL": This value should be of the correct primitive type.
Manage custom sources #2938505: Add UI for editing and removing custom (CSV) sources CSV parser UI
Tests for the CSV parser UI #2938500: Add UI tests for the CSV parser CSV parser UI, base for functional tests

Comments

MegaChriz created an issue. See original summary.

megachriz’s picture

larowlan’s picture

Issue tags: +DrupalSouth 2017
dman’s picture

From looking at the prototype/roadmap for 'Tamper' project (NOT feeds_tamper - a confusion that lost me a bit of confusion) ....
I think that the idea for a new, stand-alone 'Tamper" API
> Tamper is a generic API for transforming data
Seems overly broad and ambitious. It (curently) appears abandoned, or at least inactive.

MY feeling is that since that idea (a fine proposal in principle) was put up as a placeholder ...
Better things and tools have become available in the D8/Symfony subsystem.

If we want a generic 'Tamper' facility (do we really, can we really without adding too much extra abstraction?) - I think that the arcitecture seems to be better to leverage the Symfony plugins for event reactions or listeners (sorry, I can't quote the exact terminology, but I have seen tools like this - tools that now stand in for our old D7 hook_x_alter() style events.

I THINK that the concept of relying on the non-existent super-generic vaporware 'tamper' external module is holding up the roll forward of progress in Feeds D8, and should probably be dropped for now.
I BELIEVE that there are other tools somewhere inside the D8 structure already that will be a better fit for this task, and will also be compatable with the D8 style of reacting on events and 'tampering/altering' objects at given phases of processing.
(I can't name-drop those yet, I've only seen them at a distance and my brain is not fresh ATM)

megachriz’s picture

@dman
You make some valid points here. You are probably right that developing a generic Tamper module first will slow down the progress for Feeds D8. So that is a valid concern for dropping Tamper module for now.
Good to hear also that there already other tools available that provide similar functionality. It would be good to investigate what they are and if it wouldn't take a lot of effort to depend on them. If it does seem to take a lot of effort, we should just go for a more 'simple' port of Feeds Tamper for now.
@dman, would you like to check what these other tools were? I know there is a Typed data API, which I haven't studied yet. Can it be that these tools are somewhere inside that API?

dman’s picture

Tamper with fields via event subscribers

I've gone back to some stuff I was remembering, and also discussed with a few other brains here at DrupalSouth today.
The subsystem I was referring to vaguely is the Symfony EventDispatcher stuff! Sorry I was temporarily drawing a blank on the word when put on the spot for an opinion before.

The Feeds D8 Conceptual Overview even acknowledges 'Events' as the paradigm to shift to. I think we just need to keep doing that, but at a more granular (per-field) level.

Looking at other related things like MigratePreRowSaveEvent, my gut was telling me that what we could be doing is registering a FeedsFieldPrepare event, and then having tampers subscribe to that event and do the altering that they want!

Even if Feeds and Feeds_Tamper is still part of the same project, it's ok for the one module to respond to its own events.
*This*, I feel, provides the abstraction of a 'tamper' opportunity that the proposed 'Tamper' module was envisioning, without introducing additional dependency or layers.

We'll still need a Feeds Tamper UI of sorts to be added to the module, and it'll still have to manage the order of the tampers (apparently Event Dispatching can't be trusted for order-of-operation) but the decoupling of the feeds pipeline into events and listeners seems to be architecturally more the way things are going.

Typed Data as internal row format

You mention typed data API - which, although it has nothing to do with *this* "tamper" question, is also a good suggestion for a standardised middleware data format I'd put forward to @thomasmurphy as they started to discuss the build of the CSV parser and plan the next XML parser.
IF we can trust and use typed_data (I'm not sure it's production-ready yet), Then yeah, I feel like Feeds should be able to return typed_data from its Parser phase, and the Processor should consume typed_data.
A win there is that pre-existing CSV->typed_data, JSON->typed_data, XML->typed_data, remote_api_call->typed_data converter libraries should already exist and become not-our-problem.
Adopting Typed_data for our arbitrarily-formatted imported rows also seems to improve potential compatibility with Rules, which I'm slowly attempting to nudge forwards also.

ericgsmith’s picture

Hi @dman - was good to meet you at DrupalSouth!

I've taken a quick look through this thread although I doubt I have nearly enough information - but here are a few thoughts - apologies if I am polluting this thread as there seem to be similar conversations happening across the 3 modules in question.

I actually quite like the idea of tamper module being decoupled - I think there would be real value in this pattern being abstracted so that eventually feeds and migrate might be able to share more of their code than they can now.

As far as the feeds module goes itself, I think a feeds tamper module can work without any additional events being fired with the existing init and process events currently in use. It could follow the same pattern of dynamically registering event subscribers after the init function fires.

E.g.
Entity structure needed
- we need a config entity of "feed tamper" or something which contains information on what tamper plugins and settings are applied to what field mappings (this would be sort of similar pattern to the entity view mode entity, in that it stores what field formatter plugins and settings are applied to what fields - feeds tamper config entity would do the same just with multiple tamper plugins/settings per mapping)

Processing steps
- feeds tamper subscribes to the feeds.init_import event
- use the feed information supplied to see if we have a relevant tamper configuration entity for the current feed. if we do, dynamically register the feed tamper process method (with a high priority so it runs before feeds process)
- in the process method instantiate the tamper plugins with their settings and call their transforms on the relevant item data. once that has run the regular feeds process will be next in line to run the import.

I don't know enough about the internal dynamics of feeds and how the mapping & storage / processing works at this stage to kick anything off the ground further - although I've as a bit of a playground to the idea added https://github.com/ericgsmith/tamper - if there is somebody willing to take the tamper idea forward I'm happy to try help out but probably can't commit many hours of my time.

megachriz’s picture

@dman, @ericgsmith
I appreciate sharing your thoughts on this subject. Not sure if understood everything of it exactly, but I'll try to respond it by my best knowledge.

Tamper with fields via event subscribers

There is already a parse event, which I had in my mind of using for Feeds Tamper. If you add a listener to this event with a lower priority than Feeds does, you'll get the parsed result which you then can modify:

class FeedsTamper implements EventSubscriberInterface {
  /**
   * {@inheritdoc}
   */
  static function getSubscribedEvents() {
    $events[FeedsEvents::PARSE][] = ['afterParse', -100];
    return $events;
  }

  /**
   * Act on parser result.
   */
  public function afterParse(ParseEvent $event) {
    /** @var \Drupal\feeds\FeedInterface */
    $feed_type = $event->getFeed();
    /** @var \Drupal\feeds\Result\ParserResultInterface */
    $parser_result = $event->getParserResult();

    /** @var \Drupal\feeds\Feeds\Item\ItemInterface */
    foreach ($parser_result as $item) {
      // Example: get an item's value.
      $authors = $item->get('authors');
      // Manipulate value.
      // 'authors' is for example: 'Morticia,Fester,Gomez'.
      $authors = explode(',', $authors);
      // And set an item's value.
      // 'authors' is now: [
      //   'Morticia',
      //   'Fester','
      //   'Gomez',
      // ].
      $item->set('authors', $authors);
    }
  }
}

I don't think that we need another event layer in this process. I do notice that there is a difference with MigratePreRowSaveEvent: in there, there's an event per row, while in the above example there is one event for all rows (or at least the rows that have been parsed which can happen in chunks, for CSV say 50 records per cycle). I'm not sure if it is bad to have an event for multiple rows instead of an event per row.

Even if Feeds and Feeds_Tamper is still part of the same project, it's ok for the one module to respond to its own events.
*This*, I feel, provides the abstraction of a 'tamper' opportunity that the proposed 'Tamper' module was envisioning, without introducing additional dependency or layers.

I'm not sure if I quite understand this. What I can tell is that Feeds already responds to its own events for performing its core tasks (fetching, parsing, processing). It sounds like you are proposing that each Tamper plugin should respond to an event. I had in mind the use of a FeedsTamperPluginManager which - based on the FeedsType - checks which Tamper plugins are configured for that type. Each configured Tamper plugin will have a weight in Feeds Tamper, which the plugin manager uses to sort the plugins so they run in the right order. On the parse event, the plugin manager would then loop through all the rows and apply all configured Tamper plugins on each row.

Typed Data as internal row format

I haven't quite got into Rules for D8 yet, but it sounds like a good idea to have Rules events for each Feeds event and that you can work with the data within Rules. When responding to the parse event in Rules, Rules would see how each item is expected to look like.
This feature does seem like a nice to have at the moment though, so I think that we should schedule it for after the first alpha release of Feeds.

Decoupled Tamper module

@ericgsmith, Great for working out a 'playground' of the Tamper module. It looks already way more advanced than my initial playground. While a separate Tamper module could add additional time to develop and probably adds extra complexity (because more modules will be in play), I think we should give it a go, certainly because ericgsmith's playground looks like to head in a good direction. If, after a while, it doesn't seem to work out, we can then still go for a more straightforward port of Feeds Tamper.

I propose to check back after a few weeks to see if the Tamper module evolves further and if Feeds Tamper can make use of the Tamper plugins. Let's aim to have steps 1 until 3 from #2917926: Port Feeds Tamper to D8 be done by December 31, 2017. That is:

  1. Develop generic Tamper module architecture with at least one working Tamper plugin (but preferable a few more).
  2. Let Feeds Tamper make use of Tamper plugins and apply these on the parser result (bridge between Tamper and Feeds).
  3. A config schema for Feeds Tamper (each instantiated plugin needs at least a reference to the feed type, a reference to the source field and a weight).

Would that fit into your schedule, @ericgsmith? If so, I'll plan a few hours a week to work on the code for this as well.

Perhaps we should move the discussion about Tamper over to #2917926: Port Feeds Tamper to D8 as I had there a separate discussion about it with @larowlan.

damienmckenna’s picture

It might be a silly question, but is the tamper stuff even needed for the first alpha if there's an underlying API to work from?

megachriz’s picture

@DamienMcKenna
Thanks for asking!

Strictly spoken, the Tamper module isn't needed for the first alpha as there are possible workarounds. In my opinion though these workarounds are not obvious and therefore hard to apply for non-developers.

My idea of the first alpha release is to have a Feeds version that covers at least basic usage without custom coding. In my opinion at least the Tamper plugin "explode" (with which you can turn a value into multiple values) belongs to the basic use cases. It is often needed when importing CSV files where you can put a list of values into a single column.

megachriz’s picture

Issue summary: View changes

I've updated the links to issues in the issue summary. For the UI of Feeds Tamper an issue has been created #2937728: Add an UI. Development on the Tamper module can be tracked on #2921727: Full release of Tamper, though #2917926: Port Feeds Tamper to D8 currently contains most of the discussion on the module.

megachriz’s picture

Issue summary: View changes

An UI for the CSV parser is added!

Two followup issues have been created:
#2938505: Add UI for editing and removing custom (CSV) sources
#2938500: Add UI tests for the CSV parser

Both should be aimed for, but they are not blockers for 8.x-3.0-alpha1.

megachriz’s picture

megachriz’s picture

This week in Feeds D8:

  1. Max completed implementing permissions for Feeds Tamper: #2942067: Implement permissions. He'll be working on the Feeds Tamper UI next.
  2. Eric worked on a Feeds Tamper add form (in order to test Tamper config forms better): #2937728: Add an UI.
  3. Eric made some progress on the Tamper module: #2937719: Multiple value handling, #2937721: Create 'SkipException' classes. and #2937717: Add support for manipulating a complete 'feeds item'/'row'..
  4. MegaChriz made #2939503: Unpublish/Delete nodes not included in feed ready for review/testing. He also added some automated tests to Feeds.

Next Feeds meeting will be on Thursday, February 15 at 19:00 UTC on Drupal Slack in the #feeds channel!

megachriz’s picture

This week in Feeds D8:

  1. Errors with feeds_item.0.url were fixed! #2857692: Update existing nodes fails when not mapping to "Feeds Item: Item URL": This value should be of the correct primitive type.
  2. Unpublish/delete nodes not included in feed was finalized! #2939503: Unpublish/Delete nodes not included in feed
  3. Feeds has a more usable base class for functional tests.
  4. Better handling of multiple values in Tamper plugins: #2937719: Multiple value handling and #2948569: Handle multival changes from tamper module

The plan for the coming week:

  1. Finalize remove Tamper UI: #2948850: Add an availability to remove tampers from sources
  2. Fix #2946698: Call to undefined method getSetting() in all tampers together with #2948543: Make all plugins configurable
  3. Max plans to finish the Feeds Tamper overview page (the UI where you can see all plugins on the Feed type with links to add, edit and delete). #2937728: Add an UI
  4. Eric plans to look further into using context aware Tamper plugins: #2937717: Add support for manipulating a complete 'feeds item'/'row'.
  5. The XML parser UI: MegaChriz plans to examine what changes would be needed to both Feeds and Feeds extensible parsers to supply the "context" field at the top of the mapping page. #2917924: Implement the XML Xpath parser UI
  6. Should there be time left, MegaChriz plans to review/test #2911491: Provide feeds type fields as mapping sources
megachriz’s picture

Issue summary: View changes

Added references for follow-ups for the Feeds Tamper UI in the issue summary: #2953361: Allow Tamper plugins to be reordered and #2953362: Allow Tamper plugins to be enabled/disabled.

megachriz’s picture

This week in Feeds D8:

  1. The UI for removing Tampers was finalized: #2948850: Add an availability to remove tampers from sources
  2. Max made the UI for the Tamper listing: #2937728: Add an UI. For the UI listing there are three follow-ups: #2953361: Allow Tamper plugins to be reordered, #2953362: Allow Tamper plugins to be enabled/disabled and #2949203: Add UI tests.
  3. Irina worked on a plan for Feeds + Migrate integration: https://docs.google.com/document/d/1XJpw36kw-Fpck_kLa9iR8wEtKInhz9SxgZ1F...

The plan for the coming week:

  1. Irina will continue to work on the Feeds + Migrate integration plan.
  2. The XML parser UI: MegaChriz plans to examine what changes would be needed to both Feeds and Feeds extensible parsers to supply the "context" field at the top of the mapping page. #2917924: Implement the XML Xpath parser UI
  3. Should there be time left, MegaChriz plans to review/test #2911491: Provide feeds type fields as mapping sources
megachriz’s picture

This week in Feeds:

  1. A start was made on the XML Xpath parser UI: #2917924: Implement the XML Xpath parser UI
  2. Fixes for #2948543: Make all plugins configurable and #2946698: Call to undefined method getSetting() in all tampers were committed.

The plan for the coming week:

  1. Irina will continue to work on the Feeds + Migrate integration plan.
  2. MegaChriz plans to work further on the XML Xpath parser UI.
  3. Eric plans to work further on #2937721: Create 'SkipException' classes..

The next Feeds meetup will be on Thursday, March 29 at 18:00 UTC. That's one hour earlier as before. The time shift happens because of daylight saving time in Europe. So in Europe time, it will be at the same time.

cmcintosh’s picture

@MegaCriz I have a bit of an immediate need for feeds. But from the UI designs it looks like feeds is sticking with supporting Node / Users, is this correct?

megachriz’s picture

@cmcintosh
Other content entity types can be supported as well. I have been experimenting with a wider support of content entity types in my sandbox module Feeds DEV. So far, that particular feature - a generic entity processor - seems to work very well. I have only tested it on Commerce products and Commerce product variations though.

megachriz’s picture

Status: Active » Fixed

Feeds 8.x-3.0-alpha1 has been released! Feeds extensible parsers 8.x-1.0-alpha1 has been released as well.

I'll update this issue when an initial plan for the next release is made.

hongpong’s picture

Thanks for all your hard work on this!! It's much appreciated, feeds is such a good module.

mxwright’s picture

Yes! Just tested and it worked for me.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

megachriz’s picture

8.x-3.0-alpha2 has been released!
https://www.drupal.org/project/feeds/releases/8.x-3.0-alpha2

See what is planned for the next release: #2978642: Plan for 8.x-3.0-alpha3 release.