diff --git a/captcha.module b/captcha.module index fde54e7..fc8248e 100644 --- a/captcha.module +++ b/captcha.module @@ -10,6 +10,7 @@ */ use Drupal\captcha\Entity\CaptchaPoint; +use Drupal\Core\Form\FormStateInterface; /** * Constants for CAPTCHA persistence. @@ -18,6 +19,7 @@ use Drupal\captcha\Entity\CaptchaPoint; * form saves them as strings in the variables table anyway? */ +// @TODO: move all constants to some class. // Always add a CAPTCHA (even on every page of a multipage workflow). define('CAPTCHA_PERSISTENCE_SHOW_ALWAYS', 0); // Only one CAPTCHA has to be solved per form instance/multi-step workflow. @@ -146,7 +148,7 @@ function captcha_element_info() { /** * Process callback for CAPTCHA form element. */ -function captcha_element_process(array $element, array &$form_state, array $complete_form) { +function captcha_element_process(array $element, FormStateInterface $form_state, array $complete_form) { // Add captcha.inc file module_load_include('inc', 'captcha'); @@ -300,8 +302,9 @@ function theme_captcha($variables) { * if needed and adds. CAPTCHA administration links for site * administrators if this option is enabled. */ -function captcha_form_alter(array &$form, array &$form_state, $form_id) { - if (!user_access('skip CAPTCHA')) { +function captcha_form_alter(array &$form, FormStateInterface $form_state, $form_id) { + $account = \Drupal::currentUser(); + if (!$account->hasPermission('skip CAPTCHA')) { // Visitor does not have permission to skip CAPTCHAs. module_load_include('inc', 'captcha'); @@ -327,8 +330,8 @@ function captcha_form_alter(array &$form, array &$form_state, $form_id) { } } elseif (\Drupal::config('captcha.settings')->get('captcha_administration_mode', FALSE) - && user_access('administer CAPTCHA settings') - && (arg(0) != 'admin' || \Drupal::config('captcha.settings')->get('captcha_allow_on_admin_pages', FALSE))) { + && $account->hasPermission('administer CAPTCHA settings') + && (\Drupal::service('router.admin_context')->isAdminRoute() || \Drupal::config('captcha.settings')->get('captcha_allow_on_admin_pages', FALSE))) { // Add CAPTCHA administration tools. module_load_include('inc', 'captcha'); @@ -358,25 +361,25 @@ function captcha_form_alter(array &$form, array &$form_state, $form_id) { '@disable' => url("admin/config/people/captcha/captcha-points/$form_id/disable", array('query' => drupal_get_destination())), )), ); - // Add an example challenge with solution. - // This does not work with the reCAPTCHA and Egglue challenges as - // discussed in http://drupal.org/node/487032 and - // http://drupal.org/node/525586. As a temporary workaround, we - // blacklist the reCAPTCHA and Egglue challenges and do not show - // an example challenge. - // TODO: Once the issues mentioned above are fixed, this workaround - // should be removed. - $captcha_element['example'] = array( - '#type' => 'details', - '#title' => t('Example'), - '#description' => t('This is a pre-solved, non-blocking example of this challenge.'), - '#open' => TRUE, - ); - $captcha_element['example']['example_captcha'] = array( - '#type' => 'captcha', - '#captcha_type' => $captcha_point->getCaptchaType(), - '#captcha_admin_mode' => TRUE, - ); +// // Add an example challenge with solution. +// // This does not work with the reCAPTCHA and Egglue challenges as +// // discussed in http://drupal.org/node/487032 and +// // http://drupal.org/node/525586. As a temporary workaround, we +// // blacklist the reCAPTCHA and Egglue challenges and do not show +// // an example challenge. +// // TODO: Once the issues mentioned above are fixed, this workaround +// // should be removed. +// $captcha_element['example'] = array( +// '#type' => 'details', +// '#title' => t('Example'), +// '#description' => t('This is a pre-solved, non-blocking example of this challenge.'), +// '#open' => TRUE, +// ); +// $captcha_element['example']['example_captcha'] = array( +// '#type' => 'captcha', +// '#captcha_type' => $captcha_point->getCaptchaType(), +// '#captcha_admin_mode' => TRUE, +// ); } else { $captcha_element['#title'] = t('CAPTCHA: no challenge enabled'); @@ -492,7 +495,7 @@ function captcha_validate_case_insensitive_ignore_spaces($solution, $response) { * Array with $posted_form_id and $post_captcha_sid (with NULL values * if the values could not be found, e.g. for a fresh form). */ -function _captcha_get_posted_captcha_info(array $element, array $form_state, $this_form_id) { +function _captcha_get_posted_captcha_info(array $element, FormStateInterface $form_state, $this_form_id) { if ($form_state['submitted'] && isset($form_state['captcha_info'])) { // We are handling (or rebuilding) an already submitted form, // so we already determined the posted form ID and CAPTCHA session ID diff --git a/captcha.routing.yml b/captcha.routing.yml index 05695df..4f5ab8a 100644 --- a/captcha.routing.yml +++ b/captcha.routing.yml @@ -2,6 +2,7 @@ captcha_settings: path: '/admin/config/people/captcha' defaults: _form: '\Drupal\captcha\Form\CaptchaSettingsForm' + _title: 'CAPTCHA settings' requirements: _permission: 'administer CAPTCHA settings' diff --git a/image_captcha/config/install/image_captcha.settings.yml b/image_captcha/config/install/image_captcha.settings.yml index 0185911..a08ce49 100644 --- a/image_captcha/config/install/image_captcha.settings.yml +++ b/image_captcha/config/install/image_captcha.settings.yml @@ -1,5 +1,5 @@ image_captcha_fonts_preview_map_cache: [] -image_captcha_fonts: [] +image_captcha_fonts: ['BUILTIN'] image_captcha_font_size: 30 image_captcha_character_spacing: '1.2' image_captcha_image_allowed_chars: 'aAbBCdEeFfGHhijKLMmNPQRrSTtWXYZ23456789' diff --git a/image_captcha/image_captcha.routing.yml b/image_captcha/image_captcha.routing.yml index 9f3e653..48ef56e 100644 --- a/image_captcha/image_captcha.routing.yml +++ b/image_captcha/image_captcha.routing.yml @@ -8,13 +8,13 @@ image_captcha.settings: image_captcha.font_preview: path: '/admin/config/people/captcha/image_captcha/font_preview/{token}' defaults: - _controller: '\Drupal\image_captcha\Controller\CaptchaFontPreview' + _controller: '\Drupal\image_captcha\Controller\CaptchaFontPreview::content' requirements: _permission: 'administer CAPTCHA settings' image_captcha.generator: path: '/image-captcha-generate/{session_id}/{timestamp}' defaults: - _content: '\Drupal\image_captcha\Controller\CaptchaImageGenerator::send' + _controller: '\Drupal\image_captcha\Controller\CaptchaImageGenerator::create' requirements: _permission: 'access content' diff --git a/image_captcha/src/Controller/CaptchaFontPreview.php b/image_captcha/src/Controller/CaptchaFontPreview.php index d494f65..38b7c7d 100644 --- a/image_captcha/src/Controller/CaptchaFontPreview.php +++ b/image_captcha/src/Controller/CaptchaFontPreview.php @@ -7,14 +7,14 @@ namespace Drupal\image_captcha\Controller; -use Drupal\Core\Controller\HtmlPageController; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\StreamedResponse; -class CaptchaFontPreview extends HtmlPageController { +class CaptchaFontPreview extends StreamedResponse { /** * {@inheritdoc} */ - public function content(Request $request, $_content) { + public function content(Request $request) { $token = $request->get('token'); // Get the font from the given font token. if ($token == 'BUILTIN') { diff --git a/image_captcha/src/Controller/CaptchaImageGenerator.php b/image_captcha/src/Controller/CaptchaImageGenerator.php index c049a83..1a905f5 100644 --- a/image_captcha/src/Controller/CaptchaImageGenerator.php +++ b/image_captcha/src/Controller/CaptchaImageGenerator.php @@ -49,10 +49,10 @@ class CaptchaImageGenerator extends StreamedResponse { */ public function sendHeaders() { if ($this->config->get('image_captcha_file_format') == IMAGE_CAPTCHA_FILE_FORMAT_JPG) { - header('Content-Type: image/jpeg'); + $this->headers->set('content-type', 'image/jpeg'); } else { - header('Content-Type: image/png'); + $this->headers->set('content-type', 'image/png'); } return parent::sendHeaders(); @@ -63,6 +63,9 @@ class CaptchaImageGenerator extends StreamedResponse { return; } + // Begin capturing the byte stream + ob_start(); + $file_format = $this->config->get('image_captcha_file_format'); if ($file_format == IMAGE_CAPTCHA_FILE_FORMAT_JPG) { imagejpeg($this->image); @@ -107,7 +110,7 @@ class CaptchaImageGenerator extends StreamedResponse { protected function generateImage($code) { $fonts = _image_captcha_get_enabled_fonts(); - $font_size = (int) $this->config->get('image_captcha_font_size'); + $font_size = $this->config->get('image_captcha_font_size'); list($width, $height) = _image_captcha_image_size($code); $image = imagecreatetruecolor($width, $height); @@ -124,12 +127,12 @@ class CaptchaImageGenerator extends StreamedResponse { imagecolortransparent($image, $background_color); } imagefilledrectangle($image, 0, 0, $width, $height, $background_color); +// +// // Do we need to draw in RTL mode? +// global $language; +// $rtl = $language->direction && ((bool) $this->config->get('image_captcha_rtl_support')); - // Do we need to draw in RTL mode? - global $language; - $rtl = $language->direction && ((bool) $this->config->get('image_captcha_rtl_support')); - - $result = $this->printString($image, $width, $height, $fonts, $font_size, $code, $rtl); + $result = $this->printString($image, $width, $height, $fonts, $font_size, $code); if (!$result) { return FALSE; } @@ -310,9 +313,11 @@ class CaptchaImageGenerator extends StreamedResponse { $character_quantity = count($characters); $foreground_rgb = $this->hexToRgb($this->config->get('image_captcha_foreground_color')); + $background_rgb = $this->hexToRgb($this->config->get('image_captcha_background_color')); + $background_color = imagecolorallocate($image, $background_rgb[0], $background_rgb[1], $background_rgb[2]); $foreground_color = imagecolorallocate($image, $foreground_rgb[0], $foreground_rgb[1], $foreground_rgb[2]); // Precalculate the value ranges for color randomness. - $foreground_randomness = (int) $this->config->get('image_captcha_foreground_color_randomness'); + $foreground_randomness = $this->config->get('image_captcha_foreground_color_randomness'); $foreground_color_range = array(); if ($foreground_randomness) { @@ -345,6 +350,7 @@ class CaptchaImageGenerator extends StreamedResponse { // Get character dimensions for TrueType fonts. if ($font != 'BUILTIN') { + putenv('GDFONTPATH=' . realpath('.')); $bbox = imagettfbbox($font_size, 0, drupal_realpath($font), $character); // In very rare cases with some versions of the GD library, the x-value // of the left side of the bounding box as returned by the first call of diff --git a/image_captcha/src/Form/ImageCaptchaSettingsForm.php b/image_captcha/src/Form/ImageCaptchaSettingsForm.php index 2fd4016..b8949a2 100644 --- a/image_captcha/src/Form/ImageCaptchaSettingsForm.php +++ b/image_captcha/src/Form/ImageCaptchaSettingsForm.php @@ -8,6 +8,7 @@ namespace Drupal\image_captcha\Form; use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Language\Language; /** @@ -25,7 +26,8 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function buildForm(array $form, array &$form_state) { + public function buildForm(array $form, FormStateInterface $form_state) { + $config = $this->config('image_captcha.settings'); // Add CSS and JS for theming and added usability on admin form. $form['#attached']['library'][] = 'captcha_image/base'; @@ -61,13 +63,13 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { $form['image_captcha_code_settings']['image_captcha_image_allowed_chars'] = array( '#type' => 'textfield', '#title' => t('Characters to use in the code'), - '#default_value' => $this->config('image_captcha_image_allowed_chars'), + '#default_value' => $config->get('image_captcha_image_allowed_chars'), ); $form['image_captcha_code_settings']['image_captcha_code_length'] = array( '#type' => 'select', '#title' => t('Code length'), '#options' => array(2 => 2, 3, 4, 5, 6, 7, 8, 9, 10), - '#default_value' => (int) $this->config('image_captcha_code_length'), + '#default_value' => $config->get('image_captcha_code_length'), '#description' => t('The code length influences the size of the image. Note that larger values make the image generation more CPU intensive.'), ); // RTL support option (only show this option when there are RTL languages). @@ -76,7 +78,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { $form['image_captcha_code_settings']['image_captcha_rtl_support'] = array( '#title' => t('RTL support'), '#type' => 'checkbox', - '#default_value' => $this->config('image_captcha_rtl_support'), + '#default_value' => $config->get('image_captcha_rtl_support'), '#description' => t('Enable this option to render the code from right to left for right to left languages.'), ); } @@ -95,7 +97,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { '#type' => 'textfield', '#title' => t('Background color'), '#description' => t('Enter the hexadecimal code for the background color (e.g. #FFF or #FFCE90). When using the PNG file format with transparent background, it is recommended to set this close to the underlying background color.'), - '#default_value' => $this->config('image_captcha_background_color'), + '#default_value' => $config->get('image_captcha_background_color'), '#maxlength' => 7, '#size' => 8, ); @@ -103,7 +105,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { '#type' => 'textfield', '#title' => t('Text color'), '#description' => t('Enter the hexadecimal code for the text color (e.g. #000 or #004283).'), - '#default_value' => $this->config('image_captcha_foreground_color', '#000000'), + '#default_value' => $config->get('image_captcha_foreground_color'), '#maxlength' => 7, '#size' => 8, ); @@ -117,14 +119,14 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { 150 => t('High variation'), 200 => t('Very high variation'), ), - '#default_value' => (int) $this->config('image_captcha_foreground_color_randomness'), + '#default_value' => $config->get('image_captcha_foreground_color_randomness'), '#description' => t('The different characters will have randomized colors in the specified range around the text color.'), ); $form['image_captcha_color_settings']['image_captcha_file_format'] = array( '#type' => 'select', '#title' => t('File format'), '#description' => t('Select the file format for the image. JPEG usually results in smaller files, PNG allows tranparency.'), - '#default_value' => $this->config('image_captcha_file_format'), + '#default_value' => $config->get('image_captcha_file_format'), '#options' => array( IMAGE_CAPTCHA_FILE_FORMAT_JPG => t('JPEG'), IMAGE_CAPTCHA_FILE_FORMAT_PNG => t('PNG'), @@ -155,27 +157,27 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { 9 => '9', 10 => t('@level - high', array('@level' => '10')), ), - '#default_value' => (int) $this->config('image_captcha_distortion_amplitude'), + '#default_value' => $config->get('image_captcha_distortion_amplitude'), '#description' => t('Set the degree of wave distortion in the image.'), ); $form['image_captcha_distortion_and_noise']['image_captcha_bilinear_interpolation'] = array( '#type' => 'checkbox', '#title' => t('Smooth distortion'), - '#default_value' => $this->config('image_captcha_bilinear_interpolation'), + '#default_value' => $config->get('image_captcha_bilinear_interpolation'), '#description' => t('This option enables bilinear interpolation of the distortion which makes the image look smoother, but it is more CPU intensive.'), ); $form['image_captcha_distortion_and_noise']['image_captcha_dot_noise'] = array( '#type' => 'checkbox', '#title' => t('Add salt and pepper noise'), - '#default_value' => $this->config('image_captcha_dot_noise'), + '#default_value' => $config->get('image_captcha_dot_noise'), '#description' => t('This option adds randomly colored point noise.'), ); $form['image_captcha_distortion_and_noise']['image_captcha_line_noise'] = array( '#type' => 'checkbox', '#title' => t('Add line noise'), - '#default_value' => $this->config('image_captcha_line_noise', 0), + '#default_value' => $config->get('image_captcha_line_noise', 0), '#description' => t('This option enables lines randomly drawn on top of the text code.'), ); @@ -191,7 +193,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { 7 => '7', 10 => '10 - ' . t('severe'), ), - '#default_value' => (int) $this->config('image_captcha_noise_level'), + '#default_value' => (int) $config->get('image_captcha_noise_level'), ); return parent::buildForm($form, $form_state); @@ -200,7 +202,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function validateForm(array &$form, array &$form_state) { + public function validateForm(array &$form, FormStateInterface $form_state) { // Check image_captcha_image_allowed_chars for spaces. if (preg_match('/\s/', $form_state['values']['image_captcha_image_allowed_chars'])) { @@ -240,11 +242,11 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function submitForm(array &$form, array &$form_state) { + public function submitForm(array &$form, FormStateInterface $form_state) { if (!isset($form['image_captcha_font_settings']['no_ttf_support'])) { // Filter the image_captcha fonts array to pick out the selected ones. $fonts = array_filter($form_state['values']['image_captcha_fonts']); - $this->config('image_captcha_fonts', $fonts); + $this->config('image_captcha.settings')->set('image_captcha_fonts', $fonts)->save(); } parent::SubmitForm($form, $form_state); @@ -261,6 +263,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { * The font settings specific form elements. */ protected function settingsDotSection() { + $config = $this->config('image_captcha.settings'); // Put it all in a details element. $form = array( '#type' => 'details', @@ -286,7 +289,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { // Cache the list of previewable fonts. All the previews are done // in separate requests, and we don't want to rescan the filesystem // every time, so we cache the result. - $this->config('image_captcha_fonts_preview_map_cache', $fonts); + $config->get('image_captcha_fonts_preview_map_cache', $fonts); // Put these fonts with preview image in the list. foreach ($fonts as $token => $font) { $img_src = check_url(url('admin/config/people/captcha/image_captcha/font_preview/' . $token)); @@ -330,7 +333,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { 48 => '48 pt', 64 => '64 pt - ' . t('extra large'), ), - '#default_value' => (int) $this->config('image_captcha_font_size'), + '#default_value' => (int) $config->get('image_captcha_font_size'), '#description' => t('The font size influences the size of the image. Note that larger values make the image generation more CPU intensive.'), ); } @@ -341,7 +344,7 @@ class ImageCaptchaSettingsForm extends ConfigFormBase { '#type' => 'select', '#title' => t('Character spacing'), '#description' => t('Define the average spacing between characters. Note that larger values make the image generation more CPU intensive.'), - '#default_value' => $this->config('image_captcha_character_spacing'), + '#default_value' => $config->get('image_captcha_character_spacing'), '#options' => array( '0.75' => t('tight'), '1' => t('normal'), diff --git a/src/Form/CaptchaExamplesForm.php b/src/Form/CaptchaExamplesForm.php index 48f5faf..244e6b6 100644 --- a/src/Form/CaptchaExamplesForm.php +++ b/src/Form/CaptchaExamplesForm.php @@ -9,6 +9,7 @@ namespace Drupal\captcha\Form; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -46,7 +47,7 @@ class CaptchaExamplesForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function buildForm(array $form, array &$form_state) { + public function buildForm(array $form, FormStateInterface $form_state) { module_load_include('inc', 'captcha', 'captcha.admin'); $module = $this->getRequest()->get('module'); diff --git a/src/Form/CaptchaPointDeleteForm.php b/src/Form/CaptchaPointDeleteForm.php index 48c0271..953a01d 100644 --- a/src/Form/CaptchaPointDeleteForm.php +++ b/src/Form/CaptchaPointDeleteForm.php @@ -34,7 +34,7 @@ class CaptchaPointDeleteForm extends EntityConfirmFormBase { /** * {@inheritdoc} */ - public function submit(array $form, array &$form_state) { + public function submit(array $form, FormStateInterface $form_state) { $this->entity->delete(); drupal_set_message($this->t('Category %label has been deleted.', array('%label' => $this->entity->label()))); $form_state['redirect_route'] = $this->getCancelRoute(); diff --git a/src/Form/CaptchaPointForm.php b/src/Form/CaptchaPointForm.php index 306af3a..a3d264b 100644 --- a/src/Form/CaptchaPointForm.php +++ b/src/Form/CaptchaPointForm.php @@ -9,13 +9,14 @@ namespace Drupal\captcha\Form; use Drupal\Core\Entity\EntityForm; use Drupal\captcha\CaptchaPointInterface; +use Drupal\Core\Form\FormStateInterface; class CaptchaPointForm extends EntityForm { /** * {@inheritdoc} */ - public function form(array $form, array &$form_state) { + public function form(array $form, FormStateInterface $form_state) { $form = parent::form($form, $form_state); module_load_include('inc', 'captcha', 'captcha.admin'); @@ -53,7 +54,7 @@ class CaptchaPointForm extends EntityForm { /** * {@inheritdoc} */ - public function save(array $form, array &$form_state) { + public function save(array $form, FormStateInterface $form_state) { $captcha_point = $this->entity; $status = $captcha_point->save(); if ($status) { diff --git a/src/Form/CaptchaSettingsForm.php b/src/Form/CaptchaSettingsForm.php index d6e55de..7a81510 100644 --- a/src/Form/CaptchaSettingsForm.php +++ b/src/Form/CaptchaSettingsForm.php @@ -9,6 +9,7 @@ namespace Drupal\captcha\Form; use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Form\ConfigFormBase; +use Drupal\Core\Form\FormStateInterface; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -46,7 +47,7 @@ class CaptchaSettingsForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function buildForm(array $form, array &$form_state) { + public function buildForm(array $form, FormStateInterface $form_state) { $config = $this->config('captcha.settings'); module_load_include('inc', 'captcha'); module_load_include('inc', 'captcha', 'captcha.admin'); @@ -106,7 +107,7 @@ class CaptchaSettingsForm extends ConfigFormBase { '#default_value' => $config->get('captcha_add_captcha_description'), ); // Textfield(s) for the CAPTCHA description. - if (module_exists('locale')) { + if (\Drupal::moduleHandler()->moduleExists('locale')) { $langs = language_list(); $form['captcha_descriptions'] = array( '#type' => 'details', @@ -194,7 +195,7 @@ class CaptchaSettingsForm extends ConfigFormBase { /** * {@inheritdoc} */ - public function submitForm(array &$form, array &$form_state) { + public function submitForm(array &$form, FormStateInterface $form_state) { $config = \Drupal::config('captcha.settings'); $config->set('captcha_administration_mode', $form_state['values']['captcha_administration_mode']); $config->set('captcha_allow_on_admin_pages', $form_state['values']['captcha_allow_on_admin_pages']); @@ -203,7 +204,7 @@ class CaptchaSettingsForm extends ConfigFormBase { // CAPTCHA description stuff. $config->set('captcha_add_captcha_description', $form_state['values']['captcha_add_captcha_description']); // Save (or reset) the CAPTCHA descriptions. - if (module_exists('locale')) { + if (\Drupal::moduleHandler()->moduleExists('locale')) { $langs = language_list(); foreach ($langs as $lang_code => $lang_name) { $description = $form_state['values']["captcha_description_$lang_code"]; @@ -242,10 +243,10 @@ class CaptchaSettingsForm extends ConfigFormBase { * * @param array $form * Form structured array. - * @param array $form_state + * @param FormStateInterface $form_state * Form state strutured array. */ - public function captchaClearCaptchaPlacementCacheSubmit(array $form, array $form_state) { + public function captchaClearCaptchaPlacementCacheSubmit(array $form, FormStateInterface $form_state) { $this->state->delete('captcha_placement_map_cache'); drupal_set_message($this->t('Cleared the CAPTCHA placement cache.')); }