View source
<?php
namespace Drupal\monitoring\Plugin\monitoring\SensorPlugin;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\monitoring\Result\SensorResultInterface;
use Drupal\monitoring\SensorPlugin\ExtendedInfoSensorPluginInterface;
use Drupal\monitoring\SensorPlugin\DatabaseAggregatorSensorPluginBase;
use Drupal\Core\Entity\DependencyTrait;
use Drupal\Core\Entity\Query\Sql\Condition;
use Drupal\Core\Entity\Query\Sql\Tables;
class DatabaseAggregatorSensorPlugin extends DatabaseAggregatorSensorPluginBase implements ExtendedInfoSensorPluginInterface {
use DependencyTrait;
protected $queryString;
protected $queryArguments;
protected $executedQuery;
protected $fetchedObject;
protected $configurableConditions = TRUE;
protected $configurableVerboseOutput = TRUE;
protected $configurableTable = TRUE;
public function getDefaultConfiguration() {
$default_config = parent::getDefaultConfiguration();
$default_config['settings'] = [
'history_status' => TRUE,
];
return $default_config;
}
protected function getAggregateQuery() {
$database = $this
->getService('database');
$query = $database
->select($this->sensorConfig
->getSetting('table'));
$this
->addAggregateExpression($query);
foreach ($this
->getConditions() as $condition) {
$this
->translateCondition($condition, $query);
$query
->condition($condition['field'], $condition['value'], isset($condition['operator']) ? $condition['operator'] : NULL);
}
if ($this
->getTimeIntervalField() && $this
->getTimeIntervalValue()) {
$query
->condition($this
->getTimeIntervalField(), \Drupal::time()
->getRequestTime() - $this
->getTimeIntervalValue(), '>');
}
return $query;
}
protected function addAggregateExpression(SelectInterface $select) {
$select
->addExpression('COUNT(*)', 'records_count');
}
protected function translateCondition(array &$condition, SelectInterface $select) {
$tables = new Tables($select);
Condition::translateCondition($condition, $select, $tables
->isFieldCaseSensitive($condition['field']));
}
protected function getQuery() {
$database = $this
->getService('database');
$query = $database
->select($this->sensorConfig
->getSetting('table'));
foreach ($this
->getConditions() as $condition) {
$this
->translateCondition($condition, $query);
$query
->condition($condition['field'], $condition['value'], isset($condition['operator']) ? $condition['operator'] : NULL);
}
if ($this
->getTimeIntervalField() && $this
->getTimeIntervalValue()) {
$query
->condition($this
->getTimeIntervalField(), \Drupal::time()
->getRequestTime() - $this
->getTimeIntervalValue(), '>');
}
$fields = $this->sensorConfig
->getSetting('verbose_fields');
if (!empty($fields)) {
foreach ($fields as $field) {
$query
->addField($this->sensorConfig
->getSetting('table'), $field);
}
}
if ($this
->getTimeIntervalField()) {
$query
->orderBy($this
->getTimeIntervalField(), 'DESC');
}
return $query;
}
protected function getHistoryQuery() {
$database = $this
->getService('database');
$query = $database
->select($this->sensorConfig
->getSetting('table'));
foreach ($this
->getConditions() as $condition) {
$this
->translateCondition($condition, $query);
$query
->condition($condition['field'], $condition['value'], isset($condition['operator']) ? $condition['operator'] : NULL);
}
$query
->addExpression('MIN(' . $this
->getTimeIntervalField() . ') DIV ' . $this
->getTimeIntervalValue() . ' * ' . $this
->getTimeIntervalValue(), 'timestamp');
$query
->groupBy($this
->getTimeIntervalField() . ' DIV ' . $this
->getTimeIntervalValue());
$this
->addAggregateExpression($query);
return $query;
}
protected function getOldestEntry() {
$database = $this
->getService('database');
$query = $database
->select($this->sensorConfig
->getSetting('table'));
foreach ($this
->getConditions() as $condition) {
$this
->translateCondition($condition, $query);
$query
->condition($condition['field'], $condition['value'], isset($condition['operator']) ? $condition['operator'] : NULL);
}
$query
->addExpression('MIN(' . $this
->getTimeIntervalField() . ')', 'timestamp');
return $query
->range(0, 1)
->execute()
->fetchField();
}
public function resultVerbose(SensorResultInterface $result) {
$output = [];
if ($this->sensorConfig
->getSetting('verbose_fields')) {
$this
->verboseResultUnaggregated($output);
}
if ($this->sensorConfig
->getSetting('history_status')) {
$this
->verboseResultHistory($output);
}
return $output;
}
public function verboseResultUnaggregated(array &$output) {
$output['verbose_sensor_result'] = array(
'#type' => 'verbose_table_result',
'#title' => t('Unaggregated result'),
);
$query = $this
->getQuery();
$query_result = $query
->range(0, 10)
->execute();
$rows = $this
->buildTableRows($query_result
->fetchAll());
$fields = $this->sensorConfig
->getSetting('verbose_fields');
$timestamp_field_name = $this
->getTimeIntervalField();
if ($timestamp_field_name && in_array($timestamp_field_name, $fields)) {
foreach ($rows as $key => $row) {
$rows[$key][$timestamp_field_name] = \Drupal::service('date.formatter')
->format($row[$timestamp_field_name], 'short');
}
}
$output['verbose_sensor_result']['#header'] = $this
->buildTableHeader($rows);
$output['verbose_sensor_result']['#rows'] = $rows;
$output['verbose_sensor_result']['#query'] = $query_result
->getQueryString();
$output['verbose_sensor_result']['#query_args'] = $query
->getArguments();
}
public function verboseResultHistory(array &$output) {
$output['verbose_sensor_history'] = array(
'#type' => 'verbose_table_result',
'#title' => t('History'),
);
$query = $this
->getHistoryQuery();
$query_result = $query
->range(0, 10)
->execute();
$rows = $this
->buildTableRows($query_result
->fetchAll());
foreach ($rows as $key => $row) {
$rows[$key]['timestamp'] = \Drupal::service('date.formatter')
->format($row['timestamp'], 'short');
}
$output['verbose_sensor_history']['#header'] = $this
->buildTableHeader($rows);
$output['verbose_sensor_history']['#rows'] = $rows;
$output['verbose_sensor_history']['#query'] = $query_result
->getQueryString();
$output['verbose_sensor_history']['#query_args'] = $query
->getArguments();
if ($oldest_entry = $this
->getOldestEntry()) {
$output['verbose_sensor_history']['#description'] = t('Oldest timestamp record is from :oldest_timestamp', [
':oldest_timestamp' => \Drupal::service('date.formatter')
->format($oldest_entry, 'short'),
]);
}
}
protected function buildTableHeader($rows = []) {
if (empty($rows)) {
return [];
}
$keys = array_keys($rows[0]);
$header = array_combine($keys, $keys);
return $header;
}
protected function buildTableRows(array $results) {
$rows = [];
foreach ($results as $delta => $row) {
$rows[$delta] = (array) $row;
}
return $rows;
}
public function runSensor(SensorResultInterface $result) {
$query = $this
->getAggregateQuery();
$this->queryArguments = $query
->getArguments();
$this->executedQuery = $query
->execute();
$this->queryString = $this->executedQuery
->getQueryString();
$this->fetchedObject = $this->executedQuery
->fetchObject();
$records_count = 0;
if (!empty($this->fetchedObject->records_count)) {
$records_count = $this->fetchedObject->records_count;
}
$result
->setValue($records_count);
}
public function calculateDependencies() {
parent::calculateDependencies();
\Drupal::moduleHandler()
->loadAllIncludes('install');
foreach (\Drupal::moduleHandler()
->getImplementations('schema') as $module) {
$schema = drupal_get_module_schema($module, $this->sensorConfig
->getSetting('table'));
if (isset($schema['module'])) {
$this
->addDependency('module', $schema['module']);
break;
}
}
return $this->dependencies;
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['table'] = array(
'#type' => 'textfield',
'#default_value' => $this->sensorConfig
->getSetting('table'),
'#maxlength' => 255,
'#title' => t('Table'),
'#required' => TRUE,
'#access' => $this->configurableTable,
);
$form['conditions_table'] = array(
'#type' => 'fieldset',
'#title' => t('Conditions'),
'#prefix' => '<div id="selected-conditions">',
'#suffix' => '</div>',
'#tree' => FALSE,
'#access' => $this->configurableConditions,
);
$form['conditions_table']['conditions'] = array(
'#type' => 'table',
'#tree' => TRUE,
'#header' => array(
'field' => t('Field key'),
'operator' => t('Operator'),
'value' => t('Value'),
),
'#empty' => t('Add conditions to filter the results.'),
);
$conditions = (array) $this->sensorConfig
->getSetting('conditions');
if (!$form_state
->has('conditions_rows')) {
$form_state
->set('conditions_rows', count($conditions) + 1);
}
for ($i = 0; $i < $form_state
->get('conditions_rows'); $i++) {
$condition = isset($conditions[$i]) ? $conditions[$i] : array();
$condition += array(
'field' => '',
'value' => '',
'operator' => '=',
);
$form['conditions_table']['conditions'][$i] = array(
'field' => array(
'#type' => 'textfield',
'#default_value' => $condition['field'],
'#title' => t('Field'),
'#title_display' => 'invisible',
'#size' => 20,
),
'operator' => array(
'#type' => 'select',
'#default_value' => $condition['operator'],
'#title' => t('Operator'),
'#title_display' => 'invisible',
'#options' => $this
->getConditionsOperators(),
),
'value' => array(
'#type' => 'textfield',
'#default_value' => $condition['value'],
'#title' => t('Value'),
'#title_display' => 'invisible',
'#size' => 40,
),
);
}
$form['conditions_table']['condition_add_button'] = array(
'#type' => 'submit',
'#value' => t('Add another condition'),
'#ajax' => array(
'wrapper' => 'selected-conditions',
'callback' => array(
$this,
'conditionsReplace',
),
'method' => 'replace',
),
'#submit' => array(
array(
$this,
'addConditionSubmit',
),
),
);
$form['output_table'] = array(
'#type' => 'fieldset',
'#title' => t('Verbose Fields'),
'#prefix' => '<div id="selected-output">',
'#suffix' => '</div>',
'#tree' => FALSE,
'#access' => $this->configurableVerboseOutput,
);
$form['output_table']['verbose_fields'] = array(
'#type' => 'table',
'#tree' => TRUE,
'#header' => array(
'field_key' => t('Field key'),
),
'#title' => t('Verbose fields'),
'#empty' => t('Add keys to display in the verbose output.'),
);
$fields = (array) $this->sensorConfig
->getSetting('verbose_fields');
if (!$form_state
->has('fields_rows')) {
$form_state
->set('fields_rows', count($fields) + 1);
}
for ($i = 0; $i < $form_state
->get('fields_rows'); $i++) {
$field = isset($fields[$i]) ? $fields[$i] : $i;
$form['output_table']['verbose_fields'][$field] = array(
'field_key' => array(
'#type' => 'textfield',
'#default_value' => is_int($field) ? '' : $field,
'#size' => 20,
),
);
}
$form['output_table']['fields_add_button'] = array(
'#type' => 'submit',
'#value' => t('Add another field'),
'#ajax' => array(
'wrapper' => 'selected-output',
'callback' => array(
$this,
'fieldsReplace',
),
'method' => 'replace',
),
'#submit' => array(
array(
$this,
'addFieldSubmit',
),
),
);
$form['aggregation']['history_status'] = [
'#type' => 'checkbox',
'#default_value' => $this->sensorConfig
->getSetting('history_status'),
'#title' => t('Enable history'),
'#description' => t('Check to show history results.'),
];
if ($this->configurableTimestampField) {
$form['aggregation']['history_status']['#states'] = [
'invisible' => [
':input[name="settings[aggregation][time_interval_field]"]' => [
'value' => '',
],
],
];
}
return $form;
}
protected function getConditionsOperators() {
return array(
'=' => t('='),
'!=' => t('!='),
'<' => t('<'),
'=<' => t('=<'),
'>' => t('>'),
'>=' => t('>='),
'STARTS_WITH' => t('STARTS_WITH'),
'CONTAINS' => t('CONTAINS'),
);
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$settings = $this->sensorConfig
->getSettings();
$settings['conditions'] = [];
foreach ($form_state
->getValue('conditions', []) as $key => $condition) {
if (!empty($condition['field'])) {
$settings['conditions'][] = $condition;
}
}
$settings['verbose_fields'] = [];
foreach ($form_state
->getValue('verbose_fields', []) as $field) {
if (!empty($field['field_key'])) {
$settings['verbose_fields'][] = $field['field_key'];
}
}
if ($form_state
->getValue('settings')['aggregation']['time_interval_field']) {
$settings['history_status'] = $form_state
->getValue('settings')['aggregation']['history_status'];
}
else {
$settings['history_status'] = FALSE;
}
$this->sensorConfig
->set('settings', $settings);
}
public function conditionsReplace(array $form, FormStateInterface $form_state) {
return $form['plugin_container']['settings']['conditions_table'];
}
public function addConditionSubmit(array $form, FormStateInterface $form_state) {
$form_state
->setRebuild();
$form_state
->set('conditions_rows', $form_state
->get('conditions_rows') + 1);
$this
->messenger()
->addMessage(t('Condition added.'));
}
public function fieldsReplace(array $form, FormStateInterface $form_state) {
return $form['plugin_container']['settings']['output_table'];
}
public function addFieldSubmit(array $form, FormStateInterface $form_state) {
$form_state
->setRebuild();
$form_state
->set('fields_rows', $form_state
->get('fields_rows') + 1);
$this
->messenger()
->addMessage(t('Field added.'));
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::validateConfigurationForm($form, $form_state);
$database = $this
->getService('database');
$table = $form_state
->getValue(array(
'settings',
'table',
));
$query = $database
->select($table);
if (!$database
->schema()
->tableExists($table)) {
try {
$query
->range(0, 1)
->execute();
} catch (\Exception $e) {
$form_state
->setErrorByName('settings][table', t('The table %table does not exist in the database %database', [
'%table' => $table,
'%database' => $database
->getConnectionOptions()['database'],
]));
return;
}
}
$field_name = $form_state
->getValue(array(
'settings',
'aggregation',
'time_interval_field',
));
if (!empty($field_name)) {
if (!$database
->schema()
->fieldExists($table, $field_name)) {
$form_state
->setErrorByName('settings][aggregation][time_interval_field', t('The specified time interval field %name does not exist in table %table.', array(
'%name' => $field_name,
'%table' => $table,
)));
}
}
if ($this->configurableConditions) {
$fields = $form_state
->getValue('verbose_fields', []);
foreach ($fields as $key => $field) {
$query = $database
->select($table);
$field_name = $field['field_key'];
if (!empty($field_name) && !$database
->schema()
->fieldExists($table, $field_name)) {
$query
->addField($table, $field_name);
try {
$query
->range(0, 1)
->execute();
} catch (\Exception $e) {
$form_state
->setErrorByName("verbose_fields][{$key}][field_key", t('The field %field does not exist in the table "%table".', [
'%field' => $field_name,
'%table' => $table,
]));
continue;
}
}
}
$fields = $form_state
->getValue('conditions', []);
foreach ($fields as $key => $field) {
$query = $database
->select($table);
$field_name = $field['field'];
if (!empty($field_name) && !$database
->schema()
->fieldExists($table, $field_name)) {
$query
->addField($table, $field_name);
try {
$query
->range(0, 1)
->execute();
} catch (\Exception $e) {
$form_state
->setErrorByName("conditions][{$key}][field", t('The field %field does not exist in the table "%table".', [
'%field' => $field_name,
'%table' => $table,
]));
continue;
}
}
}
}
}
}