sitemap_status-1.0.0-alpha4/src/Form/SettingsForm.php
src/Form/SettingsForm.php
<?php
namespace Drupal\sitemap_status\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\sitemap_status\SitemapStatusInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Class SettingsForm.
*/
class SettingsForm extends ConfigFormBase {
/**
* Drupal\sitemap_status\SitemapStatusInterface definition.
*
* @var \Drupal\sitemap_status\SitemapStatusInterface
*/
protected $sitemapStatus;
/**
* Drupal\Core\Queue\QueueFactory definition.
*
* @var \Drupal\Core\Queue\QueueFactory
*/
protected $queueFactory;
/**
* Drupal\Core\Datetime\DateFormatterInterface definition.
*
* @var \Drupal\Core\Datetime\DateFormatterInterface
*/
protected $dateFormatter;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
$instance = parent::create($container);
$instance->sitemapStatus = $container->get('sitemap_status');
$instance->queueFactory = $container->get('queue');
$instance->dateFormatter = $container->get('date.formatter');
return $instance;
}
/**
* {@inheritdoc}
*/
protected function getEditableConfigNames() {
return [
'sitemap_status.settings',
];
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'sitemap_status_settings';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('sitemap_status.settings');
$summary = $this->sitemapStatus->getStatusSummary();
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = \Drupal::service('renderer');
$form['summary'] = [
'#type' => 'details',
'#title' => $this->t('Status summary'),
'#open' => TRUE,
];
$form['summary']['status_summary'] = [
'#type' => 'item',
'#markup' => $renderer->render($summary),
];
$form['dom'] = [
'#type' => 'details',
'#title' => $this->t('DOM based check'),
'#description' => $this->t('By default, only the http status is checked. Optionally check the DOM for errors or elements.'),
'#open' => TRUE,
];
$form['dom']['has_error_check'] = [
'#type' => 'checkbox',
'#title' => $this->t('Check errors'),
'#description' => $this->t('Status check passes if no errors are contained in the DOM.'),
'#default_value' => $config->get('has_error_check'),
];
$form['dom']['error_classes'] = [
'#type' => 'textarea',
'#title' => $this->t('Error classes'),
'#description' => $this->t('If the DOM contains one of these classes the status check fails. One per line, without the dot prefix. Defaults to <code>messages--error</code> if not set.'),
'#default_value' => $config->get('error_classes'),
'#states' => [
'invisible' => [
':input[name="has_error_check"]' => ['checked' => FALSE],
],
],
];
$form['dom']['has_element_check'] = [
'#type' => 'checkbox',
'#title' => $this->t('Check elements'),
'#description' => $this->t('Status check passes if elements are contained in the DOM.'),
'#default_value' => $config->get('has_element_check'),
];
$form['dom']['elements'] = [
'#type' => 'textarea',
'#title' => $this->t('Elements'),
'#description' => $this->t('If the DOM does not contains all of these elements, the status check fails. One per line, without the tag opening/closing (e.g. <code>heading</code>). Defaults to <code>h1</code> if not set.'),
'#default_value' => $config->get('elements'),
'#states' => [
'invisible' => [
':input[name="has_element_check"]' => ['checked' => FALSE],
],
],
];
$form['locations'] = [
'#type' => 'details',
'#title' => $this->t('Locations'),
'#open' => TRUE,
];
$form['locations']['basic_auth'] = [
'#type' => 'textfield',
'#title' => $this->t('Basic auth'),
'#description' => $this->t('Optionally appends basic auth credentials to the locations status check. Format: <em>username:password</em>'),
'#maxlength' => 255,
'#size' => 64,
'#default_value' => $config->get('basic_auth'),
];
$form['locations']['path_prefix'] = [
'#type' => 'textfield',
'#title' => $this->t('Path prefix'),
'#description' => $this->t('Can be used for a specific directory or a region based redirect, to be able to distinguish other 301 redirects. Without leading or trailing slashes.'),
'#maxlength' => 64,
'#size' => 64,
'#default_value' => $config->get('path_prefix'),
];
$form['locations']['async'] = [
'#type' => 'checkbox',
'#title' => $this->t('Async requests'),
'#description' => $this->t('Fetches locations status asynchronously, faster but uses more resources.'),
'#default_value' => $config->get('async'),
];
$form['locations']['concurrent_requests'] = [
'#type' => 'number',
'#title' => $this->t('Maximum concurrent requests'),
'#default_value' => $config->get('concurrent_requests') ?: SitemapStatusInterface::MAX_CONCURRENT_REQUESTS,
'#min' => 2,
'#states' => [
'invisible' => [
':input[name="async"]' => ['checked' => FALSE],
],
],
];
$form['locations']['maximum_locations'] = [
'#type' => 'number',
'#title' => $this->t('Maximum amount of locations to check'),
'#description' => $this->t('If set to 0, no maximum. Otherwise, checks the first locations found in the sitemap.'),
'#default_value' => $config->get('maximum_locations') ?: 0,
'#min' => 0,
];
$form['process'] = [
'#type' => 'details',
'#title' => t('Process'),
'#open' => TRUE,
];
$form['process']['stop_on_error'] = [
'#type' => 'checkbox',
// @todo batch needs to be adapted first
// @see LocationBatch::batchLocationProcess()
// @see LocationBatch::batchLocationsGroupProcess()
'#access' => FALSE,
'#title' => $this->t('Stop on error'),
'#description' => $this->t('Stops the status check on the first error met.'),
'#default_value' => $config->get('stop_on_error'),
];
$form['process']['cron_frequency'] = [
'#type' => 'select',
'#title' => $this->t('Cron frequency'),
'#default_value' => $config->get('cron_frequency'),
'#options' => [
0 => '<' . $this->t('Disable cron check') . '>',
1 => $this->t('Daily'),
7 => $this->t('Weekly'),
],
'#description' => $this->t('Optionally triggers the sitemap status on cron.'),
];
$form['cache'] = [
'#type' => 'details',
'#title' => $this->t('Cache'),
'#open' => TRUE,
];
$form['cache']['preserve_cache'] = [
'#type' => 'checkbox',
'#title' => $this->t('Preserve status check cache on cache rebuild.'),
'#default_value' => $config->get('preserve_cache'),
];
$form['actions_message'] = [
'#type' => 'item',
'#markup' => $this->t('If the configuration has changed, it should be saved to apply while checking the status.'),
];
$form = parent::buildForm($form, $form_state);
$form['actions']['check_status'] = [
'#type' => 'submit',
'#value' => $this->t('Check sitemap status'),
'#submit' => [[$this, 'batchCheckStatus']],
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
parent::submitForm($form, $form_state);
$this->config('sitemap_status.settings')
->set('has_error_check', $form_state->getValue('has_error_check'))
->set('error_classes', $form_state->getValue('error_classes'))
->set('has_element_check', $form_state->getValue('has_element_check'))
->set('elements', $form_state->getValue('elements'))
->set('path_prefix', $form_state->getValue('path_prefix'))
->set('basic_auth', $form_state->getValue('basic_auth'))
->set('async', $form_state->getValue('async'))
->set('concurrent_requests', $form_state->getValue('concurrent_requests'))
->set('maximum_locations', $form_state->getValue('maximum_locations'))
->set('cron_frequency', $form_state->getValue('cron_frequency'))
->set('stop_on_error', $form_state->getValue('stop_on_error'))
->set('preserve_cache', $form_state->getValue('preserve_cache'))
->save();
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
$pathPrefix = $form_state->getValue('path_prefix');
$basicAuth = $form_state->getValue('basic_auth');
$asyncRequests = $form_state->getValue('async');
$concurrentRequests = (int) $form_state->getValue('concurrent_requests');
// @todo validate errors classes (no dot, class safe) and elements (valid tag)
// @todo improve validation / possibly refactor with sitemap status service.
if (!empty($pathPrefix)) {
$currentHost = \Drupal::request()->getSchemeAndHttpHost();
$environmentUrl = $currentHost . '/' . $pathPrefix;
if (!$this->sitemapStatus->isUrlValid($environmentUrl)) {
$form_state->setError(
$form['path_prefix'],
$this->t('The resulting url with the path prefix (@environment_url) is not valid.', [
'@environment_url' => $environmentUrl,
])
);
}
}
if (!empty($basicAuth)) {
$basicAuthParts = explode(':', $basicAuth);
if (count($basicAuthParts) !== 2) {
$form_state->setError(
$form['basic_auth'],
$this->t('The basic auth must be with the format <em>username:password</em>.')
);
}
}
if ($asyncRequests === 1 && $concurrentRequests > SitemapStatusInterface::MAX_CONCURRENT_REQUESTS) {
$this->messenger()->addWarning($this->t('The maximum amount of concurrent requests might vary depending on the available resources. It is advised to not configure more than @max_requests.', [
'@max_requests' => SitemapStatusInterface::MAX_CONCURRENT_REQUESTS,
]));
}
}
/**
* Submit handler that checks the locations status with a batch.
*
* @todo move in the sitemap status service.
*
* @param array $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
public function batchCheckStatus(array &$form, FormStateInterface $form_state) {
// Make sure to delete the state override from Drush.
// To be removed once onQueueFinishedProcessing is implemented.
// @see SitemapStatusCommand.
\Drupal::state()->delete(SitemapStatusInterface::STATE_CONFIG_OVERRIDE);
$config = $this->config('sitemap_status.settings');
$asyncRequests = $config->get('async');
$sitemapLocations = $this->sitemapStatus->fetchSitemapLocations();
$operations = [];
$progressMessage = '';
if ($asyncRequests === 1) {
$concurrentRequests = $config->get('concurrent_requests');
if (empty($concurrentRequests)) {
$concurrentRequests = SitemapStatusInterface::MAX_CONCURRENT_REQUESTS;
}
$locationsGroups = array_chunk($sitemapLocations, $concurrentRequests);
foreach ($locationsGroups as $locationGroup) {
$operations[] = [
'\Drupal\sitemap_status\LocationBatch::batchLocationsGroupProcess', [$locationGroup],
];
}
$progressMessage = $this->t('Checked @current locations group on @total.');
}
else {
foreach ($sitemapLocations as $location) {
$operations[] = [
'\Drupal\sitemap_status\LocationBatch::batchLocationProcess', [$location],
];
}
$progressMessage = $this->t('Checked @current locations on @total.');
}
$batch = [
'title' => $this->t('Status check of @total sitemap locations', ['@total' => count($sitemapLocations)]),
'operations' => $operations,
'progress_message' => $progressMessage,
'finished' => ['\Drupal\sitemap_status\LocationBatch', 'batchFinished'],
];
batch_set($batch);
}
}
