Skip to content

Commit 902f14f

Browse files
committed
312: Added OS2Forms handler interface for validating handler configurations
1 parent dfecb6f commit 902f14f

7 files changed

Lines changed: 191 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ before starting to add changes. Use example [placed in the end of the page](#exa
1111

1212
## [Unreleased]
1313

14+
- [PR-340](https://github.com/OS2Forms/os2forms/pull/340)
15+
- Added `OS2FormsHandlerInterface` for reporting misconfigured webform
16+
handlers on the webform build and handlers pages.
17+
- Implemented configuration validation for the Digital Post handler
18+
- Added empty options to the Digital Post handler element selects, so
19+
dangling element references no longer display as valid configuration.
20+
1421
## [5.1.0] 2026-06-03
1522

1623
- [PR-326](https://github.com/OS2Forms/os2forms/pull/326)

modules/os2forms_digital_post/os2forms_digital_post.info.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package: 'OS2Forms'
55
core_version_requirement: ^9 || ^10
66
dependencies:
77
- 'beskedfordeler:beskedfordeler'
8+
- 'os2forms:os2forms'
89
- 'drupal:advancedqueue'
910
- 'os2web_datalookup:os2web_datalookup'
1011
- 'os2web_key:os2web_key'

modules/os2forms_digital_post/src/Plugin/WebformHandler/WebformHandlerSF1601.php

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Drupal\os2forms_digital_post\Plugin\WebformHandler;
44

55
use Drupal\Core\Form\FormStateInterface;
6+
use Drupal\os2forms\Plugin\WebformHandler\OS2FormsHandlerInterface;
67
use Drupal\os2forms_digital_post\Helper\MeMoHelper;
78
use Drupal\os2forms_digital_post\Helper\WebformHelperSF1601;
89
use Drupal\webform\Plugin\WebformHandlerBase;
@@ -23,7 +24,7 @@
2324
* submission = \Drupal\webform\Plugin\WebformHandlerInterface::SUBMISSION_REQUIRED,
2425
* )
2526
*/
26-
final class WebformHandlerSF1601 extends WebformHandlerBase {
27+
final class WebformHandlerSF1601 extends WebformHandlerBase implements OS2FormsHandlerInterface {
2728
public const MEMO_MESSAGE = 'memo_message';
2829
public const MEMO_ACTIONS = 'memo_actions';
2930
public const TYPE = 'type';
@@ -110,6 +111,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $formStat
110111
'#required' => TRUE,
111112
'#default_value' => $this->configuration[self::MEMO_MESSAGE][static::RECIPIENT_ELEMENT] ?? NULL,
112113
'#options' => $availableElements,
114+
'#empty_option' => $this->t('- Select -'),
113115
];
114116

115117
$availableElements = $this->getAttachmentElements();
@@ -119,6 +121,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $formStat
119121
'#required' => TRUE,
120122
'#default_value' => $this->configuration[self::MEMO_MESSAGE][static::ATTACHMENT_ELEMENT] ?? NULL,
121123
'#options' => $availableElements,
124+
'#empty_option' => $this->t('- Select -'),
122125
];
123126

124127
$form[self::MEMO_MESSAGE][self::SENDER_LABEL] = [
@@ -264,6 +267,37 @@ static function (array $element) use ($elementTypes) {
264267
}, $elements);
265268
}
266269

270+
/**
271+
* {@inheritdoc}
272+
*
273+
* @phpstan-return array<int, mixed>
274+
*/
275+
public function validateConfiguration(): array {
276+
$problems = [];
277+
278+
$recipientElement = $this->configuration[self::MEMO_MESSAGE][static::RECIPIENT_ELEMENT] ?? NULL;
279+
if (NULL === $recipientElement || '' === $recipientElement) {
280+
$problems[] = $this->t('No recipient element is configured.');
281+
}
282+
elseif (!isset($this->getRecipientElements()[$recipientElement])) {
283+
$problems[] = $this->t('The recipient element (%element) does not exist or does not have a supported type.', [
284+
'%element' => $recipientElement,
285+
]);
286+
}
287+
288+
$attachmentElement = $this->configuration[self::MEMO_MESSAGE][static::ATTACHMENT_ELEMENT] ?? NULL;
289+
if (NULL === $attachmentElement || '' === $attachmentElement) {
290+
$problems[] = $this->t('No attachment element is configured.');
291+
}
292+
elseif (!isset($this->getAttachmentElements()[$attachmentElement])) {
293+
$problems[] = $this->t('The attachment element (%element) does not exist or does not have a supported type.', [
294+
'%element' => $attachmentElement,
295+
]);
296+
}
297+
298+
return $problems;
299+
}
300+
267301
/**
268302
* {@inheritdoc}
269303
*

os2forms.services.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
Drupal\os2forms\Helper\HandlerConfigurationValidator: ~
3+
4+
Drupal\os2forms\EventSubscriber\HandlerConfigurationValidationSubscriber:
5+
arguments:
6+
- "@Drupal\\os2forms\\Helper\\HandlerConfigurationValidator"
7+
- "@current_route_match"
8+
- "@messenger"
9+
tags:
10+
- { name: event_subscriber }
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Drupal\os2forms\EventSubscriber;
4+
5+
use Drupal\Core\Messenger\MessengerInterface;
6+
use Drupal\Core\Routing\RouteMatchInterface;
7+
use Drupal\Core\StringTranslation\StringTranslationTrait;
8+
use Drupal\os2forms\Helper\HandlerConfigurationValidator;
9+
use Drupal\webform\WebformInterface;
10+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
11+
use Symfony\Component\HttpKernel\Event\RequestEvent;
12+
use Symfony\Component\HttpKernel\KernelEvents;
13+
14+
/**
15+
* Reports misconfigured webform handlers on webform admin pages.
16+
*
17+
* @see \Drupal\os2forms\Plugin\WebformHandler\OS2FormsHandlerInterface
18+
*/
19+
class HandlerConfigurationValidationSubscriber implements EventSubscriberInterface {
20+
use StringTranslationTrait;
21+
22+
/**
23+
* Routes on which to report misconfigured handlers.
24+
*/
25+
private const ROUTE_NAMES = [
26+
// The webform build page (where elements are renamed or deleted).
27+
'entity.webform.edit_form',
28+
// The webform handlers page.
29+
'entity.webform.handlers',
30+
];
31+
32+
public function __construct(
33+
private readonly HandlerConfigurationValidator $validator,
34+
private readonly RouteMatchInterface $routeMatch,
35+
private readonly MessengerInterface $messenger,
36+
) {
37+
}
38+
39+
/**
40+
* Reports misconfigured webform handlers to the current user.
41+
*/
42+
public function onRequest(RequestEvent $event): void {
43+
if (!in_array($this->routeMatch->getRouteName(), self::ROUTE_NAMES, TRUE)) {
44+
return;
45+
}
46+
47+
$webform = $this->routeMatch->getParameter('webform');
48+
if (!$webform instanceof WebformInterface) {
49+
return;
50+
}
51+
52+
foreach ($this->validator->validate($webform) as $handlerId => $result) {
53+
foreach ($result['problems'] as $problem) {
54+
$this->messenger->addWarning($this->t('The handler @handler (@id) is misconfigured: @problem', [
55+
'@handler' => $result['label'],
56+
'@id' => $handlerId,
57+
'@problem' => $problem,
58+
]));
59+
}
60+
}
61+
}
62+
63+
/**
64+
* {@inheritdoc}
65+
*
66+
* @phpstan-return array<string, mixed>
67+
*/
68+
public static function getSubscribedEvents(): array {
69+
return [
70+
KernelEvents::REQUEST => ['onRequest'],
71+
];
72+
}
73+
74+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
namespace Drupal\os2forms\Helper;
4+
5+
use Drupal\os2forms\Plugin\WebformHandler\OS2FormsHandlerInterface;
6+
use Drupal\webform\WebformInterface;
7+
8+
/**
9+
* Validates configuration of webform handlers.
10+
*/
11+
class HandlerConfigurationValidator {
12+
13+
/**
14+
* Validates configuration of all handlers on a webform.
15+
*
16+
* @param \Drupal\webform\WebformInterface $webform
17+
* The webform.
18+
*
19+
* @return array
20+
* Problems keyed by handler ID. Each value is an array with two keys:
21+
* - label: the webform handler label
22+
* - problems: a list of problems (translatable markup)
23+
* Handlers without problems are not included.
24+
*
25+
* @phpstan-return array<string, mixed>
26+
*/
27+
public function validate(WebformInterface $webform): array {
28+
$problems = [];
29+
foreach ($webform->getHandlers() as $handler) {
30+
if ($handler instanceof OS2FormsHandlerInterface) {
31+
if ($handlerProblems = $handler->validateConfiguration()) {
32+
$problems[$handler->getHandlerId()] = [
33+
'label' => $handler->label(),
34+
'problems' => $handlerProblems,
35+
];
36+
}
37+
}
38+
}
39+
40+
return $problems;
41+
}
42+
43+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
namespace Drupal\os2forms\Plugin\WebformHandler;
4+
5+
/**
6+
* Interface for webform handlers that can validate their configuration.
7+
*/
8+
interface OS2FormsHandlerInterface {
9+
10+
/**
11+
* Validates the handler configuration against the current webform.
12+
*
13+
* @return \Drupal\Core\StringTranslation\TranslatableMarkup[]
14+
* A list of problems with the handler configuration. An empty list means
15+
* that the configuration is valid.
16+
*
17+
* @phpstan-return array<int, mixed>
18+
*/
19+
public function validateConfiguration(): array;
20+
21+
}

0 commit comments

Comments
 (0)