diff --git a/feeds_tamper.services.yml b/feeds_tamper.services.yml index 5cdeee2..944ee9b 100644 --- a/feeds_tamper.services.yml +++ b/feeds_tamper.services.yml @@ -4,5 +4,6 @@ services: parent: container.trait feeds_tamper.feeds_subscriber: class: Drupal\feeds_tamper\EventSubscriber\FeedsSubscriber + arguments: ['@feeds_tamper.feed_type_tamper_manager'] tags: - {name: event_subscriber} diff --git a/src/EventSubscriber/FeedsSubscriber.php b/src/EventSubscriber/FeedsSubscriber.php index 08bc91d..e2eae3e 100644 --- a/src/EventSubscriber/FeedsSubscriber.php +++ b/src/EventSubscriber/FeedsSubscriber.php @@ -4,6 +4,8 @@ namespace Drupal\feeds_tamper\EventSubscriber; use Drupal\feeds\Event\FeedsEvents; use Drupal\feeds\Event\ParseEvent; +use Drupal\feeds_tamper\FeedTypeTamperManagerInterface; +use Exception; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -16,6 +18,23 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; class FeedsSubscriber implements EventSubscriberInterface { /** + * A feed type meta object. + * + * @var \Drupal\feeds_tamper\FeedTypeTamperManagerInterface + */ + protected $tamperManager; + + /** + * Constructs a new FeedsSubscriber object. + * + * @param \Drupal\feeds_tamper\FeedTypeTamperManagerInterface + * A feed type meta object. + */ + public function __construct(FeedTypeTamperManagerInterface $tamper_manager) { + $this->tamperManager = $tamper_manager; + } + + /** * {@inheritdoc} */ public static function getSubscribedEvents() { @@ -27,14 +46,13 @@ class FeedsSubscriber implements EventSubscriberInterface { * Acts on parser result. */ public function afterParse(ParseEvent $event) { - /** @var \Drupal\feeds\FeedInterface */ + /** @var \Drupal\feeds\FeedInterface $feed */ $feed = $event->getFeed(); - /** @var \Drupal\feeds\Result\ParserResultInterface */ + /** @var \Drupal\feeds\Result\ParserResultInterface $parser_result */ $parser_result = $event->getParserResult(); - /** @var \Drupal\feeds_tamper\FeedTypeTamperMetaInterface */ - // @todo Refactor using dependency injection. - $tamper_meta = \Drupal::service('feeds_tamper.feed_type_tamper_manager')->getTamperMeta($feed->getType()); + /** @var \Drupal\feeds_tamper\FeedTypeTamperMetaInterface $tamper_meta */ + $tamper_meta = $this->tamperManager->getTamperMeta($feed->getType()); // Load the tamper plugins that need to be applied to Feeds. $tampers_by_source = $tamper_meta->getTampersGroupedBySource(); @@ -44,7 +62,7 @@ class FeedsSubscriber implements EventSubscriberInterface { return; } - /** @var \Drupal\feeds\Feeds\Item\ItemInterface */ + /** @var \Drupal\feeds\Feeds\Item\ItemInterface $item */ foreach ($parser_result as $item) { foreach ($tampers_by_source as $source => $tampers) { // Get the value for a source. @@ -64,6 +82,9 @@ class FeedsSubscriber implements EventSubscriberInterface { // value needs to be iterated and each scalar separately transformed. if ($multiple && !$definition['handle_multiples']) { $new_value = []; + if (!is_array($item_value)) { + throw new Exception(sprintf('Tampering failed at %s plugin for source %s: %s received instead of an array.', $tamper->getSetting('uuid'), $source, $item_value)); + } foreach ($item_value as $scalar_value) { $new_value[] = $tamper->tamper($scalar_value); } diff --git a/tests/src/Unit/EventSubscriber/FeedsSubscriberTest.php b/tests/src/Unit/EventSubscriber/FeedsSubscriberTest.php new file mode 100644 index 0000000..ca6909e --- /dev/null +++ b/tests/src/Unit/EventSubscriber/FeedsSubscriberTest.php @@ -0,0 +1,222 @@ +event = new ParseEvent($this->getMockFeed(), $this->getMock(FetcherResultInterface::class)); + $this->event->setParserResult(new ParserResult()); + + // Create tamper meta. + $this->tamperMeta = $this->getMock(FeedTypeTamperMetaInterface::class); + + // Create feed type tamper manager. + $tamper_manager = $this->getMock(FeedTypeTamperManagerInterface::class); + $tamper_manager->expects($this->any()) + ->method('getTamperMeta') + ->will($this->returnValue($this->tamperMeta)); + + // And finally, create the subscriber to test. + $this->subscriber = new FeedsSubscriber($tamper_manager); + } + + /** + * Creates a tamper mock with a return value for the tamper() method. + * + * @param mixed $return_value + * (optional) The value that the tamper plugin must return when tamper() gets + * called on it. + * + * @return \Drupal\tamper\TamperInterface + * A mocked tamper plugin. + */ + protected function createTamperMock($return_value = NULL) { + $tamper = $this->getMock(TamperInterface::class); + $tamper->expects($this->any()) + ->method('tamper') + ->will($this->returnValue($return_value)); + + return $tamper; + } + + /** + * @covers ::afterParse + */ + public function testAfterParse() { + $tamper = $this->getMock(TamperInterface::class); + $tamper->expects($this->any()) + ->method('tamper') + ->will($this->returnValue('Foo')); + + $this->tamperMeta->expects($this->once()) + ->method('getTampersGroupedBySource') + ->will($this->returnValue([ + 'alpha' => [ + $this->createTamperMock('Foo'), + ], + ])); + + // Add an item to the parser result. + $item = new DynamicItem(); + $item->set('alpha', 'Bar'); + $this->event->getParserResult()->addItem($item); + + $this->subscriber->afterParse($this->event); + $this->assertEquals('Foo', $item->get('alpha')); + } + + /** + * @covers ::afterParse + */ + public function testAfterParseWithNoItems() { + $this->tamperMeta->expects($this->once()) + ->method('getTampersGroupedBySource') + ->will($this->returnValue([ + 'alpha' => [ + $this->createTamperMock('Foo'), + ], + ])); + + $this->subscriber->afterParse($this->event); + } + + /** + * @covers ::afterParse + */ + public function testAfterParseWithNoTampers() { + $this->tamperMeta->expects($this->once()) + ->method('getTampersGroupedBySource') + ->will($this->returnValue([])); + + // Add an item to the parser result. + $item = new DynamicItem(); + $item->set('alpha', 'Bar'); + $this->event->getParserResult()->addItem($item); + + // Run event callback. + $this->subscriber->afterParse($this->event); + $this->assertEquals('Bar', $item->get('alpha')); + } + + /** + * @covers ::afterParse + */ + public function testAfterParseWithMultiValueTampers() { + // Create a tamper that turns an input value into an array. + $tamper1 = $this->prophesize(TamperInterface::class); + $tamper1->tamper('Bar') + ->willReturn(['Bar', 'Bar']); + $tamper1->getPluginDefinition()->willReturn([ + 'handle_multiples' => FALSE, + ]); + $tamper1->multiple()->willReturn(TRUE); + $tamper1 = $tamper1->reveal(); + + // Create a tamper that returns 'Foo'. + $tamper2 = $this->prophesize(TamperInterface::class); + $tamper2->tamper('Bar') + ->willReturn('Foo'); + $tamper2->getPluginDefinition()->willReturn([ + 'handle_multiples' => FALSE, + ]); + $tamper2->multiple()->willReturn(FALSE); + $tamper2 = $tamper2->reveal(); + + // Create a tamper that returns 'FooFoo'. + $tamper3 = $this->prophesize(TamperInterface::class); + $tamper3->tamper('Foo') + ->willReturn('FooFoo'); + $tamper3->getPluginDefinition()->willReturn([ + 'handle_multiples' => FALSE, + ]); + $tamper3->multiple()->willReturn(FALSE); + $tamper3 = $tamper3->reveal(); + + $this->tamperMeta->expects($this->once()) + ->method('getTampersGroupedBySource') + ->will($this->returnValue([ + 'alpha' => [$tamper1, $tamper2, $tamper3], + ])); + + // Add an item to the parser result. + $item = new DynamicItem(); + $item->set('alpha', 'Bar'); + $this->event->getParserResult()->addItem($item); + + // Run event callback. + $this->subscriber->afterParse($this->event); + $this->assertEquals(['FooFoo', 'FooFoo'], $item->get('alpha')); + } + + /** + * @covers ::afterParse + */ + public function testAfterParseException() { + $tamper = $this->prophesize(TamperInterface::class); + $tamper->tamper('Bar') + ->willReturn('tamper_return_string'); + $tamper->getPluginDefinition()->willReturn([ + 'handle_multiples' => FALSE, + ]); + $tamper->multiple()->willReturn(TRUE); + $tamper->getSetting('uuid') + ->willReturn('uuid1'); + $tamper = $tamper->reveal(); + + $this->tamperMeta->expects($this->once()) + ->method('getTampersGroupedBySource') + ->will($this->returnValue([ + 'alpha' => [$tamper, $tamper], + ])); + + // Add an item to the parser result. + $item = new DynamicItem(); + $item->set('alpha', 'Bar'); + $this->event->getParserResult()->addItem($item); + + $this->setExpectedException(Exception::class); + $this->subscriber->afterParse($this->event); + } + +} diff --git a/tests/src/Unit/FeedsTamperTestCase.php b/tests/src/Unit/FeedsTamperTestCase.php new file mode 100644 index 0000000..8a8ae85 --- /dev/null +++ b/tests/src/Unit/FeedsTamperTestCase.php @@ -0,0 +1,10 @@ +