View source
<?php
namespace Drupal\monitoring\Plugin\monitoring\SensorPlugin;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Render\HtmlEscapedText;
use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\DependencySerializationTrait;
use Drupal\Core\Entity\DependencyTrait;
use Drupal\Core\Entity\EntityFieldManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\Query\QueryAggregateInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\monitoring\Entity\SensorConfig;
use Drupal\monitoring\Result\SensorResultInterface;
use Drupal\monitoring\SensorPlugin\DatabaseAggregatorSensorPluginBase;
use Drupal\monitoring\SensorPlugin\ExtendedInfoSensorPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ContentEntityAggregatorSensorPlugin extends DatabaseAggregatorSensorPluginBase implements ExtendedInfoSensorPluginInterface {
use DependencySerializationTrait;
use DependencyTrait;
protected $aggregateField;
protected $entityTypeManager;
protected $configurableEntityType = TRUE;
protected $entityFieldManager;
protected function getEntityQueryAggregate() {
$entity_info = $this->entityTypeManager
->getDefinition($this->sensorConfig
->getSetting('entity_type'), TRUE);
$query = $this->entityTypeManager
->getStorage($this->sensorConfig
->getSetting('entity_type'))
->getAggregateQuery()
->accessCheck(FALSE);
$this->aggregateField = $entity_info
->getKey('id');
$this
->addAggregate($query);
foreach ($this
->getConditions() as $condition) {
if (empty($condition['field'])) {
continue;
}
$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 getEntityQuery() {
$entity_info = $this->entityTypeManager
->getDefinition($this->sensorConfig
->getSetting('entity_type'), TRUE);
$query = $this->entityTypeManager
->getStorage($this->sensorConfig
->getSetting('entity_type'))
->getQuery()
->accessCheck(FALSE);
foreach ($this
->getConditions() as $condition) {
if (empty($condition['field'])) {
continue;
}
$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(), '>');
}
if ($this
->getTimeIntervalField()) {
$query
->sort($this
->getTimeIntervalField(), 'DESC');
}
else {
$query
->sort($entity_info
->getKey('id'), 'DESC');
}
return $query;
}
public function __construct(SensorConfig $sensor_config, $plugin_id, $plugin_definition, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager) {
parent::__construct($sensor_config, $plugin_id, $plugin_definition);
$this->entityTypeManager = $entity_type_manager;
$this->entityFieldManager = $entity_field_manager;
}
public static function create(ContainerInterface $container, SensorConfig $sensor_config, $plugin_id, $plugin_definition) {
return new static($sensor_config, $plugin_id, $plugin_definition, $container
->get('entity_type.manager'), $container
->get('entity_field.manager'));
}
public function getDefaultConfiguration() {
$default_config = array(
'settings' => array(
'entity_type' => 'node',
),
);
return $default_config;
}
public function runSensor(SensorResultInterface $result) {
$query_result = $this
->getEntityQueryAggregate()
->execute();
$entity_type = $this->sensorConfig
->getSetting('entity_type');
$entity_info = $this->entityTypeManager
->getDefinition($entity_type);
if (isset($query_result[0][$entity_info
->getKey('id') . '_count'])) {
$records_count = $query_result[0][$entity_info
->getKey('id') . '_count'];
}
else {
$records_count = 0;
}
$result
->setValue($records_count);
}
public function resultVerbose(SensorResultInterface $result) {
$output = [];
if ($this->sensorConfig
->getSetting('verbose_fields')) {
$this
->verboseResultUnaggregated($output);
}
return $output;
}
public function verboseResultUnaggregated(array &$output) {
$output = [];
$field_type_manager = \Drupal::service('plugin.manager.field.field_type');
Database::startLog('monitoring_ceasp');
$entity_ids = $this
->getEntityQuery()
->range(0, 10)
->execute();
$query_log = Database::getLog('monitoring_ceasp')[0];
$entity_type_id = $this->sensorConfig
->getSetting('entity_type');
$entities = $this->entityTypeManager
->getStorage($entity_type_id)
->loadMultiple($entity_ids);
$fields = $this->sensorConfig
->getSetting('verbose_fields', [
'id',
'label',
]);
$rows = [];
foreach ($entities as $id => $entity) {
$row = [];
foreach ($fields as $field) {
switch ($field) {
case 'id':
$row[] = $entity
->id();
break;
case $this
->getTimeIntervalField():
$row[] = \Drupal::service('date.formatter')
->format($entity
->get($this
->getTimeIntervalField())[0]->value, 'short');
break;
case 'label':
$row[] = $entity
->hasLinkTemplate('canonical') ? $entity
->toLink() : $entity
->label();
break;
default:
if ($entity instanceof FieldableEntityInterface && $entity
->hasField($field)) {
try {
$field_type = $entity
->getFieldDefinition($field)
->getFieldStorageDefinition()
->getType();
if (isset($field_type_manager
->getDefinition($field_type)['default_formatter'])) {
$value = $entity->{$field}
->view([
'label' => 'hidden',
]);
$row[] = \Drupal::service('renderer')
->renderPlain($value);
}
else {
$property = $entity
->getFieldDefinition($field)
->getFieldStorageDefinition()
->getMainPropertyName();
$row[] = new HtmlEscapedText($entity->{$field}->{$property});
}
} catch (\Exception $e) {
$this
->messenger()
->addError(t('Error while trying to display %field: @error', [
'%field' => $field,
'@error' => $e
->getMessage(),
]));
$row[] = '';
}
}
else {
$row[] = '';
}
break;
}
}
$rows[] = array(
'data' => $row,
'class' => 'entity',
);
}
$header = $this->sensorConfig
->getSetting('verbose_fields', [
'id',
'label',
]);
$output['entities'] = array(
'#type' => 'verbose_table_result',
'#header' => $header,
'#rows' => $rows,
'#empty' => t('No matching entities were found.'),
'#query' => $query_log['query'],
'#query_args' => $query_log['args'],
);
return $output;
}
public function calculateDependencies() {
$entity_type_id = $this->sensorConfig
->getSetting('entity_type');
if (!$entity_type_id) {
throw new \Exception(new FormattableMarkup('Sensor @id is missing the required entity_type setting.', array(
'@id' => $this
->id(),
)));
}
$entity_type = $this->entityTypeManager
->getDefinition($this->sensorConfig
->getSetting('entity_type'));
$this
->addDependency('module', $entity_type
->getProvider());
return $this->dependencies;
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$settings = $this->sensorConfig
->getSettings();
$options = [];
foreach ($this->entityTypeManager
->getDefinitions() as $id => $entity_type) {
if ($entity_type
->entityClassImplements(FieldableEntityInterface::class)) {
$options[$id] = $entity_type
->getLabel();
}
}
$form['entity_type'] = array(
'#type' => 'select',
'#default_value' => $this->sensorConfig
->getSetting('entity_type', 'node'),
'#maxlength' => 255,
'#options' => $options,
'#title' => t('Entity Type'),
'#ajax' => array(
'callback' => array(
$this,
'fieldsReplace',
),
'wrapper' => 'selected-output',
'method' => 'replace',
),
'#access' => $this->configurableEntityType,
);
if (!isset($settings['entity_type'])) {
$form['entity_type']['#required'] = TRUE;
}
$form['conditions_table'] = array(
'#type' => 'fieldset',
'#title' => t('Conditions'),
'#prefix' => '<div id="selected-conditions">',
'#suffix' => '</div>',
'#tree' => FALSE,
);
$form['conditions_table']['conditions'] = array(
'#type' => 'table',
'#tree' => TRUE,
'#header' => array(
'field' => t('Field'),
'operator' => t('Operator'),
'value' => t('Value'),
),
'#empty' => t('Add conditions to filter the results.'),
);
$conditions = array_values($this->sensorConfig
->getSetting('conditions', []));
if (empty($conditions)) {
$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' => '=',
);
$operators = array(
'=' => t('='),
'!=' => t('!='),
'<' => t('<'),
'=<' => t('=<'),
'>' => t('>'),
'>=' => t('>='),
'STARTS_WITH' => t('STARTS_WITH'),
'CONTAINS' => t('CONTAINS'),
);
$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' => $operators,
),
'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['verbose_fields'] = array(
'#type' => 'details',
'#title' => t('Verbose Output configuration'),
'#prefix' => '<div id="selected-output">',
'#suffix' => '</div>',
'#open' => TRUE,
);
$entity_type = $this->entityTypeManager
->getDefinition($this->sensorConfig
->getSetting('entity_type'));
$available_fields = array_merge([
'id',
'label',
], array_keys($this->entityFieldManager
->getBaseFieldDefinitions($entity_type
->id())));
sort($available_fields);
$form['verbose_fields']['#description'] = t('Available Fields for entity type %type: %fields.', [
'%type' => $entity_type
->getLabel(),
'%fields' => implode(', ', $available_fields),
]);
$fields = $this->sensorConfig
->getSetting('verbose_fields', [
'id',
'label',
]);
if (!$form_state
->has('fields_rows')) {
$form_state
->set('fields_rows', count($fields) + 1);
}
for ($i = 0; $i < $form_state
->get('fields_rows'); $i++) {
$form['verbose_fields'][$i] = [
'#type' => 'textfield',
'#default_value' => isset($fields[$i]) ? $fields[$i] : '',
'#maxlength' => 256,
'#required' => FALSE,
'#tree' => TRUE,
];
}
$form['verbose_fields']['field_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',
),
),
);
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$sensor_form = $form_state
->getFormObject();
$sensor_config = $sensor_form
->getEntity();
$settings = $sensor_config
->getSettings();
$settings['conditions'] = [];
foreach ($form_state
->getValue('conditions') as $key => $condition) {
if (!empty($condition['field'])) {
$settings['conditions'][] = $condition;
}
}
$verbose_fields = [];
foreach ($form_state
->getValue('settings')['verbose_fields'] as $key => $field) {
if (!empty($field)) {
$verbose_fields[] = $field;
}
}
$settings['verbose_fields'] = array_unique($verbose_fields);
$sensor_config
->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']['verbose_fields'];
}
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);
$field_name = $form_state
->getValue(array(
'settings',
'aggregation',
'time_interval_field',
));
$entity_type_id = $form_state
->getValue(array(
'settings',
'entity_type',
));
if (!empty($field_name) && !empty($entity_type_id)) {
$entity_info = $this->entityFieldManager
->getFieldStorageDefinitions($entity_type_id);
$data_type = NULL;
if (!empty($entity_info[$field_name])) {
$data_type = $entity_info[$field_name]
->getPropertyDefinition('value')
->getDataType();
}
if ($data_type != 'timestamp') {
$form_state
->setErrorByName('settings][aggregation][time_interval_field', t('The specified time interval field %name does not exist or is not type timestamp.', array(
'%name' => $field_name,
)));
}
}
}
protected function addAggregate(QueryAggregateInterface $query) {
$query
->aggregate($this->aggregateField, 'COUNT');
}
}