diff --git a/src/Plugin/migrate/process/Service.php b/src/Plugin/migrate/process/Service.php new file mode 100644 index 0000000000000000000000000000000000000000..cd91028096ce61d7a683eccb9a63161e892b48a2 --- /dev/null +++ b/src/Plugin/migrate/process/Service.php @@ -0,0 +1,56 @@ +<?php + +namespace Drupal\migrate_plus\Plugin\migrate\process; + +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\migrate\Plugin\migrate\process\Callback; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Provides a plugin to use a callable from a service class. + * + * Example: + * + * @code + * process: + * filemime: + * plugin: service + * service: file.mime_type.guesser + * method: guessMimeType + * source: filename + * @endcode + * + * All options for the callback plugin can be used, except for 'callable', + * which will be ignored. + * + * @see \Drupal\migrate\Plugin\migrate\process\Callback + * + * @MigrateProcessPlugin( + * id = "service" + * ) + */ +class Service extends Callback implements ContainerFactoryPluginInterface { + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + if (!isset($configuration['service'])) { + throw new \InvalidArgumentException('The "service" must be set.'); + } + if (!isset($configuration['method'])) { + throw new \InvalidArgumentException('The "method" must be set.'); + } + if (!$container->has($configuration['service'])) { + throw new \InvalidArgumentException(sprintf('You have requested the non-existent service "%s".', $configuration['service'])); + } + $service = $container->get($configuration['service']); + if (!method_exists($service, $configuration['method'])) { + throw new \InvalidArgumentException(sprintf('The "%s" service has no method "%s".', $configuration['service'], $configuration['method'])); + } + + $configuration['callable'] = [$service, $configuration['method']]; + return new static($configuration, $plugin_id, $plugin_definition); + } + +} diff --git a/tests/src/Kernel/Plugin/migrate/process/ServiceTest.php b/tests/src/Kernel/Plugin/migrate/process/ServiceTest.php new file mode 100644 index 0000000000000000000000000000000000000000..59086865d208cba9d8874790336d187352a6e13f --- /dev/null +++ b/tests/src/Kernel/Plugin/migrate/process/ServiceTest.php @@ -0,0 +1,118 @@ +<?php + +namespace Drupal\Tests\migrate_plus\Kernel\Plugin\migrate\process; + +use Drupal\KernelTests\KernelTestBase; +use Drupal\migrate\MigrateExecutableInterface; +use Drupal\migrate\Row; + +/** + * Tests the service plugin. + * + * @coversDefaultClass \Drupal\migrate_plus\Plugin\migrate\process\Service + * @group migrate_plus + */ +class ServiceTest extends KernelTestBase { + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'migrate', + 'migrate_plus', + 'system', + ]; + + /** + * The process plugin manager. + * + * @var \Drupal\migrate\Plugin\MigratePluginManagerInterface + */ + protected $pluginManager; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $this->pluginManager = $this->container->get('plugin.manager.migrate.process'); + } + + /** + * Tests using a service. + * + * @covers ::create + */ + public function testValidConfig(): void { + /** @var \Drupal\migrate\MigrateExecutableInterface $executable */ + $executable = $this->prophesize(MigrateExecutableInterface::class)->reveal(); + $row = new Row([], []); + $configuration = [ + 'service' => 'email.validator', + 'method' => 'isValid', + ]; + /** @var \Drupal\migrate_plus\Plugin\migrate\process\Service $service */ + $service = $this->pluginManager->createInstance('service', $configuration); + + // Test a valid email address. + $value = 'drupal@example.com'; + $bool = $service->transform($value, $executable, $row, 'destination_property'); + $this->assertEquals(TRUE, $bool); + + // Test an invalid email address. + $value = 'drupal_example.com'; + $bool = $service->transform($value, $executable, $row, 'destination_property'); + $this->assertEquals(FALSE, $bool); + } + + /** + * Tests configuration validation. + * + * @param string[] $configuration + * The configuration for the service plugin. The expected keys are 'service' + * and 'method'. + * @param string $message + * The expected exception message. + * + * @covers ::create + * + * @dataProvider providerConfig + */ + public function testInvalidConfig(array $configuration, $message): void { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage($message); + $this->pluginManager->createInstance('service', $configuration); + } + + /** + * Data provider for testInvalidConfig. + */ + public function providerConfig() { + return [ + 'missing service name' => [ + 'configuration' => [], + 'message' => 'The "service" must be set.', + ], + 'missing method name' => [ + 'configuration' => ['service' => 'email.validator'], + 'message' => 'The "method" must be set.', + ], + 'invalid service name' => [ + 'configuration' => [ + 'service' => 'no shirt no shoes no service', + 'method' => 'isValid', + ], + 'message' => 'You have requested the non-existent service "no shirt no shoes no service".', + ], + 'invalid method name' => [ + 'configuration' => [ + 'service' => 'email.validator', + 'method' => 'noSuchMethod', + ], + 'message' => 'The "email.validator" service has no method "noSuchMethod".', + ], + ]; + } + +}