ajax_dashboard-8.x-2.x-dev/src/AJAXDashboard.php
src/AJAXDashboard.php
<?php
namespace Drupal\ajax_dashboard;
use Drupal\Component\Utility\Html;
use Symfony\Component\Yaml\Yaml;
/**
* Class AJAXDashboard.
*
* @package Drupal\ajax_dashboard
*/
class AJAXDashboard {
/**
* @param $dashboard_id
* @param $dashboard_params
*
* @return array
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public static function getDashboardConfig($dashboard_id, $dashboard_params = []) {
$config_id = 'ajax_dashboard.ajax_dashboard.' . $dashboard_id;
$config = \Drupal::config($config_id);
$dashboard_config = $config->getRawData();
// Create config from underlying YAML if it does not exist as config.
if (empty($dashboard_config)) {
$dashboard_manager = \Drupal::service('plugin.manager.ajax_dashboard');
$dashboards = $dashboard_manager->getDefinitions();
if (isset($dashboards[$dashboard_id])) {
$dashboard_config = $dashboards[$dashboard_id];
// AJAX Dashboard config can go up to 6 levels deep
// e.g. Views button configs under controls.
$config = \Drupal\ajax_dashboard\Entity\AJAXDashboard::create([
'id' => $dashboard_id,
'status' => TRUE,
'data' => Yaml::dump($dashboard_config, 6, 2)
]);
$config->save();
}
}
// Override computed config with a module hook
$dashboard_config['data'] = isset($dashboard_config['data']) && !empty($dashboard_config['data']) ? Yaml::parse($dashboard_config['data']) : [];
\Drupal::moduleHandler()->alter('ajax_dashboard_config', $dashboard_config, $dashboard_params);
if (isset($dashboard_config['status']) && !empty($dashboard_config['status'])) {
return $dashboard_config['data'];
}
return [];
}
/**
* Build the AJAX Dashboard.
*
* Builds the dashboard from the data specified in a YAML file, and
* from parameters passed to the theme object.
*
* @param array $dashboard
* Dashboard data, loaded from a *.ajax_dashboard.yml file.
* @param array $variables
* Theme variables to modify as a part of building the dashboard.
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public static function buildDashboard(array $dashboard, array &$variables) {
$variables['dashboard']['id'] = $dashboard['id'];
$variables['dashboard']['label'] = isset($dashboard['label']) ? $dashboard['label'] : '';
$check_hash = function ($k) {
return strpos($k, '#') !== FALSE;
};
$attributes = array_filter($dashboard, $check_hash, ARRAY_FILTER_USE_KEY);
foreach ($attributes as $key => $value) {
if ($key === '#attributes') {
foreach ($value as $attr_key => $attr) {
$variables['attributes'][$attr_key] = $attr;
}
}
else {
$variables[$key] = $value;
}
}
// Add a generic placeholder if a custom one wasn't set.
if (!isset($variables['attributes']['data-placeholder'])) {
$variables['attributes']['data-placeholder'] = t('Loading...');
}
// For attributes, the dashboard also has the "ajax-dashboard" class.
$variables['attributes']['class'][] = 'ajax-dashboard';
// Do not let ID be set as an attribute. Set here.
$variables['attributes']['id'] = 'ajax-dashboard--' . $dashboard['id'];
// Build the controls.
$variables['dashboard']['controls'] = [
'#type' => 'html_tag',
'#tag' => 'div',
];
foreach ($dashboard['controls'] as $control_key => $control) {
// Backwards compatibility: set the default control plugin.
if (empty($control['plugin'])) {
$control['plugin'] = 'button_list';
}
if (strpos($control_key, '#') === 0) {
$variables['dashboard']['controls'][$control_key] = $control;
}
else {
$variables['dashboard']['controls'][$control_key] = [
'#theme' => 'ajax_dashboard_control',
'#dashboard_id' => $dashboard['id'],
'#control_id' => $control_key,
'#control_data' => $control,
'#params' => $variables['dashboard']['#params'],
'#weight' => isset($control['weight']) ? $control['weight'] : 0,
];
}
}
$variables['dashboard']['controls']['#attributes']['class'][] = 'ajax-dashboard-controls';
$variables['dashboard']['controls']['#attributes']['id'] = 'ajax-dashboard-controls--' . $dashboard['id'];
// Pick the active dashboard.
$dashboard_params = [
'dashboard' => $dashboard['id'],
'params' => $variables['dashboard']['#params'],
];
$active_button = self::getActiveButton($dashboard_params);
if (!empty($active_button)) {
$variables['dashboard']['display'] = self::displayDashboard($dashboard_params, $active_button);
}
$variables['#attached']['library'][] = 'ajax_dashboard/dashboard';
$variables['#attached']['drupalSettings']['ajax_dashboard']['dashboard_id'] = $dashboard['id'];
}
/**
* Utility function for sorting by weight.
* @param $a
* @param $b
* @return int
*/
public static function sortByWeight($a = [], $b = []) {
$wa = isset($a['weight']) ? $a['weight'] : 0;
$wb = isset($b['weight']) ? $b['weight'] : 0;
if ($wa == $wb) {
return 0;
}
return ($wa < $wb) ? -1 : 1;
}
/**
* @param array $dashboard_params
* @return mixed|null
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public static function getActiveButton(array $dashboard_params = []) {
$active_button = NULL;
/*
* Build the list of available buttons.
*/
if (isset($dashboard_params['dashboard'])) {
$params = !empty($dashboard_params['params']) ? $dashboard_params['params'] : [];
$dashboard = self::getDashboardConfig($dashboard_params['dashboard'], $params);
$control_manager = \Drupal::service('plugin.manager.ajax_dashboard_control');
$control_definitions = $control_manager->getDefinitions();
$buttons = [];
// Get dashboard buttons.
if (isset($dashboard['controls'])) {
// Sort the dashboard items.
$sort_func = AJAXDashboard::class . '::sortByWeight';
uasort($dashboard['controls'], $sort_func);
foreach ($dashboard['controls'] as $control_id => $control) {
$control['id'] = $control_id;
// If the control plugin isn't specified, use button_list as the assumed default.
if (empty($control['plugin'])) {
$control['plugin'] = 'button_list';
}
// If the plugin points to a valid control class, get its button data.
// Then, add the data to the $buttons array.
if (isset($control_definitions[$control['plugin']]['class'])) {
$control_buttons = $control_definitions[$control['plugin']]['class']::getButtonData($dashboard_params, $control, $dashboard);
$buttons = array_merge($buttons, $control_buttons);
}
}
}
/*
* If this was called with a query, the exact item will be selected.
* Otherwise, use the cookie logic.
* Finally, first valid item.
*/
// First check if we have at least one button with access enabled.
if (!empty($buttons)) {
$active_button = NULL;
// See if we have params for a clicked button.
// $dashboard_params['dashboard'] was verified earlier.
if (isset($dashboard_params['control']) && isset($dashboard_params['button'])) {
$button_id_array = [
$dashboard_params['dashboard'],
$dashboard_params['control'],
$dashboard_params['button'],
];
$button_id = implode('_', $button_id_array);
if (isset($buttons[$button_id])) {
$active_button = $buttons[$button_id];
}
}
// If we hadn't clicked something, check the url for a query parameter.
if (!$active_button) {
$query = \Drupal::request()->query;
if ($query->has('dashboard')) {
$button_id = $query->get('dashboard');
if (isset($buttons[$button_id])) {
$active_button = $buttons[$button_id];
}
}
}
// Next, see if we have a cookie.
if (!$active_button) {
$cookies = \Drupal::request()->cookies;
if ($cookies->has('ajax_dashboard__' . $dashboard_params['dashboard'])) {
$button_id = $cookies->get('ajax_dashboard__' . $dashboard_params['dashboard']);
if (isset($buttons[$button_id])) {
$active_button = $buttons[$button_id];
}
}
}
// Finally, just get the first item in the list.
if (!$active_button) {
$keys = array_keys($buttons);
$key = array_shift($keys);
$active_button = $buttons[$key];
}
}
}
return $active_button;
}
/**
* Create the dashboard display's render array.
*
* This may be called during the AJAX reload, or on initial page load.
* This function looks for the active button, and runs that button's
* display logic to create the dashboard.
*
* @param array $dashboard_params
* Dashboard parameters and data.
* @param array $active_button
* The active dashboard button.
*
* @return array
* A render array.
*/
public static function displayDashboard(array $dashboard_params = [], array $active_button = []) {
$dashboard_params['params'] = isset($dashboard_params['params']) ? $dashboard_params['params'] : [];
$output = ['#markup' => ''];
if ($active_button && isset($active_button['class'])) {
// Build the display.
$output = $active_button['class']::getButtonDashboardContent($dashboard_params['params'], $active_button['button_data']);
$dashboard_display_id = Html::escape('ajax-dashboard-display--' . $dashboard_params['dashboard']);
return [
'#prefix' => '<div id="' . $dashboard_display_id . '" class="ajax-dashboard-display">',
'dashboard' => $output,
'#suffix' => '</div>',
'#cache' => [
'max-age' => 0,
],
];
}
return $output;
}
}
