Comments

camerongreen created an issue. See original summary.

camerongreen’s picture

Issue summary: View changes
megachriz’s picture

Status: Active » Fixed

No alter hooks, but events

Feeds uses events instead of hooks in D8. The event you'll need to subscribe to is FeedsEvents::PARSE. Since Feeds uses this event also to perform its core tasks (see Drupal\feeds\EventSubscriber\LazySubscriber), you'll need to give the callback function a priority below zero. You can also use the constant FeedsEvents::AFTER for this.

In #2917928-8: Plan for 8.x-3.0-alpha1 release I posted an example for manipulating the parsed result.

After parse base class

I'm also considering adding a base class for parser result manipulation, to make it easier to make manipulations in a custom module if you need to make a lot. That's currently posted in #2772601-12: Is there a way to Skip row processing which matches some condition. I would like some feedback on that.

Feeds Tamper

Feeds Tamper for D8 is already available, though it is still in the dev stage. The main reason for that is that #2971881: Plugins that depend on a tamperable item need to know the available properties isn't fixed yet, which blocks some Tamper plugins from being ported, for example the "Rewrite" plugin. The "Explode" plugin - which you need to split out some comma separated fields into individual strings - is already available.

camerongreen’s picture

Great answer, thanks! Yes I was just looking at events and that event in particular, so good to know I was heading in the right direction. So much to learn in Drupal 8.

camerongreen’s picture

From MegaChriz's answer this is roughly how I did it.

modules/custom/mymodule/mymodule.services.yml

services:
  mymodule.subscriber:
    class: Drupal\mymodule\EventSubscriber\MyModuleEventsSubscriber
    tags:
      - {name: event_subscriber}

modules/custom/mymodule/src/EventSubscriber/MyModuleEventsSubscriber.php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\feeds\Event\FeedsEvents;
use Drupal\feeds\Event\ParseEvent;
use Drupal\feeds\Feeds\Item\ItemInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;


class MyModuleEventsSubscriber implements EventSubscriberInterface {

  /**
   * Constructor.
   */
  public function __construct() {
  }


  /**
   * Modify events after existing parser.
   *
   * @param \Drupal\feeds\Event\ParseEvent $event
   *   The parse event.
   */
  public function afterParse(ParseEvent $event) {
    /**
     * @var \Drupal\feeds\Result\ParserResultInterface
     * @var \Drupal\feeds\Feeds\Item\ItemInterface
     */
    foreach ($event->getParserResult() as $item) {
      $this->alterItem($item, $event);
    }
  }


  /**
   * Alters a single item.
   *
   * @param \Drupal\feeds\Feeds\Item\ItemInterface
   *   The item to make modifications on.
   * @param \Drupal\feeds\Event\ParseEvent $event
   *   The parse event.
   */
  protected function alterItem(ItemInterface $item, ParseEvent $event) {
    // Get the field after mapping and adjust it.
    $this->splitTaxonomyTerms('mappedfield', $item);
  }


  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = [];
    $events[FeedsEvents::PARSE][] = ['afterParse', FeedsEvents::AFTER];
    return $events;
  }


  /**
   * Splits a taxonomy term into individual strings
   * separated on comma.
   *
   * @param string $field
   * @param \Drupal\feeds\Feeds\Item\ItemInterface $item
   */
  protected function splitTaxonomyTerms(string $field, ItemInterface $item): void {
    $raw_value = $item->get($field);
    $new_value = preg_split('/\s*,\s*/', $raw_value);
    $item->set($field, $new_value);
  }
}
megachriz’s picture

Looks good. If you have more than one feed type, you may want to limit altering the parse result to just certain feed types.

For example, you could add the following code to the afterParse() method:

if ($event->getFeed()->getType()->id() != 'my_feed_type') {
  // Not the feed type we are interested in. Abort.
  return;
}
dchatry’s picture

Works perfectly thanks both of you!

This type of example should be added to the documentation ;)

Status: Fixed » Closed (fixed)

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

nasseralikarimi’s picture

Issue summary: View changes

It works fine, thanks for all your time.

maskedjellybean’s picture

Is the example in #5 still relevant? Using phpStorm and Xdebug, I set breakpoints in each method. I then ran my import and nothing was triggered. If it is still relevant, at what point in the import process should I expect this to be called? And could we add this to the documentation?

maskedjellybean’s picture

Nevermind! I just had to clear the caches again. This would've been impossible without step debugger but that's true of anything in D8. I still think this should be added to the documentation. Here's another real world example in case it helps someone:

namespace Drupal\oh_events\EventSubscriber;

use Drupal\feeds\Event\FeedsEvents;
use Drupal\feeds\Event\ParseEvent;
use Drupal\feeds\Feeds\Item\ItemInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;


class FeedsEventSubscriber implements EventSubscriberInterface {

  /**
   * Constructor.
   */
  public function __construct() {
  }


  /**
   * Modify events after existing parser.
   *
   * @param \Drupal\feeds\Event\ParseEvent $event
   *   The parse event.
   */
  public function afterParse(ParseEvent $event) {
    /**
     * @var \Drupal\feeds\Result\ParserResultInterface
     * @var \Drupal\feeds\Feeds\Item\ItemInterface
     */
    if ($event->getFeed()->getType()->id() == 'events') {
      foreach ($event->getParserResult() as $item) {

        // Remove '[View All Classes & Events]' from categories so
        // it is not created as a taxonomy term.
        $category_names = $item->get('categories_category_category_name');
        if (!empty($category_names)) {
          foreach ($category_names as $key => $category_name) {
            if ($category_name == '[View All Classes & Events]') {
              unset($category_names[$key]);
            }
          }
          $item->set('categories_category_category_name', $category_names);
        }
      }
    }
  }


  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    $events = [];
    $events[FeedsEvents::PARSE][] = ['afterParse', FeedsEvents::AFTER];
    return $events;
  }
}