From bef53f36381acd6e4f13f32f3a4cc7a282ab9570 Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Fri, 30 Jan 2026 14:47:47 +0100 Subject: [PATCH 1/7] Add string length validation --- Classes/Domain/Factory/SuggestFormFactory.php | 19 +++++++++++++------ Configuration/TypoScript/setup.typoscript | 4 ++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Classes/Domain/Factory/SuggestFormFactory.php b/Classes/Domain/Factory/SuggestFormFactory.php index 51cc5b3..75f0330 100644 --- a/Classes/Domain/Factory/SuggestFormFactory.php +++ b/Classes/Domain/Factory/SuggestFormFactory.php @@ -44,11 +44,9 @@ public function __construct( public function build( array $configuration, - ?string $prototypeName = null, + ?string $prototypeName = 'standard', ?ServerRequestInterface $request = null ): FormDefinition { - $prototypeName = 'standard'; - $prototypeConfiguration = $this->formConfigurationService->getPrototypeConfiguration($prototypeName); $settings = $this->configurationManager->getConfiguration( @@ -186,9 +184,18 @@ public function build( 'elementDescription', $this->getLocalizedLabel($settings['suggest']['fields']['title']['description']) ); - /** @var NotEmptyValidator $titleValidator */ - $titleValidator = $this->validatorResolver->createValidator(NotEmptyValidator::class); - $titleField->addValidator($titleValidator); + $titleStringLengthValidatorOptions = ['minimum' => $settings['suggest']['fields']['title']['validation']['min'] ?? 1]; + if ($settings['suggest']['fields']['title']['validation']['max'] ?? false) { + $titleStringLengthValidatorOptions['maximum'] = (int)$settings['suggest']['fields']['title']['validation']['max']; + } + /** @var StringLengthValidator $titleStringLengthValidator */ + $titleStringLengthValidator = $this->validatorResolver->createValidator(StringLengthValidator::class, $titleStringLengthValidatorOptions); + $titleField->addValidator($titleStringLengthValidator); + if ($titleStringLengthValidatorOptions['minimum'] > 0) { + /** @var NotEmptyValidator $titleNotEmptyValidator */ + $titleNotEmptyValidator = $this->validatorResolver->createValidator(NotEmptyValidator::class); + $titleField->addValidator($titleNotEmptyValidator); + } /** @var GenericFormElement $descriptionField */ $descriptionField = $sessionInformation->createElement('description', 'Textarea'); diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index b976221..469f0c5 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -73,6 +73,10 @@ plugin.tx_sessionplaner { title { label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.title description = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.title.description + validation { + min = 1 + max = 255 + } } description { label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.description From abf00bcaf533dc653ab32e09ffba52c327f8b69d Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Mon, 2 Feb 2026 15:03:38 +0100 Subject: [PATCH 2/7] Add subtitle field --- Classes/Domain/Factory/SuggestFormFactory.php | 25 +++++++++++++++++++ .../Domain/Finisher/SuggestFormFinisher.php | 1 + Classes/Domain/Model/Session.php | 12 +++++++++ .../tx_sessionplaner_domain_model_session.php | 12 +++++++++ Configuration/TypoScript/setup.typoscript | 9 +++++++ Resources/Private/Language/locallang.xlf | 6 +++++ Resources/Private/Language/locallang_tca.xlf | 3 +++ Resources/Private/Templates/Session/Show.html | 5 ++++ Resources/Public/Stylesheets/frontend.css | 4 +-- ext_tables.sql | 1 + 10 files changed, 76 insertions(+), 2 deletions(-) diff --git a/Classes/Domain/Factory/SuggestFormFactory.php b/Classes/Domain/Factory/SuggestFormFactory.php index 75f0330..c87d653 100644 --- a/Classes/Domain/Factory/SuggestFormFactory.php +++ b/Classes/Domain/Factory/SuggestFormFactory.php @@ -197,6 +197,31 @@ public function build( $titleField->addValidator($titleNotEmptyValidator); } + if ((bool)($settings['suggest']['fields']['subtitle']['enable'] ?? false) === true) { + /** @var GenericFormElement $subtitleField */ + $subtitleField = $sessionInformation->createElement('subtitle', 'Text'); + $subtitleField->setLabel($this->getLocalizedLabel($settings['suggest']['fields']['subtitle']['label'])); + $subtitleField->setProperty( + 'elementDescription', + $this->getLocalizedLabel($settings['suggest']['fields']['subtitle']['description']) + ); + $subtitleStringLengthValidatorOptions = ['minimum' => $settings['suggest']['fields']['subtitle']['validation']['min'] ?? 1]; + if ($settings['suggest']['fields']['subtitle']['validation']['max'] ?? false) { + $subtitleStringLengthValidatorOptions['maximum'] = (int)$settings['suggest']['fields']['subtitle']['validation']['max']; + } + /** @var StringLengthValidator $subtitleStringLengthValidator */ + $subtitleStringLengthValidator = $this->validatorResolver->createValidator( + StringLengthValidator::class, + $subtitleStringLengthValidatorOptions + ); + $subtitleField->addValidator($subtitleStringLengthValidator); + if ($subtitleStringLengthValidatorOptions['minimum'] > 0) { + /** @var NotEmptyValidator $subtitleNotEmptyValidator */ + $subtitleNotEmptyValidator = $this->validatorResolver->createValidator(NotEmptyValidator::class); + $subtitleField->addValidator($subtitleNotEmptyValidator); + } + } + /** @var GenericFormElement $descriptionField */ $descriptionField = $sessionInformation->createElement('description', 'Textarea'); $descriptionField->setLabel($this->getLocalizedLabel($settings['suggest']['fields']['description']['label'])); diff --git a/Classes/Domain/Finisher/SuggestFormFinisher.php b/Classes/Domain/Finisher/SuggestFormFinisher.php index 8182f44..34dd8c4 100644 --- a/Classes/Domain/Finisher/SuggestFormFinisher.php +++ b/Classes/Domain/Finisher/SuggestFormFinisher.php @@ -70,6 +70,7 @@ protected function executeInternal() } $session->setTopic((string)($data['title'] ?? '')); + $session->setTopicAddition((string)($data['subtitle'] ?? '')); $session->setDescription((string)($data['description'] ?? '')); if (isset($data['type']) && $data['type'] !== '') { diff --git a/Classes/Domain/Model/Session.php b/Classes/Domain/Model/Session.php index badc9a0..cc3015a 100644 --- a/Classes/Domain/Model/Session.php +++ b/Classes/Domain/Model/Session.php @@ -35,6 +35,8 @@ class Session extends AbstractSlugEntity */ protected string $topic = ''; + protected string $topicAddition = ''; + protected string $pathSegment = ''; protected string $description = ''; @@ -146,6 +148,16 @@ public function getTopic(): string return $this->topic; } + public function setTopicAddition(string $topicAddition): void + { + $this->topicAddition = $topicAddition; + } + + public function getTopicAddition(): string + { + return $this->topicAddition; + } + public function setPathSegment(string $pathSegment): void { $this->pathSegment = $pathSegment; diff --git a/Configuration/TCA/tx_sessionplaner_domain_model_session.php b/Configuration/TCA/tx_sessionplaner_domain_model_session.php index 132eaff..2c8a97d 100644 --- a/Configuration/TCA/tx_sessionplaner_domain_model_session.php +++ b/Configuration/TCA/tx_sessionplaner_domain_model_session.php @@ -72,6 +72,17 @@ 'max' => 256, ], ], + 'topic_addition' => [ + 'exclude' => false, + 'label' => $languageFile . 'tx_sessionplaner_domain_model_session-topic_addition', + 'config' => [ + 'type' => 'input', + 'size' => 40, + 'eval' => 'trim', + 'required' => false, + 'max' => 256, + ], + ], 'path_segment' => [ 'exclude' => false, 'label' => $languageFile . 'tx_sessionplaner_domain_model_session-path_segment', @@ -341,6 +352,7 @@ --div--;General, --palette--;' . $languageFile . 'tx_sessionplaner_domain_model_session.palettes.options;options, topic, + topic_addition, path_segment, description, --palette--;' . $languageFile diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 469f0c5..7986009 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -78,6 +78,15 @@ plugin.tx_sessionplaner { max = 255 } } + subtitle { + enable = 0 + label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.subtitle + description = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.subtitle.description + validation { + min = 0 + max = 255 + } + } description { label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.description description = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.description.description diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index f163f33..09e6f93 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -209,6 +209,12 @@ A descriptive title for your submission + + Subtitle + + + A descriptive subtitle for your submission + Description diff --git a/Resources/Private/Language/locallang_tca.xlf b/Resources/Private/Language/locallang_tca.xlf index 65a84cd..f213bbb 100644 --- a/Resources/Private/Language/locallang_tca.xlf +++ b/Resources/Private/Language/locallang_tca.xlf @@ -135,6 +135,9 @@ Topic + + Topic Addition + Path Segment diff --git a/Resources/Private/Templates/Session/Show.html b/Resources/Private/Templates/Session/Show.html index fa714dc..3e7c16e 100644 --- a/Resources/Private/Templates/Session/Show.html +++ b/Resources/Private/Templates/Session/Show.html @@ -22,6 +22,11 @@

{session.topic}

+ +
+

{session.topicAddition}

+
+
diff --git a/Resources/Public/Stylesheets/frontend.css b/Resources/Public/Stylesheets/frontend.css index 259fba6..07119f8 100644 --- a/Resources/Public/Stylesheets/frontend.css +++ b/Resources/Public/Stylesheets/frontend.css @@ -54,7 +54,7 @@ border-radius: var(--session-tag-border-radius); } -.sessionplaner-tag-title { +.sessionplaner-tag-title, .sessionplaner-tag-subtitle { --session-tag-title-decoration-color: inherit; text-decoration-line: underline; text-decoration-thickness: 5px; @@ -730,4 +730,4 @@ width: 100%; } -/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fZ2VuZXJhbC5zY3NzIiwiZnJvbnRlbmQuY3NzIiwiLi4vLi4vLi4vQnVpbGQvU291cmNlcy9TYXNzL2Zyb250ZW5kL19kYXkuc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fdGFnLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3RyYWNrLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3Jvb20uc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fc2Vzc2lvbi5zY3NzIiwiLi4vLi4vLi4vQnVpbGQvU291cmNlcy9TYXNzL2Zyb250ZW5kL19zbG90LnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3NwZWFrZXIuc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fYmlvLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX2xpc3Quc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fY29ubmVjdC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0ksMkJBQUE7QUNDSjs7QUNJSTtFQUNJLGdCQUFBO0FERFI7O0FDSUE7RUFDSSxrQkFBQTtFQUNBLG1CQUFBO0FEREo7O0FDR0E7RUFDSSxlQUFBO0VBQ0EsZ0JBQUE7QURBSjs7QUNFQTtFQUNJLGNBQUE7QURDSjs7QUNDQTtFQUNJLGFBQUE7RUFDQSxlQUFBO0VBQ0EsYUFBQTtBREVKO0FDREk7RUFDSSxhQUFBO0VBQ0EsV0FBQTtBREdSO0FDRlE7RUFISjtJQUlRLFVBQUE7RURLVjtBQUNGOztBRTdCQTtFQUNJLGFBQUE7RUFDQSxlQUFBO0VBQ0EsUUFBQTtBRmdDSjs7QUU5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 */ \ No newline at end of file +/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fZ2VuZXJhbC5zY3NzIiwiZnJvbnRlbmQuY3NzIiwiLi4vLi4vLi4vQnVpbGQvU291cmNlcy9TYXNzL2Zyb250ZW5kL19kYXkuc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fdGFnLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3RyYWNrLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3Jvb20uc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fc2Vzc2lvbi5zY3NzIiwiLi4vLi4vLi4vQnVpbGQvU291cmNlcy9TYXNzL2Zyb250ZW5kL19zbG90LnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX3NwZWFrZXIuc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fYmlvLnNjc3MiLCIuLi8uLi8uLi9CdWlsZC9Tb3VyY2VzL1Nhc3MvZnJvbnRlbmQvX2xpc3Quc2NzcyIsIi4uLy4uLy4uL0J1aWxkL1NvdXJjZXMvU2Fzcy9mcm9udGVuZC9fY29ubmVjdC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0ksMkJBQUE7QUNDSjs7QUNJSTtFQUNJLGdCQUFBO0FERFI7O0FDSUE7RUFDSSxrQkFBQTtFQUNBLG1CQUFBO0FEREo7O0FDR0E7RUFDSSxlQUFBO0VBQ0EsZ0JBQUE7QURBSjs7QUNFQTtFQUNJLGNBQUE7QURDSjs7QUNDQTtFQUNJLGFBQUE7RUFDQSxlQUFBO0VBQ0EsYUFBQTtBREVKO0FDREk7RUFDSSxhQUFBO0VBQ0EsV0FBQTtBREdSO0FDRlE7RUFISjtJQUlRLFVBQUE7RURLVjtBQUNGOztBRTdCQTtFQUNJLGFBQUE7RUFDQSxlQUFBO0VBQ0EsUUFBQTtBRmdDSjs7QUU5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 */ diff --git a/ext_tables.sql b/ext_tables.sql index 72c9a2a..dfbe165 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -45,6 +45,7 @@ CREATE TABLE tx_sessionplaner_domain_model_slot CREATE TABLE tx_sessionplaner_domain_model_session ( topic varchar (255) DEFAULT '' NOT NULL, + topic_addition varchar (255) DEFAULT '' NOT NULL, path_segment varchar(2048), speaker varchar(255) DEFAULT '' NOT NULL, twitter varchar(255) DEFAULT '' NOT NULL, From 17bbab1b8e85c89efd8b020f5909462baccb14b9 Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Mon, 2 Feb 2026 16:50:24 +0100 Subject: [PATCH 3/7] Add tag suggestion field --- Classes/Domain/Factory/SuggestFormFactory.php | 25 +++++++++++++++++++ .../Domain/Finisher/SuggestFormFinisher.php | 1 + Classes/Domain/Model/Session.php | 12 +++++++++ .../tx_sessionplaner_domain_model_session.php | 11 ++++++++ Configuration/TypoScript/setup.typoscript | 9 +++++++ Resources/Private/Language/locallang.xlf | 6 +++++ Resources/Private/Language/locallang_tca.xlf | 3 +++ ext_tables.sql | 1 + 8 files changed, 68 insertions(+) diff --git a/Classes/Domain/Factory/SuggestFormFactory.php b/Classes/Domain/Factory/SuggestFormFactory.php index c87d653..332e068 100644 --- a/Classes/Domain/Factory/SuggestFormFactory.php +++ b/Classes/Domain/Factory/SuggestFormFactory.php @@ -240,6 +240,31 @@ public function build( ); $descriptionField->addValidator($stringLengthValidator); + if ((bool)($settings['suggest']['fields']['tag_suggestion']['enable'] ?? false) === true) { + /** @var GenericFormElement $tagSuggestionField */ + $tagSuggestionField = $sessionInformation->createElement('tag_suggestion', 'Text'); + $tagSuggestionField->setLabel($this->getLocalizedLabel($settings['suggest']['fields']['tag_suggestion']['label'])); + $tagSuggestionField->setProperty( + 'elementDescription', + $this->getLocalizedLabel($settings['suggest']['fields']['tag_suggestion']['description']) + ); + $tagSuggestionStringLengthValidatorOptions = ['minimum' => $settings['suggest']['fields']['tag_suggestion']['validation']['min'] ?? 1]; + if ($settings['suggest']['fields']['tag_suggestion']['validation']['max'] ?? false) { + $tagSuggestionStringLengthValidatorOptions['maximum'] = (int)$settings['suggest']['fields']['tag_suggestion']['validation']['max']; + } + /** @var StringLengthValidator $tagSuggestionStringLengthValidator */ + $tagSuggestionStringLengthValidator = $this->validatorResolver->createValidator( + StringLengthValidator::class, + $tagSuggestionStringLengthValidatorOptions + ); + $tagSuggestionField->addValidator($tagSuggestionStringLengthValidator); + if ($tagSuggestionStringLengthValidatorOptions['minimum'] > 0) { + /** @var NotEmptyValidator $tagSuggestionNotEmptyValidator */ + $tagSuggestionNotEmptyValidator = $this->validatorResolver->createValidator(NotEmptyValidator::class); + $tagSuggestionField->addValidator($tagSuggestionNotEmptyValidator); + } + } + if ((bool)($settings['suggest']['fields']['length']['enable'] ?? false) === true) { /** @var GenericFormElement $lengthField */ $lengthField = $sessionInformation->createElement('estimatedlength', 'SingleSelect'); diff --git a/Classes/Domain/Finisher/SuggestFormFinisher.php b/Classes/Domain/Finisher/SuggestFormFinisher.php index 34dd8c4..f8412ff 100644 --- a/Classes/Domain/Finisher/SuggestFormFinisher.php +++ b/Classes/Domain/Finisher/SuggestFormFinisher.php @@ -72,6 +72,7 @@ protected function executeInternal() $session->setTopic((string)($data['title'] ?? '')); $session->setTopicAddition((string)($data['subtitle'] ?? '')); $session->setDescription((string)($data['description'] ?? '')); + $session->setTagSuggestion((string)($data['tag_suggestion'] ?? '')); if (isset($data['type']) && $data['type'] !== '') { $session->setType((int)$data['type']); diff --git a/Classes/Domain/Model/Session.php b/Classes/Domain/Model/Session.php index cc3015a..8d07b9c 100644 --- a/Classes/Domain/Model/Session.php +++ b/Classes/Domain/Model/Session.php @@ -41,6 +41,8 @@ class Session extends AbstractSlugEntity protected string $description = ''; + protected string $tagSuggestion = ''; + protected string $speaker = ''; protected string $twitter = ''; @@ -178,6 +180,16 @@ public function getDescription(): string return $this->description; } + public function setTagSuggestion(string $tagSuggestion): void + { + $this->tagSuggestion = $tagSuggestion; + } + + public function getTagSuggestion(): string + { + return $this->tagSuggestion; + } + public function addSpeaker(Speaker $speaker): void { $this->speakers->attach($speaker); diff --git a/Configuration/TCA/tx_sessionplaner_domain_model_session.php b/Configuration/TCA/tx_sessionplaner_domain_model_session.php index 2c8a97d..3598214 100644 --- a/Configuration/TCA/tx_sessionplaner_domain_model_session.php +++ b/Configuration/TCA/tx_sessionplaner_domain_model_session.php @@ -167,6 +167,17 @@ 'richtextConfiguration' => 'default', ], ], + 'tag_suggestion' => [ + 'exclude' => false, + 'label' => $languageFile . 'tx_sessionplaner_domain_model_session-tag_suggestion', + 'config' => [ + 'type' => 'input', + 'size' => 40, + 'eval' => 'trim', + 'required' => false, + 'max' => 256, + ], + ], 'documents' => [ 'exclude' => false, 'label' => $languageFile . 'tx_sessionplaner_domain_model_session-download', diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 7986009..9f4c5c9 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -87,6 +87,15 @@ plugin.tx_sessionplaner { max = 255 } } + tag_suggestion { + enable = 0 + label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.tag_suggestion + description = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.tag_suggestion.description + validation { + min = 0 + max = 255 + } + } description { label = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.description description = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.description.description diff --git a/Resources/Private/Language/locallang.xlf b/Resources/Private/Language/locallang.xlf index 09e6f93..f4ae8bd 100644 --- a/Resources/Private/Language/locallang.xlf +++ b/Resources/Private/Language/locallang.xlf @@ -221,6 +221,12 @@ A description of your submission + + Tag Suggestion + + + A descriptive tag you would add to your submission + Type diff --git a/Resources/Private/Language/locallang_tca.xlf b/Resources/Private/Language/locallang_tca.xlf index f213bbb..b25e77f 100644 --- a/Resources/Private/Language/locallang_tca.xlf +++ b/Resources/Private/Language/locallang_tca.xlf @@ -132,6 +132,9 @@ Do not link + + Tag Suggestion + Topic diff --git a/ext_tables.sql b/ext_tables.sql index dfbe165..401797f 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -58,6 +58,7 @@ CREATE TABLE tx_sessionplaner_domain_model_session requesttype int(11) unsigned DEFAULT '0' NOT NULL, norecording tinyint(4) unsigned DEFAULT '0' NOT NULL, description text, + tag_suggestion varchar (255) DEFAULT '' NOT NULL, # references speakers int(11) unsigned DEFAULT '0' NOT NULL, From 0503c5cd3e33d4e4ce0a42e50fabd8ad3c083eb6 Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Tue, 3 Feb 2026 09:22:20 +0100 Subject: [PATCH 4/7] Add email to sender finisher --- Classes/Domain/Factory/SuggestFormFactory.php | 43 ++++++++++++++-- Configuration/TypoScript/constants.typoscript | 11 +++++ Configuration/TypoScript/setup.typoscript | 6 +++ .../Templates/Email/EmailToSender.html | 49 +++++++++++++++++++ .../Private/Templates/Email/EmailToSender.txt | 18 +++++++ 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 Resources/Private/Templates/Email/EmailToSender.html create mode 100644 Resources/Private/Templates/Email/EmailToSender.txt diff --git a/Classes/Domain/Factory/SuggestFormFactory.php b/Classes/Domain/Factory/SuggestFormFactory.php index 332e068..ef7dd04 100644 --- a/Classes/Domain/Factory/SuggestFormFactory.php +++ b/Classes/Domain/Factory/SuggestFormFactory.php @@ -344,15 +344,38 @@ public function build( ]); } + $message = $settings['suggest']['confirmation']['message'] ?? + 'LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.suggest.confirmation'; + $confirmationMessage = LocalizationUtility::translate($message) ?? ''; + + if ($this->sendingSenderNotificationAllowed($settings)) { + $form->createFinisher('EmailToSender', [ + 'subject' => $settings['suggest']['senderNotification']['subject'], + 'recipients' => [ + '{email}' => '{fullname}', + ], + 'senderAddress' => $settings['suggest']['senderNotification']['senderAddress'], + 'senderName' => $settings['suggest']['senderNotification']['senderName'], + 'format' => 'html', + 'headline' => $settings['suggest']['senderNotification']['subject'], + 'variables' => [ + 'title' => $settings['suggest']['senderNotification']['subject'], + 'message' => $confirmationMessage, + ], + 'templateName' => 'EmailToSender', + 'templateRootPaths' => [ + 100 => 'EXT:sessionplaner/Resources/Private/Templates/Email/' + ], + ]); + } + if (($settings['suggest']['confirmation']['pageUid'] ?? '') !== '') { $form->createFinisher('Redirect', [ 'pageUid' => (int)$settings['suggest']['confirmation']['pageUid'], ]); } else { - $message = $settings['suggest']['confirmation']['message'] ?? - 'LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.suggest.confirmation'; $form->createFinisher('Confirmation', [ - 'message' => LocalizationUtility::translate($message) ?? '', + 'message' => $confirmationMessage, ]); } @@ -378,6 +401,20 @@ protected function sendingNotificationAllowed(array $settings): bool && $settings['suggest']['notification']['senderName'] !== ''; } + protected function sendingSenderNotificationAllowed(array $settings): bool + { + return isset( + $settings['suggest']['senderNotification']['enable'], + $settings['suggest']['senderNotification']['subject'], + $settings['suggest']['senderNotification']['senderAddress'], + $settings['suggest']['senderNotification']['senderName'] + ) + && (bool)$settings['suggest']['senderNotification']['enable'] === true + && $settings['suggest']['senderNotification']['subject'] !== '' + && $settings['suggest']['senderNotification']['senderAddress'] !== '' + && $settings['suggest']['senderNotification']['senderName'] !== ''; + } + protected function getLocalizedLabel(string $label): string { if (strncmp($label, 'LLL:', 4) === 0) { diff --git a/Configuration/TypoScript/constants.typoscript b/Configuration/TypoScript/constants.typoscript index ec54a92..6f8fe4c 100644 --- a/Configuration/TypoScript/constants.typoscript +++ b/Configuration/TypoScript/constants.typoscript @@ -2,6 +2,7 @@ # customsubcategory=110_SPPERSISTENCE=Persistence # customsubcategory=120_SPSETTINGS=Settings # customsubcategory=130_SPSUGGESTMAIL=Suggest Notifications +# customsubcategory=135_SPSUGGESTSENDERMAIL=Suggest Notifications to Sender # customsubcategory=140_SPSUGGESTCONFIRMATION=Suggest Confirmation plugin.tx_sessionplaner { @@ -48,6 +49,16 @@ plugin.tx_sessionplaner { # cat=plugin.sessionplaner/130_SPSUGGESTMAIL/blindCarbonCopyAddress; type=string; label=Blind Carbon Copy Address blindCarbonCopyAddress = } + senderNotification { + # cat=plugin.sessionplaner/135_SPSUGGESTSENDERMAIL/enable; type=boolean; label=Enable + enable = 0 + # cat=plugin.sessionplaner/135_SPSUGGESTSENDERMAIL/subject; type=string; label=Subject + subject = Thank you for your suggestion + # cat=plugin.sessionplaner/135_SPSUGGESTSENDERMAIL/senderAddress; type=string; label=Sender Address + senderAddress = + # cat=plugin.sessionplaner/135_SPSUGGESTSENDERMAIL/senderName; type=string; label=Sender Name + senderName = + } confirmation { # cat=plugin.sessionplaner/140_SPSUGGESTCONFIRMATION/message; type=string; label=Confirmation Message message = LLL:EXT:sessionplaner/Resources/Private/Language/locallang.xlf:form.suggest.confirmation diff --git a/Configuration/TypoScript/setup.typoscript b/Configuration/TypoScript/setup.typoscript index 9f4c5c9..fe037a4 100644 --- a/Configuration/TypoScript/setup.typoscript +++ b/Configuration/TypoScript/setup.typoscript @@ -127,6 +127,12 @@ plugin.tx_sessionplaner { carbonCopyAddress = {$plugin.tx_sessionplaner.settings.suggest.notification.carbonCopyAddress} blindCarbonCopyAddress = {$plugin.tx_sessionplaner.settings.suggest.notification.blindCarbonCopyAddress} } + senderNotification { + enable = {$plugin.tx_sessionplaner.settings.suggest.senderNotification.enable} + subject = {$plugin.tx_sessionplaner.settings.suggest.senderNotification.subject} + senderAddress = {$plugin.tx_sessionplaner.settings.suggest.senderNotification.senderAddress} + senderName = {$plugin.tx_sessionplaner.settings.suggest.senderNotification.senderName} + } confirmation { message = {$plugin.tx_sessionplaner.settings.suggest.confirmation.message} pageUid = {$plugin.tx_sessionplaner.settings.suggest.confirmation.pageUid} diff --git a/Resources/Private/Templates/Email/EmailToSender.html b/Resources/Private/Templates/Email/EmailToSender.html new file mode 100644 index 0000000..e068f83 --- /dev/null +++ b/Resources/Private/Templates/Email/EmailToSender.html @@ -0,0 +1,49 @@ + +{title} + + +

{message}

+
+
+ + + + + + + + + + + + + + +
{formvh:translateElementProperty(element: formValue.element, property: 'label')}{formvh:translateElementProperty(element: formValue.element, property: 'label')} + + + + + + + + + + +
{value}
+
+ + + + + +
{formValue.processedValue}
+
+
+
+ + - + +
+
+
diff --git a/Resources/Private/Templates/Email/EmailToSender.txt b/Resources/Private/Templates/Email/EmailToSender.txt new file mode 100644 index 0000000..9f69bb5 --- /dev/null +++ b/Resources/Private/Templates/Email/EmailToSender.txt @@ -0,0 +1,18 @@ + +{title} + +{message} + + + + + *** ***: - {singleValue} + + + + *** ***: {formValue.processedValue -> f:format.raw()}- + + + + + From 4cefbc4e44998bf020a9c807134a62632cc37a94 Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Tue, 3 Feb 2026 09:39:10 +0100 Subject: [PATCH 5/7] Add tag suggestion to showitems --- Configuration/TCA/tx_sessionplaner_domain_model_session.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Configuration/TCA/tx_sessionplaner_domain_model_session.php b/Configuration/TCA/tx_sessionplaner_domain_model_session.php index 3598214..ebf3452 100644 --- a/Configuration/TCA/tx_sessionplaner_domain_model_session.php +++ b/Configuration/TCA/tx_sessionplaner_domain_model_session.php @@ -379,6 +379,7 @@ day, room, slot, + tag_suggestion, tags, ', ], From 70f466609c111c94a95514ad75e5b526be8c5fcd Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Tue, 3 Feb 2026 09:43:52 +0100 Subject: [PATCH 6/7] Fix indentation --- ext_tables.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext_tables.sql b/ext_tables.sql index 401797f..483cbb2 100644 --- a/ext_tables.sql +++ b/ext_tables.sql @@ -45,7 +45,7 @@ CREATE TABLE tx_sessionplaner_domain_model_slot CREATE TABLE tx_sessionplaner_domain_model_session ( topic varchar (255) DEFAULT '' NOT NULL, - topic_addition varchar (255) DEFAULT '' NOT NULL, + topic_addition varchar (255) DEFAULT '' NOT NULL, path_segment varchar(2048), speaker varchar(255) DEFAULT '' NOT NULL, twitter varchar(255) DEFAULT '' NOT NULL, @@ -58,7 +58,7 @@ CREATE TABLE tx_sessionplaner_domain_model_session requesttype int(11) unsigned DEFAULT '0' NOT NULL, norecording tinyint(4) unsigned DEFAULT '0' NOT NULL, description text, - tag_suggestion varchar (255) DEFAULT '' NOT NULL, + tag_suggestion varchar (255) DEFAULT '' NOT NULL, # references speakers int(11) unsigned DEFAULT '0' NOT NULL, From e33a743b7277d58bc9b41fbe6d63b43a4beac44f Mon Sep 17 00:00:00 2001 From: Marvin Buchmann Date: Tue, 3 Feb 2026 10:46:25 +0100 Subject: [PATCH 7/7] Revert drive-by --- Classes/Domain/Factory/SuggestFormFactory.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/Domain/Factory/SuggestFormFactory.php b/Classes/Domain/Factory/SuggestFormFactory.php index ef7dd04..71a7679 100644 --- a/Classes/Domain/Factory/SuggestFormFactory.php +++ b/Classes/Domain/Factory/SuggestFormFactory.php @@ -44,9 +44,11 @@ public function __construct( public function build( array $configuration, - ?string $prototypeName = 'standard', + ?string $prototypeName = null, ?ServerRequestInterface $request = null ): FormDefinition { + $prototypeName = 'standard'; + $prototypeConfiguration = $this->formConfigurationService->getPrototypeConfiguration($prototypeName); $settings = $this->configurationManager->getConfiguration(