diff --git a/core/modules/action/src/ActionFormBase.php b/core/modules/action/src/ActionFormBase.php index 3fafd035ee..f1cffad7c3 100644 --- a/core/modules/action/src/ActionFormBase.php +++ b/core/modules/action/src/ActionFormBase.php @@ -14,18 +14,18 @@ abstract class ActionFormBase extends EntityForm { /** - * The action plugin being configured. + * The action storage. * - * @var \Drupal\Core\Action\ActionInterface + * @var \Drupal\Core\Entity\EntityStorageInterface */ - protected $plugin; + protected $storage; /** - * The action storage. + * The action entity. * - * @var \Drupal\Core\Entity\EntityStorageInterface + * @var \Drupal\system\ActionConfigEntityInterface */ - protected $storage; + protected $entity; /** * Constructs a new action form. @@ -46,14 +46,6 @@ public static function create(ContainerInterface $container) { ); } - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - $this->plugin = $this->entity->getPlugin(); - return parent::buildForm($form, $form_state); - } - /** * {@inheritdoc} */ @@ -85,8 +77,8 @@ public function form(array $form, FormStateInterface $form_state) { '#value' => $this->entity->getType(), ]; - if ($this->plugin instanceof PluginFormInterface) { - $form += $this->plugin->buildConfigurationForm($form, $form_state); + if ($plugin = $this->getPlugin()) { + $form += $plugin->buildConfigurationForm($form, $form_state); } return parent::form($form, $form_state); @@ -96,7 +88,7 @@ public function form(array $form, FormStateInterface $form_state) { * Determines if the action already exists. * * @param string $id - * The action ID + * The action ID. * * @return bool * TRUE if the action exists, FALSE otherwise. @@ -120,9 +112,8 @@ protected function actions(array $form, FormStateInterface $form_state) { */ public function validateForm(array &$form, FormStateInterface $form_state) { parent::validateForm($form, $form_state); - - if ($this->plugin instanceof PluginFormInterface) { - $this->plugin->validateConfigurationForm($form, $form_state); + if ($plugin = $this->getPlugin()) { + $plugin->validateConfigurationForm($form, $form_state); } } @@ -131,9 +122,8 @@ public function validateForm(array &$form, FormStateInterface $form_state) { */ public function submitForm(array &$form, FormStateInterface $form_state) { parent::submitForm($form, $form_state); - - if ($this->plugin instanceof PluginFormInterface) { - $this->plugin->submitConfigurationForm($form, $form_state); + if ($plugin = $this->getPlugin()) { + $plugin->submitConfigurationForm($form, $form_state); } } @@ -147,4 +137,17 @@ public function save(array $form, FormStateInterface $form_state) { $form_state->setRedirect('entity.action.collection'); } + /** + * Gets the action plugin while ensuring it implements configuration forms. + * + * @return \Drupal\Core\Action\ActionInterface|\Drupal\Core\Plugin\PluginFormInterface|null + * The action plugin, or NULL if it does not implement configuration forms. + */ + protected function getPlugin() { + if ($this->entity->getPlugin() instanceof PluginFormInterface) { + return $this->entity->getPlugin(); + } + return NULL; + } + } diff --git a/core/modules/action/tests/action_form_ajax_test/action_form_ajax_test.info.yml b/core/modules/action/tests/action_form_ajax_test/action_form_ajax_test.info.yml new file mode 100644 index 0000000000..020e9ef45d --- /dev/null +++ b/core/modules/action/tests/action_form_ajax_test/action_form_ajax_test.info.yml @@ -0,0 +1,7 @@ +name: action_form_ajax_test +type: module +description: 'module used for testing ajax in action config entity forms.' +package: Core +version: VERSION +core: 8.x +hidden: true diff --git a/core/modules/action/tests/action_form_ajax_test/config/schema/action_form_ajax_test.schema.yml b/core/modules/action/tests/action_form_ajax_test/config/schema/action_form_ajax_test.schema.yml new file mode 100644 index 0000000000..7ebe2e1b6d --- /dev/null +++ b/core/modules/action/tests/action_form_ajax_test/config/schema/action_form_ajax_test.schema.yml @@ -0,0 +1,7 @@ +action.configuration.action_form_ajax_test: + type: action_configuration_default + label: 'action_form_ajax_test action' + mapping: + party_time: + type: string + label: 'The time of the party.' diff --git a/core/modules/action/tests/action_form_ajax_test/src/Plugin/Action/ActionAjaxTest.php b/core/modules/action/tests/action_form_ajax_test/src/Plugin/Action/ActionAjaxTest.php new file mode 100644 index 0000000000..bf8bd5b1f3 --- /dev/null +++ b/core/modules/action/tests/action_form_ajax_test/src/Plugin/Action/ActionAjaxTest.php @@ -0,0 +1,89 @@ + '', + ]; + } + + /** + * {@inheritdoc} + */ + public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { + $result = AccessResult::allowed(); + return $return_as_object ? $result : $result->isAllowed(); + } + + /** + * {@inheritdoc} + */ + public function execute() { + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + $having_a_party = $form_state->getValue('having_a_party', !empty($this->configuration['party_time'])); + $form['having_a_party'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Are we having a party?'), + '#ajax' => [ + 'wrapper' => 'party-container', + 'callback' => [$this, 'partyCallback'], + ], + '#default_value' => $having_a_party, + ]; + $form['container'] = [ + '#type' => 'container', + '#prefix' => '
', + '#suffix' => '
', + ]; + + if ($having_a_party) { + $form['container']['party_time'] = [ + '#type' => 'textfield', + '#title' => $this->t('Party time'), + '#default_value' => $this->configuration['party_time'], + ]; + } + + return $form; + } + + /** + * Callback for party checkbox. + */ + public function partyCallback(array $form, FormStateInterface $form_state) { + return $form['container']; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $this->configuration['party_time'] = $form_state->getValue('party_time'); + } + +} diff --git a/core/modules/action/tests/src/FunctionalJavascript/ActionFormAjaxTest.php b/core/modules/action/tests/src/FunctionalJavascript/ActionFormAjaxTest.php new file mode 100644 index 0000000000..6b9aa75257 --- /dev/null +++ b/core/modules/action/tests/src/FunctionalJavascript/ActionFormAjaxTest.php @@ -0,0 +1,70 @@ +drupalCreateUser(['administer actions']); + $this->drupalLogin($user); + } + + /** + * Tests action plugins with AJAX save their configuration. + */ + public function testActionConfigurationWithAjax() { + $url = Url::fromRoute('action.admin_add', ['action_id' => 'action_form_ajax_test']); + $this->drupalGet($url); + $this->assertSession()->statusCodeEquals(200); + $page = $this->getSession()->getPage(); + + $id = 'test_plugin'; + $page->find('css', '[name="id"]') + ->setValue($id); + + $page->find('css', '[name="having_a_party"]') + ->check(); + $this->assertSession()->waitForElement('css', '[name="party_time"]'); + + $party_time = 'Evening'; + $page->find('css', '[name="party_time"]') + ->setValue($party_time); + + $page->find('css', '[value="Save"]') + ->click(); + + $url = Url::fromRoute('entity.action.collection'); + $this->assertSession()->pageTextContains('The action has been successfully saved.'); + $this->assertSession()->addressEquals($url); + $this->assertSession()->statusCodeEquals(200); + + // Check storage. + $instance = Action::load($id); + $configuration = $instance->getPlugin()->getConfiguration(); + $this->assertEquals(['party_time' => $party_time], $configuration); + + // Configuration should be shown in edit form.: + $this->drupalGet($instance->toUrl('edit-form')); + $this->assertSession()->checkboxChecked('having_a_party'); + $this->assertSession()->fieldValueEquals('party_time', $party_time); + } + +}