View source
<?php
namespace Drupal\forena\Controller;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\OpenModalDialogCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Ajax\UpdateBuildIdCommand;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\forena\Form\ReportModalForm;
use Drupal\forena\Forena;
use Drupal\forena\FrxPlugin\AjaxCommand\AjaxCommandInterface;
use Drupal\forena\Context\AppContext;
abstract class AjaxPageControllerBase extends ControllerBase implements AjaxControllerInterface {
const LAYOUT = 'sample/dashboard';
const DEFAULT_ACTION = 'view';
const TOKEN_PARAMETER = 'c';
const TOKEN_PREFIX = 'ajax';
const MAX_STATE_AGE = 43260;
protected $token;
public $layout;
public $parms = [];
public $is_modal_form = FALSE;
public $modal_added = FALSE;
public $section = '';
public $prior_section = '';
public $form_state;
protected $state;
protected static $instance;
public $libraries = [];
protected $context;
protected $build = [];
public $modal_content = [];
public $jsMode;
protected $commands = [];
public $endCommand = NULL;
public $prevent_action = FALSE;
public $action;
public $post_form_id = '';
public static function service() {
if (static::$instance === NULL) {
static::$instance = new static();
}
return static::$instance;
}
public function isAjaxCall() {
return $this->jsMode != 'nojs';
}
public function __construct() {
static::$instance = $this;
if (isset($_GET)) {
$this->parms = $_GET;
if (isset($_REQUEST[static::TOKEN_PARAMETER])) {
$this->token = $_REQUEST[static::TOKEN_PARAMETER];
unset($this->parms[static::TOKEN_PARAMETER]);
}
unset($this->parms['_wrapper_format']);
unset($this->parms['ajax_form']);
}
$this->context = AppContext::create();
$this->layout = static::LAYOUT;
$this->libraries[] = 'forena/forena';
$this
->setReportContext('app', $this->context);
$this
->loadState();
}
public function setReportContext($name, &$value) {
Forena::service()
->setDataContext($name, $value);
}
protected function generateStateToken() {
$this->token = static::TOKEN_PREFIX . '-' . bin2hex(openssl_random_pseudo_bytes(20));
}
public function getStateToken() {
if (!$this->token) {
$this
->generateStateToken();
}
return $this->token;
}
public function getState() {
return $this->state;
}
protected function loadState() {
if (!$this->token) {
$this
->generateStateToken();
}
else {
$svc = \Drupal::keyValueExpirable(static::TOKEN_PREFIX);
$data = $svc
->get($this->token);
if ($data) {
$this->state = unserialize($data);
}
}
}
public function saveState() {
if ($this->state !== NULL) {
$state = serialize($this->state);
$svc = \Drupal::keyValueExpirable(static::TOKEN_PREFIX);
$svc
->setWithExpire($this->token, $state, static::MAX_STATE_AGE);
}
}
public function page($action = '', $js_mode = 'nojs') {
$this->jsMode = $js_mode;
if (!empty($_GET['_wrapper_format'])) {
$this->jsMode = $_GET['_wrapper_format'];
}
if (!$action && $this->jsMode == 'nojs') {
$route_name = \Drupal::routeMatch()
->getRouteName();
return $this
->redirect($route_name, [
'action' => static::DEFAULT_ACTION,
]);
}
else {
$build = $this
->response($action);
return $build;
}
}
public function response($action) {
$this->action = $action;
switch ($this->jsMode) {
case 'nojs':
$this
->initLayout();
$this
->processFormRequest();
if (!$this->prevent_action) {
$this
->route($action);
}
foreach ($this->build as $section => $content) {
if (is_array($content)) {
$content = \Drupal::Service('renderer')
->render($content);
}
$this->context->{$section} = $content;
}
$content = Forena::service()
->report($this->layout);
if (!empty($content['#attached']['library'])) {
$content['#attached']['library'] = array_merge($content['#attached']['library'], $this->libraries);
}
else {
$content['#attached']['library'] = $this->libraries;
}
$response = $content;
break;
case 'drupal_modal':
$this
->processFormRequest();
if (!$this->prevent_action) {
$this
->route($action);
}
$response = $this->build;
break;
default:
$this
->processFormRequest();
if (!$this->prevent_action) {
$this
->route($action);
}
$commands = $this
->getCommands();
$response = new AjaxResponse();
foreach ($commands as $command) {
$response
->addCommand($command);
}
}
$this
->saveState();
return $response;
}
public function processFormRequest() {
if (!empty($_REQUEST['form_id'])) {
$form_id = $_REQUEST['form_id'];
$this
->processForm($form_id);
}
}
public function processForm($form_id) {
switch ($form_id) {
case ReportModalForm::FORM_ID:
$this
->getModalForm('main', ReportModalForm::class, '');
}
}
public function preventAction($prevent_action = TRUE) {
$this->prevent_action = $prevent_action;
}
public function render($section, $content) {
if ($this->jsMode != 'nojs' && $this->jsMode != 'drupal_modal') {
$this->commands[] = new HtmlCommand('#' . $section, $content);
}
else {
$this->build[$section] = $content;
}
}
public function getCommands() {
$commands = $this->commands;
if (!empty($this->endCommand)) {
$commands[] = $this->endCommand;
}
$this->commands = [];
return $commands;
}
public function addCommand($command) {
$this->commands[] = $command;
}
public function clearCommands() {
$this->commands = [];
}
protected function generateAjaxReplace($section, $form) {
$commands = [];
$build = $this->form_state
->getCompleteForm();
if (isset($_POST['form_build_id']) && $_POST['form_build_id'] !== $build['#build_id']) {
$commands[] = new UpdateBuildIdCommand($_POST['form_build_id'], $build['#build_id']);
}
$callback = NULL;
$wrapper = NULL;
$ajax_callback = NULL;
if (($triggering_element = $this->form_state
->getTriggeringElement()) && isset($triggering_element['#ajax']['callback'])) {
$callback = $ajax_callback = $triggering_element['#ajax']['callback'];
$wrapper = $triggering_element['#ajax']['wrapper'];
}
$callback = $this->form_state
->prepareCallback($callback);
if ($callback) {
if (empty($callback) || !is_callable($callback)) {
$commands[] = new HtmlCommand('#' . $section, $form);
}
$result = call_user_func_array($callback, [
&$form,
&$this->form_state,
]);
if (is_array($result)) {
if (!empty($result['#group'])) {
unset($result['#group']);
}
if ($wrapper) {
$commands[] = new ReplaceCommand('#' . $wrapper, $result);
}
else {
$commands[] = new HtmlCommand('#' . $section, $form);
}
}
}
else {
$commands[] = new HtmlCommand('#' . $section, $form);
}
return $commands;
}
protected function getForm($section, $class) {
$modal = $this->is_modal_form;
$this->prior_section = $this->section;
$this->section = $section;
$this->is_modal_form = FALSE;
if (empty($_POST['form_id']) || $class::FORM_ID != $this->post_form_id) {
$content = \Drupal::formBuilder()
->getForm($class);
if ($this->jsMode != 'nojs' && $this->jsMode != 'drupal_modal') {
$this->commands = array_merge($this->commands, $this
->generateAjaxReplace($section, $content));
}
else {
$this->build[$section] = $content;
}
$this->is_modal_form = $modal;
$this->section = $this->prior_section;
}
}
protected function getModalForm($section, $class, $title, $options = []) {
$modal = $this->is_modal_form;
$this->is_modal_form = TRUE;
if (empty($_POST['form_id']) || $class::FORM_ID != $this->post_form_id) {
$content = \Drupal::formBuilder()
->getForm($class);
if ($this->jsMode != 'nojs') {
if (!$this->modal_added) {
$this->commands[] = new OpenModalDialogCommand($title, $content, $options);
$this->modal_added = TRUE;
if (!isset($options['autoResize']) && !empty($options['draggable'])) {
$this->commands[] = new InvokeCommand('#drupal-modal', 'eModalDraggable');
}
}
}
else {
$this->build[$section] = $content;
}
}
$this->is_modal_form = $modal;
}
protected function report($section, $report) {
$forena = \Drupal::service('forena.reports');
$content = $forena
->report($report, $this->parms);
if ($this->jsMode != 'nojs' && $this->jsMode != 'drupal_modal') {
$this->commands[] = new HtmlCommand('#' . $section, $content);
}
else {
$this->build[$section] = $content;
}
}
public function runReport($report) {
$forena = \Drupal::service('forena.reports');
return $forena
->runReport($report, $this->parms);
}
protected function modalReport($section, $report, $title = '', $options = []) {
$forena = \Drupal::service('forena.reports');
if ($this->jsMode == 'nojs') {
$this
->report($section, $report);
}
else {
$this->modal_content = $forena
->report($report, $this->parms);
if (!isset($options['draggable'])) {
$options['draggable'] = TRUE;
}
$this
->getModalForm($section, ReportModalForm::class, $title, $options);
}
}
public function setUrl($action, $title = NULL, $parms = NULL) {
$query = "";
if ($parms === NULL) {
$parms = $this->parms;
}
if ($parms) {
unset($parms['form_id']);
$query = http_build_query($parms);
}
if ($query) {
$action .= "?{$query}";
}
$this->endCommand = new InvokeCommand('html', 'forenaAjaxChangeUrl', [
$action,
$title,
]);
}
public function setEndCommand($command) {
$this->endCommand = $command;
}
public function initLayout() {
$this->build = [];
}
public function __sleep() {
return [];
}
}