diff --git a/src/Plugin/RulesAction/EntitySave.php b/src/Plugin/RulesAction/EntitySave.php
index 3479a57f..e1bb0075 100644
--- a/src/Plugin/RulesAction/EntitySave.php
+++ b/src/Plugin/RulesAction/EntitySave.php
@@ -3,32 +3,36 @@
namespace Drupal\rules\Plugin\RulesAction;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\rules\Core\RulesActionBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Entity\EntityStorageInterface;
/**
* Provides a 'Save entity' action.
*
* @RulesAction(
* id = "rules_entity_save",
- * label = @Translation("Save entity"),
- * category = @Translation("Entity"),
- * context = {
- * "entity" = @ContextDefinition("entity",
- * label = @Translation("Entity"),
- * description = @Translation("Specifies the entity, which should be saved permanently.")
- * ),
- * "immediate" = @ContextDefinition("boolean",
- * label = @Translation("Force saving immediately"),
- * description = @Translation("Usually saving is postponed till the end of the evaluation, so that multiple saves can be fold into one. If this set, saving is forced to happen immediately."),
- * default_value = FALSE,
- * required = FALSE
- * )
- * }
+ * deriver = "Drupal\rules\Plugin\RulesAction\EntitySaveDeriver",
* )
*
* @todo: Add access callback information from Drupal 7.
*/
-class EntitySave extends RulesActionBase {
+class EntitySave extends RulesActionBase implements ContainerFactoryPluginInterface {
+
+ /**
+ * The entity storage service.
+ *
+ * @var \Drupal\Core\Entity\EntityStorageInterface
+ */
+ protected $storage;
+
+ /**
+ * The entity type id.
+ *
+ * @var string
+ */
+ protected $entityTypeId;
/**
* Flag that indicates if the entity should be auto-saved later.
@@ -37,6 +41,36 @@ class EntitySave extends RulesActionBase {
*/
protected $saveLater = TRUE;
+ /**
+ * Constructs an EntitySave object.
+ *
+ * @param array $configuration
+ * A configuration array containing information about the plugin instance.
+ * @param string $plugin_id
+ * The plugin ID for the plugin instance.
+ * @param mixed $plugin_definition
+ * The plugin implementation definition.
+ * @param \Drupal\Core\Entity\EntityStorageInterface $storage
+ * The entity storage service.
+ */
+ public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $storage) {
+ parent::__construct($configuration, $plugin_id, $plugin_definition);
+ $this->storage = $storage;
+ $this->entityTypeId = $plugin_definition['entity_type_id'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ return new static(
+ $configuration,
+ $plugin_id,
+ $plugin_definition,
+ $container->get('entity_type.manager')->getStorage($plugin_definition['entity_type_id'])
+ );
+ }
+
/**
* Saves the Entity.
*
diff --git a/src/Plugin/RulesAction/EntitySaveDeriver.php b/src/Plugin/RulesAction/EntitySaveDeriver.php
new file mode 100644
index 00000000..668dafef
--- /dev/null
+++ b/src/Plugin/RulesAction/EntitySaveDeriver.php
@@ -0,0 +1,95 @@
+entityTypeManager = $entity_type_manager;
+ $this->entityFieldManager = $entity_field_manager;
+ $this->stringTranslation = $string_translation;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, $base_plugin_id) {
+ return new static(
+ $container->get('entity_type.manager'),
+ $container->get('entity_field.manager'),
+ $container->get('string_translation')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getDerivativeDefinitions($base_plugin_definition) {
+ foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
+ // Only allow content entities and ignore configuration entities.
+ if (!$entity_type instanceof ContentEntityTypeInterface) {
+ continue;
+ }
+
+ $this->derivatives[$entity_type_id] = [
+ 'label' => $this->t('Save @entity_type', ['@entity_type' => $entity_type->getLowercaseLabel()]),
+ 'category' => $entity_type->getLabel(),
+ 'entity_type_id' => $entity_type_id,
+ 'context' => [
+ 'entity' => ContextDefinition::create("entity:$entity_type_id")
+ ->setLabel($entity_type->getLabel())
+ ->setDescription($this->t('Specifies the @entity_type_label that should be saved permanently.', ['@entity_type_label' => $entity_type->getLabel()]))
+ ->setRequired(TRUE),
+ 'immediate' => ContextDefinition::create('boolean')
+ ->setLabel($this->t('Force saving immediately'))
+ ->setDescription($this->t('Usually saving is postponed till the end of the evaluation, so that multiple saves can be fold into one. If this set, saving is forced to happen immediately.'))
+ ->setDefaultValue(FALSE)
+ ->setRequired(FALSE),
+ ],
+ ] + $base_plugin_definition;
+ }
+
+ return $this->derivatives;
+ }
+
+}
diff --git a/tests/src/Integration/Action/EntityCreateTest.php b/tests/src/Integration/Action/EntityCreateTest.php
index ee65d6e5..0e331271 100644
--- a/tests/src/Integration/Action/EntityCreateTest.php
+++ b/tests/src/Integration/Action/EntityCreateTest.php
@@ -55,31 +55,31 @@ public function setUp() {
$bundle_field_definition->getItemDefinition()
->willReturn($item_definition->reveal());
$bundle_field_definition->getCardinality()->willReturn(1)
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition->getType()->willReturn('string');
$bundle_field_definition->getLabel()->willReturn('Bundle')
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition->getDescription()
->willReturn('Bundle mock description')
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition_required->getItemDefinition()
->willReturn($item_definition->reveal());
$bundle_field_definition_required->getCardinality()->willReturn(1)
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition_required->getType()->willReturn('string');
$bundle_field_definition_required->getLabel()->willReturn('Required field')
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition_required->getDescription()
->willReturn('Required field mock description')
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition_required->isRequired()
->willReturn(TRUE)
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
$bundle_field_definition_optional->isRequired()
->willReturn(FALSE)
- ->shouldBeCalledTimes(1);
+ ->shouldBeCalled();
// Prepare mocked entity storage.
$entity_type_storage = $this->prophesize(EntityStorageBase::class);
diff --git a/tests/src/Integration/Action/EntitySaveTest.php b/tests/src/Integration/Action/EntitySaveTest.php
index 50b56178..3e24464b 100644
--- a/tests/src/Integration/Action/EntitySaveTest.php
+++ b/tests/src/Integration/Action/EntitySaveTest.php
@@ -3,6 +3,7 @@
namespace Drupal\Tests\rules\Integration\Action;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageBase;
use Drupal\Tests\rules\Integration\RulesEntityIntegrationTestBase;
/**
@@ -33,7 +34,15 @@ public function setUp() {
$this->entity = $this->prophesizeEntity(EntityInterface::class);
- $this->action = $this->actionManager->createInstance('rules_entity_save');
+ // Prepare mocked entity storage.
+ $entity_type_storage = $this->prophesize(EntityStorageBase::class);
+
+ // Return the mocked storage controller.
+ $this->entityTypeManager->getStorage('test')
+ ->willReturn($entity_type_storage->reveal());
+
+ // Instantiate the action we are testing.
+ $this->action = $this->actionManager->createInstance('rules_entity_save:test');
}
/**
@@ -42,7 +51,21 @@ public function setUp() {
* @covers ::summary
*/
public function testSummary() {
- $this->assertEquals('Save entity', $this->action->summary());
+ $this->assertEquals('Save test', $this->action->summary());
+ }
+
+ /**
+ * Tests the action execution.
+ *
+ * @covers ::execute
+ */
+ public function testActionExecution() {
+ $this->entity->save()->shouldBeCalledTimes(1);
+
+ $this->action->setContextValue('entity', $this->entity->reveal())
+ ->setContextValue('immediate', TRUE);
+
+ $this->action->execute();
}
/**
diff --git a/tests/src/Integration/Action/RulesComponentActionTest.php b/tests/src/Integration/Action/RulesComponentActionTest.php
index 1179f607..a0ae6210 100644
--- a/tests/src/Integration/Action/RulesComponentActionTest.php
+++ b/tests/src/Integration/Action/RulesComponentActionTest.php
@@ -4,6 +4,7 @@
use Drupal\Core\Config\Entity\ConfigEntityStorageInterface;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageBase;
use Drupal\rules\Context\ContextConfig;
use Drupal\rules\Context\ContextDefinition;
use Drupal\rules\Engine\RulesComponent;
@@ -17,6 +18,19 @@
*/
class RulesComponentActionTest extends RulesEntityIntegrationTestBase {
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ // Prepare mocked entity storage.
+ $entity_type_storage = $this->prophesize(EntityStorageBase::class);
+
+ // Return the mocked storage controller.
+ $this->entityTypeManager->getStorage('test')
+ ->willReturn($entity_type_storage->reveal());
+ }
+
/**
* Tests that a rule can be used as action.
*/
@@ -42,7 +56,7 @@ public function testActionAvailable() {
public function testExecute() {
// Set up a rules component that will just save an entity.
$nested_rule = $this->rulesExpressionManager->createRule();
- $nested_rule->addAction('rules_entity_save', ContextConfig::create()
+ $nested_rule->addAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'entity')
);
@@ -51,7 +65,7 @@ public function testExecute() {
'label' => 'Test rule',
], 'rules_component');
$rules_config->setExpression($nested_rule);
- $rules_config->setContextDefinitions(['entity' => ContextDefinition::create('entity')]);
+ $rules_config->setContextDefinitions(['entity' => ContextDefinition::create('entity:test')]);
$this->prophesizeStorage([$rules_config]);
@@ -66,7 +80,7 @@ public function testExecute() {
$entity->save()->shouldBeCalledTimes(1);
RulesComponent::create($rule)
- ->addContextDefinition('entity', ContextDefinition::create('entity'))
+ ->addContextDefinition('entity', ContextDefinition::create('entity:test'))
->setContextValue('entity', $entity->reveal())
->execute();
}
@@ -139,7 +153,7 @@ public function testAutosaveOnlyOnce() {
$entity = $this->prophesizeEntity(EntityInterface::class);
$nested_rule = $this->rulesExpressionManager->createRule();
- $nested_rule->addAction('rules_entity_save', ContextConfig::create()
+ $nested_rule->addAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'entity')
);
@@ -148,7 +162,7 @@ public function testAutosaveOnlyOnce() {
'label' => 'Test rule',
], 'rules_component');
$rules_config->setExpression($nested_rule);
- $rules_config->setContextDefinitions(['entity' => ContextDefinition::create('entity')]);
+ $rules_config->setContextDefinitions(['entity' => ContextDefinition::create('entity:test')]);
$this->prophesizeStorage([$rules_config]);
@@ -158,7 +172,7 @@ public function testAutosaveOnlyOnce() {
$rule->addAction('rules_component:test_rule', ContextConfig::create()
->map('entity', 'entity')
);
- $rule->addAction('rules_entity_save', ContextConfig::create()
+ $rule->addAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'entity')
);
@@ -166,7 +180,7 @@ public function testAutosaveOnlyOnce() {
$entity->save()->shouldBeCalledTimes(1);
RulesComponent::create($rule)
- ->addContextDefinition('entity', ContextDefinition::create('entity'))
+ ->addContextDefinition('entity', ContextDefinition::create('entity:test'))
->setContextValue('entity', $entity->reveal())
->execute();
}
diff --git a/tests/src/Integration/Engine/AutoSaveTest.php b/tests/src/Integration/Engine/AutoSaveTest.php
index a923d94b..a2af62d3 100644
--- a/tests/src/Integration/Engine/AutoSaveTest.php
+++ b/tests/src/Integration/Engine/AutoSaveTest.php
@@ -3,6 +3,7 @@
namespace Drupal\Tests\rules\Integration\Engine;
use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityStorageBase;
use Drupal\rules\Context\ContextConfig;
use Drupal\rules\Context\ContextDefinition;
use Drupal\rules\Engine\RulesComponent;
@@ -15,13 +16,26 @@
*/
class AutoSaveTest extends RulesEntityIntegrationTestBase {
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ // Prepare mocked entity storage.
+ $entity_type_storage = $this->prophesize(EntityStorageBase::class);
+
+ // Return the mocked storage controller.
+ $this->entityTypeManager->getStorage('test')
+ ->willReturn($entity_type_storage->reveal());
+ }
+
/**
* Tests auto saving after an action execution.
*/
public function testActionAutoSave() {
$rule = $this->rulesExpressionManager->createRule();
// Just leverage the entity save action, which by default uses auto-saving.
- $rule->addAction('rules_entity_save', ContextConfig::create()
+ $rule->addAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'entity')
);
@@ -29,7 +43,7 @@ public function testActionAutoSave() {
$entity->save()->shouldBeCalledTimes(1);
RulesComponent::create($rule)
- ->addContextDefinition('entity', ContextDefinition::create('entity'))
+ ->addContextDefinition('entity', ContextDefinition::create('entity:test'))
->setContextValue('entity', $entity->reveal())
->execute();
}
diff --git a/tests/src/Integration/Engine/IntegrityCheckTest.php b/tests/src/Integration/Engine/IntegrityCheckTest.php
index c16f2455..a609a6fc 100644
--- a/tests/src/Integration/Engine/IntegrityCheckTest.php
+++ b/tests/src/Integration/Engine/IntegrityCheckTest.php
@@ -3,6 +3,7 @@
namespace Drupal\Tests\rules\Integration\Engine;
use Drupal\rules\Context\ContextConfig;
+use Drupal\Core\Entity\EntityStorageBase;
use Drupal\rules\Context\ContextDefinition;
use Drupal\rules\Engine\RulesComponent;
use Drupal\Tests\rules\Integration\RulesEntityIntegrationTestBase;
@@ -14,17 +15,30 @@
*/
class IntegrityCheckTest extends RulesEntityIntegrationTestBase {
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ // Prepare mocked entity storage.
+ $entity_type_storage = $this->prophesize(EntityStorageBase::class);
+
+ // Return the mocked storage controller.
+ $this->entityTypeManager->getStorage('test')
+ ->willReturn($entity_type_storage->reveal());
+ }
+
/**
* Tests that the integrity check can be invoked.
*/
public function testIntegrityCheck() {
$rule = $this->rulesExpressionManager->createRule();
- $rule->addAction('rules_entity_save', ContextConfig::create()
+ $rule->addAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'entity')
);
$violation_list = RulesComponent::create($rule)
- ->addContextDefinition('entity', ContextDefinition::create('entity'))
+ ->addContextDefinition('entity', ContextDefinition::create('entity:test'))
->checkIntegrity();
$this->assertEquals(0, iterator_count($violation_list));
}
@@ -34,7 +48,7 @@ public function testIntegrityCheck() {
*/
public function testUnknownVariable() {
$rule = $this->rulesExpressionManager->createRule();
- $action = $this->rulesExpressionManager->createAction('rules_entity_save', ContextConfig::create()
+ $action = $this->rulesExpressionManager->createAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'unknown_variable')
->toArray()
);
@@ -45,7 +59,7 @@ public function testUnknownVariable() {
$this->assertEquals(1, iterator_count($violation_list));
$violation = $violation_list[0];
$this->assertEquals(
- 'Data selector unknown_variable for context Entity is invalid. Unable to get variable unknown_variable, it is not defined.',
+ 'Data selector unknown_variable for context Test is invalid. Unable to get variable unknown_variable, it is not defined.',
(string) $violation->getMessage()
);
$this->assertEquals($action->getUuid(), $violation->getUuid());
@@ -59,14 +73,14 @@ public function testCheckUuid() {
// Just use a rule with 2 dummy actions.
$rule->addAction('rules_entity_save', ContextConfig::create()
->map('entity', 'unknown_variable_1'));
- $second_action = $this->rulesExpressionManager->createAction('rules_entity_save', ContextConfig::create()
+ $second_action = $this->rulesExpressionManager->createAction('rules_entity_save:test', ContextConfig::create()
->map('entity', 'unknown_variable_2')
->toArray()
);
$rule->addExpressionObject($second_action);
$all_violations = RulesComponent::create($rule)
- ->addContextDefinition('entity', ContextDefinition::create('entity'))
+ ->addContextDefinition('entity', ContextDefinition::create('entity:test'))
->checkIntegrity();
$this->assertEquals(2, iterator_count($all_violations));
@@ -75,7 +89,7 @@ public function testCheckUuid() {
$this->assertEquals(1, count($uuid_violations));
$violation = $uuid_violations[0];
$this->assertEquals(
- 'Data selector unknown_variable_2 for context Entity is invalid. Unable to get variable unknown_variable_2, it is not defined.',
+ 'Data selector unknown_variable_2 for context Test is invalid. Unable to get variable unknown_variable_2, it is not defined.',
(string) $violation->getMessage()
);
$this->assertEquals($second_action->getUuid(), $violation->getUuid());