forena-8.x-1.x-dev/src/Form/AjaxFormBase.php
src/Form/AjaxFormBase.php
<?php namespace Drupal\forena\Form; use Drupal\Core\Ajax\AjaxResponse; use Drupal\Core\Ajax\CloseDialogCommand; use Drupal\Core\Ajax\HtmlCommand; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\forena\Controller\AjaxPageControllerBase; /** * Class AjaxFormTrait * * Use this trait to add ajax submit handler behaviors that complement an * AjaxControllerInterface class. */ abstract class AjaxFormBase extends FormBase { const FORM_ID = '__ABSTRACT__'; /** * @var AjaxPageControllerBase * The Ajax cotnroller bound to this form. */ protected $controller; /** * Set controller based on sinbleton. * AjaxFormBase constructor. */ public function __construct() { $this->controller = AjaxPageControllerBase::service(); } /** * @throws \Exception * Thrown when a programmer does not implement a FORM_ID constant. */ public function getFormId() { if (static::FORM_ID == AjaxFormBase::FORM_ID) { $class = get_class($this); throw new \Exception("FORM_ID class constant not implemented in $class"); } return static::FORM_ID; } /** * Return the controller that is bound to the form. * * @param \Drupal\Core\Form\FormStateInterface $form_state * @return \Drupal\forena\Controller\AjaxPageControllerBase|mixed */ public function getController() { return $this->controller; } /** * Ajax callback handler for submit buttons. * * @param array $form * Form array * @param \Drupal\Core\Form\FormStateInterface $form_state * Drupal form state object. * @return \Drupal\Core\Ajax\AjaxResponse * The ajax response object used to update the page. */ public function submitCallback(&$form, FormStateInterface $form_state) { if ($this->controller->is_modal_form) { return $this->ajaxModalCallback($form, $form_state); } else { return $this->ajaxCallback($form, $form_state); } } /** * Ajax callback. * @param AjaxPageControllerBase $controller * The controller to register with the interface * @param array $form * Drupal form render array * @param $form_state * Drupral form state object. * @return \Drupal\Core\Ajax\AjaxResponse */ public function ajaxCallback($form, FormStateInterface $form_state) { $response = new AjaxResponse(); // Make sure form error rebuilds happen. if ($form_state->getErrors() || $form_state->isRebuilding()) { $ctl['status_messages'] = [ '#type' => 'status_messages', '#weight' => -10, ]; // Array merge the status element onto the beginning of the form. $form = array_merge($ctl, $form); $section = $form_state->get('e_section'); $command = new HtmlCommand("#$section", $form); $response->addCommand($command); $this->controller->section = $this->controller->prior_section; } else { $this->controller->section = $this->controller->prior_section; if (!$this->controller->prevent_action) { $this->controller->post_form_id = $form_state->getFormObject()->getFormId(); $this->controller->route($this->controller->action); } } $commands = $this->controller->getCommands(); foreach ($commands as $command) { $response->addCommand($command); } $this->controller->saveState(); return $response; } /** * Ajax callback. * @param $form * @param $form_state * @return \Drupal\Core\Ajax\AjaxResponse */ public function ajaxModalCallback(&$form, FormStateInterface $form_state) { if ($form_state->getErrors() || $form_state->isRebuilding()) { unset($form['#prefix']); unset($form['#suffix']); // array merge the status elements onto the beginning of the form $ctl['status_messages'] = [ '#type' => 'status_messages', '#weight' => -10, ]; $form = array_merge($ctl, $form); $this->controller->setEndCommand(new HtmlCommand('#e-modal-form', $form)); } else { // Process route when requested. $this->controller->section = $this->controller->prior_section; if (!$this->controller->prevent_action) { $this->controller->post_form_id = $form_state->getFormObject()->getFormId(); $this->controller->route($this->controller->action); } if (!$this->controller->modal_added) { $this->controller->addCommand( new CloseDialogCommand()); } } $commands = $this->controller->getCommands(); $response = new AjaxResponse(); foreach ($commands as $command) { $response->addCommand($command); } $this->controller->saveState(); return $response; } /** * @param \Drupal\forena\Controller\AjaxPageControllerBase $controller * @param $form * @param \Drupal\Core\Form\FormStateInterface $form_state */ public function bindAjaxForm(AjaxPageControllerBase $controller, &$form, FormStateInterface $form_state) { if ($controller->is_modal_form && $controller->jsMode!='nojs') { $form_state->set('e_modal', TRUE); $form['#prefix'] = "<div id='e-modal-form'>"; $form['#suffix'] = "</div>"; } else { $form_state->set('e_section', $controller->section); } $form[$controller::TOKEN_PARAMETER] = [ '#type' => 'hidden', '#value' => $controller->getStateToken(), ]; // Disable caching on this form. $form_state->setCached(FALSE); // Set the form state handler. $controller->form_state = $form_state; // Alter the submit handlers. $this->controller = $controller; $method = "::submitCallback"; $callback = $method; $this->alterForm($form, $callback); } /** * @param array $elements * Drupal form render array section. * @param string $callback * Callback to apply to the form submit buttons. */ private function alterForm(&$elements, $callback) { foreach ($elements as $key => $element) { if (strpos($key, '#')!==0 && is_array($element)) { if (!empty($element['#type'])){ switch ($element['#type']) { case 'submit': if (!isset($element['#ajax'])) { $elements[$key]['#mode'] = $callback; $elements[$key]['#ajax'] = [ 'callback' => $callback, 'event' => 'click', ]; } break; } } $this->alterForm($elements[$key], $callback); } } } /** * Create a report controll. * @param $report * @param null $parms */ public function report($report, $parms = NULL) { if ($parms === NULL) { $parms = $this->getController()->parms; } return Forena::service()->report($report, $parms); } public function __wakeup() { $this->controller = AjaxPageControllerBase::service(); } }