abstract class AjaxPageControllerBase in Forena Reports 8
Hierarchy
- class \Drupal\Core\Controller\ControllerBase implements ContainerInjectionInterface uses LoggerChannelTrait, MessengerTrait, LinkGeneratorTrait, RedirectDestinationTrait, UrlGeneratorTrait, StringTranslationTrait
- class \Drupal\forena\Controller\AjaxPageControllerBase implements AjaxControllerInterface
Expanded class hierarchy of AjaxPageControllerBase
3 files declare their use of AjaxPageControllerBase
- AjaxFormBase.php in src/
Form/ AjaxFormBase.php - AjaxFormTrait.php in src/
Form/ AjaxFormTrait.php - ReportModalForm.php in src/
Form/ ReportModalForm.php
File
- src/
Controller/ AjaxPageControllerBase.php, line 25
Namespace
Drupal\forena\ControllerView source
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;
/**
* @var string
* Controller token for keeping track of state information between page
* loads of the controller.
*/
protected $token;
/**
* @var string Name of forena report used for layout
*/
public $layout;
/**
* @var array
* Current parameters for the report.
*/
public $parms = [];
/**
* @var bool
* Indicates whether the current form being processed is a modal.
*/
public $is_modal_form = FALSE;
/**
* @var bool
* Inidates whether a modal has already been added
*/
public $modal_added = FALSE;
/**
* @var string
*/
public $section = '';
public $prior_section = '';
/** @var FormStateInterface */
public $form_state;
/** @var object */
protected $state;
/**
* @var AjaxPageControllerBase
* Singleton instance.
*/
protected static $instance;
/**
* @var array
* Array of librarries to load with this controller.
*/
public $libraries = [];
/**
* Application context to load.
* @var static
*/
protected $context;
/**
* @var array
* Drupal render array containing content.
*/
protected $build = [];
/**
* Render array of modal content.
* @var array
*/
public $modal_content = [];
/**
* The JSMode passed to the the controller to determine how to deliver the
* page. "ajax" implies an ajax page load "nojs" implies a normal page.
* @var string
*/
public $jsMode;
/**
* Ajax commands that are to be returned by the object.
* @var AjaxCommandInterface[]
*/
protected $commands = [];
/**
* The final command that updates the page. Note this is generally either
* a setURL ajax command or it is a CloseDialog command.
* @var
*/
public $endCommand = NULL;
/**
* @var bool Prevent the further processing of default action pages
*/
public $prevent_action = FALSE;
public $action;
public $post_form_id = '';
/**
* Singleton factory method.
* @return static
*/
public static function service() {
if (static::$instance === NULL) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Indicates whether the current callback is an ajax call.
* @return bool
*/
public function isAjaxCall() {
return $this->jsMode != 'nojs';
}
/**
* AjaxPageControllerBase constructor.
*/
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';
// Set the context for the forena applcation.
$this
->setReportContext('app', $this->context);
// Load the state if it hasn't been loaded.
$this
->loadState();
}
/**
* Sets the report context for a report.
* @param $name
* @param $value
*/
public function setReportContext($name, &$value) {
Forena::service()
->setDataContext($name, $value);
}
/**
* Generate a token for form
*/
protected function generateStateToken() {
$this->token = static::TOKEN_PREFIX . '-' . bin2hex(openssl_random_pseudo_bytes(20));
}
/**
* Return the state token.
* @return string
*/
public function getStateToken() {
if (!$this->token) {
$this
->generateStateToken();
}
return $this->token;
}
/**
* @return Object|NULL
*/
public function getState() {
return $this->state;
}
/**
* Loads the state from the token.
*/
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);
}
}
}
/**
* Save the state of the controller
*/
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);
}
}
/**
* Default page controller implementation.
* This method is typically what you would reference in the routing.yml
* file as the main menu callback for the controller.
*
* @param $action
* @param string $js_mode
* @return array|\Symfony\Component\HttpFoundation\RedirectResponse
*/
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;
}
}
/**
* Return the response based on ajax pramters.
* @param string $action
* The action used by the reout to generate a reponse.
* @return array | null
* Drupal render array containing action.
*/
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);
// Add the ajax librarries used by teh controller.
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 is the type sent when you use the "data-dialog-type" class.
// Note that it is not the common way to display a modal.
$this
->processFormRequest();
if (!$this->prevent_action) {
$this
->route($action);
}
$response = $this->build;
break;
default:
// All other types are assumed to be some ajax variant.
$this
->processFormRequest();
if (!$this->prevent_action) {
$this
->route($action);
}
$commands = $this
->getCommands();
//print ajax_render($commands);
$response = new AjaxResponse();
foreach ($commands as $command) {
$response
->addCommand($command);
}
}
$this
->saveState();
return $response;
}
/**
* Process the post requests for an action.
*/
public function processFormRequest() {
if (!empty($_REQUEST['form_id'])) {
$form_id = $_REQUEST['form_id'];
$this
->processForm($form_id);
}
}
/**
* Processes the form based on a form_id
* @param string $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;
}
/**
* @param string $section
* The location where the content should go.
* @param string|array $content
* The content to replace.
*/
public function render($section, $content) {
if ($this->jsMode != 'nojs' && $this->jsMode != 'drupal_modal') {
$this->commands[] = new HtmlCommand('#' . $section, $content);
}
else {
$this->build[$section] = $content;
}
}
/**
* Get the AJAX commands to return to the blroser.
* @return array
* Array of commands to return.
*/
public function getCommands() {
$commands = $this->commands;
if (!empty($this->endCommand)) {
$commands[] = $this->endCommand;
}
$this->commands = [];
return $commands;
}
/**
* \Add an ajax controller command to the stack.
* @param $command
*/
public function addCommand($command) {
$this->commands[] = $command;
}
/**
* Clear the commnds from the ajax buffer.
*/
public function clearCommands() {
$this->commands = [];
}
/**
* Generate the ajax form replacement commands.
* @param $section
* @param $form
* @return array
*/
protected function generateAjaxReplace($section, $form) {
$commands = [];
// If the form build ID has changed, issue an Ajax command to update it.
$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']);
}
// We need to return the part of the form (or some other content) that needs
// to be re-rendered so the browser can update the page with changed
// content. It is up to the #ajax['callback'] function of the element (may
// or may not be a button) that triggered the Ajax request to determine what
// needs to be rendered.
$callback = NULL;
$wrapper = NULL;
$ajax_callback = NULL;
// If we have an ajax callback assume we're doing a drupal style ajax replacment
if (($triggering_element = $this->form_state
->getTriggeringElement()) && isset($triggering_element['#ajax']['callback'])) {
$callback = $ajax_callback = $triggering_element['#ajax']['callback'];
$wrapper = $triggering_element['#ajax']['wrapper'];
}
// Determine if there is a callback.
$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,
]);
// At this point we know callback returned a render element. If the
// element is part of the group (#group is set on it) it won't be rendered
// unless we remove #group from it. This is caused by
// \Drupal\Core\Render\Element\RenderElement::preRenderGroup(), which
// prevents all members of groups from being rendered directly.
if (is_array($result)) {
if (!empty($result['#group'])) {
unset($result['#group']);
}
if ($wrapper) {
$commands[] = new ReplaceCommand('#' . $wrapper, $result);
}
else {
// we don't have a wrapper so assume form section replacement
$commands[] = new HtmlCommand('#' . $section, $form);
}
}
}
else {
// No ajax callback implies we are doing a normal full form replacment.
$commands[] = new HtmlCommand('#' . $section, $form);
}
return $commands;
}
/**
* Retrieve a drupal form for inclusion in the app.
* Will load based on controlllerr's jsMode property as either
* an ajax command or as an inline form.
*
* @param string $section
* The section of the template in which to render the form.
* @param string $class
* The class name of the form to render.
*/
protected function getForm($section, $class) {
$modal = $this->is_modal_form;
$this->prior_section = $this->section;
$this->section = $section;
$this->is_modal_form = FALSE;
// We need to skip the second redering of this form in a route because
// it may lead to an ajax error. It should already have been rendered
// in the form processing phase.
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;
}
}
/**
* @param string $section
* The class name of the form to render.
* @param string $class
* The class name of the form to get.
* @param string $title
* The title to be used on the modal.
* @param array $options
* Array of Jquery UI Dialog options as described at
* http://api.jqueryui.com/dialog
*
*/
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 autoResize is not manually disabled draggable will always be disabled
// by drupal javascript. So we add a command to enable it manually after
// the form is initially sized.
if (!isset($options['autoResize']) && !empty($options['draggable'])) {
$this->commands[] = new InvokeCommand('#drupal-modal', 'eModalDraggable');
}
}
}
else {
$this->build[$section] = $content;
}
}
$this->is_modal_form = $modal;
}
/**
* Render a forena report.
* @param string $section
* The id of the section where the report goes.
* @param string $report
* The name of the report to render.
*/
protected function report($section, $report) {
/** @var Forena $forena */
$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) {
/** @var Forena $forena */
$forena = \Drupal::service('forena.reports');
return $forena
->runReport($report, $this->parms);
}
/**
* Render a forena report in a modal
* @param string $section
* The id of the section where the report goes.
* @param string $title
* Title of modal window
* @param string $report
* The name of the report to render.
* @param array $options
* Modal dialog options.
*/
protected function modalReport($section, $report, $title = '', $options = []) {
/** @var Forena $forena */
$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);
}
}
/**
* Set the url for the controller, including current parameters.
* @param string $action
* The relative action to set
* @param string $title
* The browser title.
* @param array|NULL $parms
* Parmaters. If null speicificied then use the parms properties
* of the cotnroller.
*/
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,
]);
}
/**
* Set the final command to be run as part of the ajax replacment.
*
* @param object $command
* AjaxCommand object. There doesn't appear to be a base ajax command type
* for drupal.
*/
public function setEndCommand($command) {
$this->endCommand = $command;
}
/**
* Initialize the layout report.
*/
public function initLayout() {
$this->build = [];
}
public function __sleep() {
return [];
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AjaxControllerInterface:: |
public | function | Route the requested action for the controller | |
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
protected | property | Drupal render array containing content. | |
AjaxPageControllerBase:: |
protected | property | Ajax commands that are to be returned by the object. | |
AjaxPageControllerBase:: |
protected | property | Application context to load. | |
AjaxPageControllerBase:: |
public | property | The final command that updates the page. Note this is generally either a setURL ajax command or it is a CloseDialog command. @var | |
AjaxPageControllerBase:: |
public | property | @var FormStateInterface | |
AjaxPageControllerBase:: |
protected static | property | Singleton instance. | |
AjaxPageControllerBase:: |
public | property | Indicates whether the current form being processed is a modal. | |
AjaxPageControllerBase:: |
public | property | The JSMode passed to the the controller to determine how to deliver the page. "ajax" implies an ajax page load "nojs" implies a normal page. | |
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
public | property | Array of librarries to load with this controller. | |
AjaxPageControllerBase:: |
public | property | Inidates whether a modal has already been added | |
AjaxPageControllerBase:: |
public | property | Render array of modal content. | |
AjaxPageControllerBase:: |
public | property | Current parameters for the report. | |
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
public | property | ||
AjaxPageControllerBase:: |
protected | property | @var object | |
AjaxPageControllerBase:: |
protected | property | Controller token for keeping track of state information between page loads of the controller. | |
AjaxPageControllerBase:: |
public | function | \Add an ajax controller command to the stack. | |
AjaxPageControllerBase:: |
public | function | Clear the commnds from the ajax buffer. | |
AjaxPageControllerBase:: |
constant | |||
AjaxPageControllerBase:: |
protected | function | Generate the ajax form replacement commands. | |
AjaxPageControllerBase:: |
protected | function | Generate a token for form | |
AjaxPageControllerBase:: |
public | function | Get the AJAX commands to return to the blroser. | |
AjaxPageControllerBase:: |
protected | function | Retrieve a drupal form for inclusion in the app. Will load based on controlllerr's jsMode property as either an ajax command or as an inline form. | |
AjaxPageControllerBase:: |
protected | function | ||
AjaxPageControllerBase:: |
public | function | ||
AjaxPageControllerBase:: |
public | function | Return the state token. | |
AjaxPageControllerBase:: |
public | function |
Initialize the layout report. Overrides AjaxControllerInterface:: |
|
AjaxPageControllerBase:: |
public | function | Indicates whether the current callback is an ajax call. | |
AjaxPageControllerBase:: |
constant | |||
AjaxPageControllerBase:: |
protected | function | Loads the state from the token. | |
AjaxPageControllerBase:: |
constant | |||
AjaxPageControllerBase:: |
protected | function | Render a forena report in a modal | |
AjaxPageControllerBase:: |
public | function |
Default page controller implementation.
This method is typically what you would reference in the routing.yml
file as the main menu callback for the controller. Overrides AjaxControllerInterface:: |
|
AjaxPageControllerBase:: |
public | function | ||
AjaxPageControllerBase:: |
public | function | Processes the form based on a form_id | |
AjaxPageControllerBase:: |
public | function | Process the post requests for an action. | |
AjaxPageControllerBase:: |
public | function | ||
AjaxPageControllerBase:: |
protected | function | Render a forena report. | |
AjaxPageControllerBase:: |
public | function |
Return the response based on ajax pramters. Overrides AjaxControllerInterface:: |
|
AjaxPageControllerBase:: |
public | function | ||
AjaxPageControllerBase:: |
public | function | Save the state of the controller | |
AjaxPageControllerBase:: |
public static | function | Singleton factory method. | |
AjaxPageControllerBase:: |
public | function | Set the final command to be run as part of the ajax replacment. | |
AjaxPageControllerBase:: |
public | function | Sets the report context for a report. | |
AjaxPageControllerBase:: |
public | function | Set the url for the controller, including current parameters. | |
AjaxPageControllerBase:: |
constant | |||
AjaxPageControllerBase:: |
constant | |||
AjaxPageControllerBase:: |
public | function | AjaxPageControllerBase constructor. | |
AjaxPageControllerBase:: |
public | function | ||
ControllerBase:: |
protected | property | The configuration factory. | |
ControllerBase:: |
protected | property | The current user service. | 1 |
ControllerBase:: |
protected | property | The entity form builder. | |
ControllerBase:: |
protected | property | The entity manager. | |
ControllerBase:: |
protected | property | The entity type manager. | |
ControllerBase:: |
protected | property | The form builder. | 2 |
ControllerBase:: |
protected | property | The key-value storage. | 1 |
ControllerBase:: |
protected | property | The language manager. | 1 |
ControllerBase:: |
protected | property | The module handler. | 2 |
ControllerBase:: |
protected | property | The state service. | |
ControllerBase:: |
protected | function | Returns the requested cache bin. | |
ControllerBase:: |
protected | function | Retrieves a configuration object. | |
ControllerBase:: |
private | function | Returns the service container. | |
ControllerBase:: |
public static | function |
Instantiates a new instance of this class. Overrides ContainerInjectionInterface:: |
40 |
ControllerBase:: |
protected | function | Returns the current user. | 1 |
ControllerBase:: |
protected | function | Retrieves the entity form builder. | |
ControllerBase:: |
protected | function | Retrieves the entity manager service. | |
ControllerBase:: |
protected | function | Retrieves the entity type manager. | |
ControllerBase:: |
protected | function | Returns the form builder service. | 2 |
ControllerBase:: |
protected | function | Returns a key/value storage collection. | 1 |
ControllerBase:: |
protected | function | Returns the language manager service. | 1 |
ControllerBase:: |
protected | function | Returns the module handler. | 2 |
ControllerBase:: |
protected | function |
Returns a redirect response object for the specified route. Overrides UrlGeneratorTrait:: |
|
ControllerBase:: |
protected | function | Returns the state storage service. | |
LinkGeneratorTrait:: |
protected | property | The link generator. | 1 |
LinkGeneratorTrait:: |
protected | function | Returns the link generator. | |
LinkGeneratorTrait:: |
protected | function | Renders a link to a route given a route name and its parameters. | |
LinkGeneratorTrait:: |
public | function | Sets the link generator service. | |
LoggerChannelTrait:: |
protected | property | The logger channel factory service. | |
LoggerChannelTrait:: |
protected | function | Gets the logger for a specific channel. | |
LoggerChannelTrait:: |
public | function | Injects the logger channel factory. | |
MessengerTrait:: |
protected | property | The messenger. | 29 |
MessengerTrait:: |
public | function | Gets the messenger. | 29 |
MessengerTrait:: |
public | function | Sets the messenger. | |
RedirectDestinationTrait:: |
protected | property | The redirect destination service. | 1 |
RedirectDestinationTrait:: |
protected | function | Prepares a 'destination' URL query parameter for use with \Drupal\Core\Url. | |
RedirectDestinationTrait:: |
protected | function | Returns the redirect destination service. | |
RedirectDestinationTrait:: |
public | function | Sets the redirect destination service. | |
StringTranslationTrait:: |
protected | property | The string translation service. | 1 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. | |
UrlGeneratorTrait:: |
protected | property | The url generator. | |
UrlGeneratorTrait:: |
protected | function | Returns the URL generator service. | |
UrlGeneratorTrait:: |
public | function | Sets the URL generator service. | |
UrlGeneratorTrait:: |
protected | function | Generates a URL or path for a specific route based on the given parameters. |