View source
<?php
namespace Drupal\webform\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\webform\Element\WebformHtmlEditor;
use Drupal\webform\Entity\Webform;
use Drupal\webform\Utility\WebformDateHelper;
use Symfony\Component\DependencyInjection\ContainerInterface;
class WebformSubmissionLimitBlock extends BlockBase implements ContainerFactoryPluginInterface {
protected $currentUser;
protected $webform;
protected $sourceEntity;
protected $entityTypeManager;
protected $requestHandler;
protected $tokenManager;
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = new static($configuration, $plugin_id, $plugin_definition);
$instance->currentUser = $container
->get('current_user');
$instance->entityTypeManager = $container
->get('entity_type.manager');
$instance->requestHandler = $container
->get('webform.request');
$instance->tokenManager = $container
->get('webform.token_manager');
return $instance;
}
public function defaultConfiguration() {
return [
'type' => 'webform',
'source_entity' => TRUE,
'content' => '',
'progress_bar' => TRUE,
'progress_bar_label' => '',
'progress_bar_message' => '',
'webform_id' => '',
'entity_type' => '',
'entity_id' => '',
];
}
public function blockForm($form, FormStateInterface $form_state) {
$form['general'] = [
'#type' => 'details',
'#title' => $this
->t('General settings'),
'#open' => TRUE,
];
$form['general']['type'] = [
'#title' => $this
->t('Display limit and total submissions for the'),
'#type' => 'select',
'#options' => [
'webform' => $this
->t('Current webform'),
'user' => $this
->t('Current user'),
],
'#ajax' => static::getTokenAjaxSettings(),
'#default_value' => $this->configuration['type'],
'#parents' => [
'settings',
'type',
],
];
$form['general']['source_entity'] = [
'#title' => $this
->t('Restrict limit and total submissions to current or specified source entity'),
'#type' => 'checkbox',
'#return_value' => TRUE,
'#ajax' => static::getTokenAjaxSettings(),
'#default_value' => $this->configuration['source_entity'],
'#parents' => [
'settings',
'source_entity',
],
];
$form['general']['content'] = [
'#type' => 'webform_html_editor',
'#title' => $this
->t('Content'),
'#description' => $this
->t('The entered text appears before the progress bar.'),
'#default_value' => $this->configuration['content'],
'#parents' => [
'settings',
'content',
],
];
$form['tokens'] = static::buildTokens($this->configuration['type'], $this->configuration['source_entity']);
$form['progress'] = [
'#type' => 'details',
'#title' => $this
->t('Progress bar'),
'#open' => TRUE,
];
$form['progress']['progress_bar'] = [
'#title' => $this
->t('Show progress bar'),
'#type' => 'checkbox',
'#return_value' => TRUE,
'#default_value' => $this->configuration['progress_bar'],
'#parents' => [
'settings',
'progress_bar',
],
];
$form['progress']['progress_bar_label'] = [
'#title' => $this
->t('Progress bar label'),
'#type' => 'textfield',
'#description' => $this
->t('The entered text appears above the progress bar.'),
'#default_value' => $this->configuration['progress_bar_label'],
'#parents' => [
'settings',
'progress_bar_label',
],
'#states' => [
'visible' => [
':input[name="settings[progress_bar]"]' => [
'checked' => TRUE,
],
],
],
];
$form['progress']['progress_bar_message'] = [
'#title' => $this
->t('Progress bar message'),
'#type' => 'textfield',
'#description' => $this
->t('The entered text appears below the progress bar.'),
'#default_value' => $this->configuration['progress_bar_message'],
'#parents' => [
'settings',
'progress_bar_message',
],
'#states' => [
'visible' => [
':input[name="settings[progress_bar]"]' => [
'checked' => TRUE,
],
],
],
];
$form['advanced'] = [
'#title' => $this
->t('Advanced settings'),
'#type' => 'details',
'#description' => $this
->t("Webform and source entity are automatically detected based on the current page request. You can use the below settings to hardcode the submission limit block's webform and source entity."),
'#open' => $this->configuration['webform_id'] || $this->configuration['entity_type'],
];
$form['advanced']['webform_id'] = [
'#title' => $this
->t('Webform'),
'#type' => 'entity_autocomplete',
'#target_type' => 'webform',
'#default_value' => $this->configuration['webform_id'] ? $this->entityTypeManager
->getStorage('webform')
->load($this->configuration['webform_id']) : NULL,
'#parents' => [
'settings',
'webform_id',
],
];
$entity_type_options = [];
foreach ($this->entityTypeManager
->getDefinitions() as $entity_type_id => $entity_type) {
$entity_type_options[$entity_type_id] = $entity_type
->getLabel();
}
$form['advanced']['entity_type'] = [
'#type' => 'select',
'#title' => 'Source entity type',
'#empty_option' => $this
->t('- None -'),
'#options' => $entity_type_options,
'#default_value' => $this->configuration['entity_type'],
'#parents' => [
'settings',
'entity_type',
],
'#states' => [
'visible' => [
':input[name="settings[advanced][webform_id]"]' => [
'filled' => TRUE,
],
':input[name="settings[source_entity]"]' => [
'checked' => TRUE,
],
],
],
];
$form['advanced']['entity_id'] = [
'#type' => 'textfield',
'#title' => 'Source entity id',
'#default_value' => $this->configuration['entity_id'],
'#parents' => [
'settings',
'entity_id',
],
'#states' => [
'visible' => [
':input[name="settings[source_entity]"]' => [
'checked' => TRUE,
],
':input[name="settings[advanced][webform_id]"]' => [
'filled' => TRUE,
],
':input[name="settings[advanced][entity_type]"]' => [
'filled' => TRUE,
],
],
],
];
$this->tokenManager
->elementValidate($form);
return $form;
}
public function blockValidate($form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
if ($values['entity_type']) {
$t_args = [
'%label' => $form['advanced']['entity_id']['#title'],
];
if (empty($values['entity_id'])) {
$form_state
->setError($form['advanced']['entity_id'], $this
->t('An %label id is required.', $t_args));
}
elseif (!$this->entityTypeManager
->getStorage($values['entity_type'])
->load($values['entity_id'])) {
$form_state
->setError($form['advanced']['entity_id'], $this
->t('A valid %label is required.', $t_args));
}
}
}
public function blockSubmit($form, FormStateInterface $form_state) {
$values = $form_state
->getValues();
foreach ($this
->defaultConfiguration() as $key => $default_value) {
$this->configuration[$key] = $values[$key];
}
}
public function build() {
$build = [];
if ($this->configuration['content']) {
$build['content'] = WebformHtmlEditor::checkMarkup($this
->replaceTokens($this->configuration['content']));
}
if ($this->configuration['progress_bar']) {
$total = $this
->getTotal();
$limit = $this
->getLimit();
$build['progress_bar'] = [
'#theme' => 'progress_bar',
'#percent' => round($total / $limit * 100),
];
if ($message = $this->configuration['progress_bar_message']) {
$build['progress_bar']['#message']['#markup'] = $this
->replaceTokens($message);
}
if ($label = $this->configuration['progress_bar_label']) {
$build['progress_bar']['#label'] = $this
->replaceTokens($label);
}
}
$build['#attached']['library'][] = 'webform/webform.block.submission_limit';
return $build;
}
protected function blockAccess(AccountInterface $account) {
$webform = $this
->getWebform();
if ($webform === FALSE) {
return AccessResult::forbidden();
}
$source_entity = $this
->getSourceEntity();
if ($source_entity === FALSE) {
return AccessResult::forbidden();
}
if ($this
->getLimit() === FALSE) {
return AccessResult::forbidden();
}
return parent::blockAccess($account);
}
public function getCacheMaxAge() {
return 0;
}
protected function replaceTokens($text) {
if (strpos($text, '[total]') !== FALSE) {
$text = str_replace('[total]', $this
->getTotal(), $text);
}
if (strpos($text, '[limit]') !== FALSE) {
$text = str_replace('[limit]', $this
->getLimit(), $text);
}
if (strpos($text, '[remaining]') !== FALSE) {
$text = str_replace('[remaining]', $this
->getLimit() - $this
->getTotal(), $text);
}
if (strpos($text, '[interval]') !== FALSE) {
$text = str_replace('[interval]', $this
->getIntervalText(), $text);
}
return $this->tokenManager
->replace($text, $this
->getWebform());
}
protected function getLimit() {
$name = $this->configuration['source_entity'] ? 'entity_' : '';
$name .= $this->configuration['type'] === 'user' ? 'limit_user' : 'limit_total';
return $this
->getWebform()
->getSetting($name) ?: FALSE;
}
protected function getInterval() {
$name = $this->configuration['source_entity'] ? 'entity_' : '';
$name .= $this->configuration['type'] === 'user' ? 'limit_user_interval' : 'limit_total_interval';
return $this
->getWebform()
->getSetting($name);
}
protected function getIntervalText() {
return WebformDateHelper::getIntervalText($this
->getInterval());
}
protected function getTotal() {
return $this->entityTypeManager
->getStorage('webform_submission')
->getTotal($this
->getWebform(), $this
->getSourceEntity(), $this
->getCurrentUser(), [
'interval' => $this
->getInterval(),
]);
}
protected function getWebform() {
if (isset($this->webform)) {
return $this->webform;
}
if ($this->configuration['webform_id']) {
$this->webform = Webform::load($this->configuration['webform_id']) ?: FALSE;
}
else {
$this->webform = $this->requestHandler
->getCurrentWebform() ?: FALSE;
}
if ($this->webform) {
$webform_submission_storage = $this->entityTypeManager
->getStorage('webform_submission');
$values = [
'webform_id' => $this
->getWebform()
->id(),
];
if ($source_entity = $this
->getSourceEntity()) {
$values += [
'entity_type' => $source_entity
->getEntityTypeId(),
'entity_id' => $source_entity
->id(),
];
}
$temp_webform_submission = $webform_submission_storage
->create($values);
$this->webform
->invokeHandlers('overrideSettings', $temp_webform_submission);
}
return $this->webform;
}
protected function getSourceEntity() {
if (!$this->configuration['source_entity']) {
return NULL;
}
if (!isset($this->sourceEntity)) {
if ($this->configuration['entity_type'] && $this->configuration['entity_id']) {
$entity_storage = $this->entityTypeManager
->getStorage($this->configuration['entity_type']);
if (!$entity_storage) {
$this->sourceEntity = FALSE;
}
else {
$this->sourceEntity = $entity_storage
->load($this->configuration['entity_id']) ?: FALSE;
}
}
else {
$this->sourceEntity = $this->requestHandler
->getCurrentSourceEntity('webform') ?: FALSE;
}
}
return $this->sourceEntity;
}
protected function getCurrentUser() {
return $this->configuration['type'] === 'user' ? $this->currentUser : NULL;
}
public static function getTokenAjaxSettings() {
return [
'callback' => [
get_called_class(),
'tokenAjaxCallback',
],
'wrapper' => 'webform-submission-limit-block-tokens',
'progress' => [
'type' => 'fullscreen',
],
];
}
public static function tokenAjaxCallback(array &$form, FormStateInterface $form_state) {
$settings = $form_state
->getValue('settings');
return static::buildTokens($settings['type'], $settings['source_entity']);
}
public static function buildTokens($type, $source_entity) {
$token_manager = \Drupal::service('webform.token_manager');
module_load_include('inc', 'webform', 'webform.tokens');
$token_info = webform_token_info();
$tokens = $token_info['tokens']['webform_submission'];
$token_types = [
'limit',
'interval',
'total',
'remaining',
];
$rows = [];
foreach ($token_types as $token_type) {
$token_name = static::getTokenName($token_type, $type, $source_entity);
$rows[] = [
[
'data' => '[' . $token_type . ']',
'style' => 'vertical-align: top',
],
[
'data' => [
'name' => [
'#markup' => $tokens[$token_name]['name'],
'#prefix' => '<strong>',
'#suffix' => '</strong><br/>',
],
'description' => [
'#markup' => $tokens[$token_name]['description'],
],
],
'style' => 'vertical-align: top',
],
];
}
return [
'#type' => 'container',
'#attributes' => [
'id' => 'webform-submission-limit-block-tokens',
],
'details' => [
'#type' => 'details',
'#title' => t('Available tokens'),
'#open' => TRUE,
'table' => [
'#type' => 'table',
'#header' => [
[
'data' => t('Token'),
'style' => 'width: auto',
],
[
'data' => t('Name / Description'),
'style' => 'width: 100%',
],
],
'#rows' => $rows,
'#attributes' => [
'style' => 'margin: 1em 0',
],
],
'token_tree_link' => [
'token' => $token_manager
->buildTreeElement(),
],
],
];
}
protected static function getTokenName($prefix = 'limit', $type = 'webform', $source_entity = FALSE) {
$parts = [
$prefix,
$type,
];
if ($source_entity) {
$parts[] = 'source_entity';
}
return implode(':', $parts);
}
}