From f8a5d9348e5e79ace8bfb626d59e4e54d62dbdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Mummert?= Date: Wed, 4 Mar 2026 16:43:05 +0100 Subject: [PATCH] Refine pinnwand backend behavior and fix frontend template rendering --- contao/config/services.yaml | 2 +- contao/dca/tl_pinnwand.php | 55 +++++++++++++++++-- contao/languages/de/modules.php | 4 +- .../FrontendModule/PinboardController.php | 12 ++-- .../PinboardTimestampListener.php | 33 ++++++----- templates/frontend_module/pinnwand.html.twig | 2 +- 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/contao/config/services.yaml b/contao/config/services.yaml index 1093f48..9c8664b 100644 --- a/contao/config/services.yaml +++ b/contao/config/services.yaml @@ -19,4 +19,4 @@ services: Eiswurm\ContaoPinboardBundle\EventListener\DataContainer\PinboardTimestampListener: tags: - - { name: contao.callback, table: tl_pinnwand, target: config.onsubmit } + - { name: contao.callback, table: tl_pinnwand, target: config.onbeforesubmit, method: onBeforeSubmit } diff --git a/contao/dca/tl_pinnwand.php b/contao/dca/tl_pinnwand.php index 28b3e7f..7c01156 100644 --- a/contao/dca/tl_pinnwand.php +++ b/contao/dca/tl_pinnwand.php @@ -2,6 +2,10 @@ declare(strict_types=1); +use Contao\DataContainer; +use Contao\Database; +use Contao\Input; + $GLOBALS['TL_DCA']['tl_pinnwand'] = [ 'config' => [ 'dataContainer' => Contao\DC_Table::class, @@ -22,8 +26,8 @@ $GLOBALS['TL_DCA']['tl_pinnwand'] = [ 'panelLayout' => 'filter;sort,search,limit', ], 'label' => [ - 'fields' => ['ueberschrift', 'dateAdded'], - 'format' => '%s [%s]', + 'fields' => ['ueberschrift', 'dateAdded', 'dateModified'], + 'showColumns' => true, ], 'global_operations' => [ 'all' => [ @@ -46,6 +50,10 @@ $GLOBALS['TL_DCA']['tl_pinnwand'] = [ 'icon' => 'delete.svg', 'attributes' => 'onclick="if(!confirm(\'' . ($GLOBALS['TL_LANG']['MSC']['deleteConfirm'] ?? 'Möchten Sie den Eintrag wirklich löschen?') . '\'))return false;Backend.getScrollOffset()"', ], + 'toggle' => [ + 'href' => 'act=toggle&field=published', + 'icon' => 'visible.svg', + ], 'show' => [ 'href' => 'act=show', 'icon' => 'show.svg', @@ -74,7 +82,7 @@ $GLOBALS['TL_DCA']['tl_pinnwand'] = [ 'exclude' => true, 'search' => true, 'inputType' => 'textarea', - 'eval' => ['mandatory' => true, 'maxlength' => 3000, 'rte' => 'tinyMCE', 'allowHtml' => true, 'tl_class' => 'clr'], + 'eval' => ['mandatory' => true, 'maxlength' => 3000, 'tl_class' => 'clr'], 'sql' => 'text NULL', ], 'link' => [ @@ -94,14 +102,14 @@ $GLOBALS['TL_DCA']['tl_pinnwand'] = [ 'sorting' => true, 'flag' => 6, 'inputType' => 'text', - 'eval' => ['rgxp' => 'datim', 'datepicker' => true, 'mandatory' => true, 'tl_class' => 'w50 wizard'], + 'eval' => ['rgxp' => 'datim', 'datepicker' => true, 'mandatory' => true, 'default' => time(), 'tl_class' => 'w50 wizard'], 'sql' => 'int(10) unsigned NOT NULL default 0', ], 'dateModified' => [ 'sorting' => true, 'flag' => 6, 'inputType' => 'text', - 'eval' => ['rgxp' => 'datim', 'readonly' => true, 'disabled' => true, 'tl_class' => 'w50'], + 'eval' => ['rgxp' => 'datim', 'readonly' => true, 'default' => time(), 'tl_class' => 'w50'], 'sql' => 'int(10) unsigned NOT NULL default 0', ], 'published' => [ @@ -122,3 +130,40 @@ $GLOBALS['TL_DCA']['tl_pinnwand'] = [ ], ], ]; + +$GLOBALS['TL_DCA']['tl_pinnwand']['fields']['ueberschrift']['save_callback'][] = static function (string $value, DataContainer $dataContainer): string { + if ('copy' !== Input::get('act')) { + return $value; + } + + $baseHeadline = trim($value); + + if ('' === $baseHeadline) { + return $value; + } + + $start = 2; + $base = $baseHeadline; + + if (preg_match('/^(.*)\s-\s(\d+)$/', $baseHeadline, $matches)) { + $base = trim($matches[1]); + $start = (int) $matches[2] + 1; + } + + $id = (int) ($dataContainer->id ?? 0); + $number = max(2, $start); + $candidate = sprintf('%s - %d', $base, $number); + + do { + $exists = Database::getInstance() + ->prepare('SELECT id FROM tl_pinnwand WHERE ueberschrift=? AND id!=?') + ->execute($candidate, $id); + + if ($exists->numRows < 1) { + return $candidate; + } + + ++$number; + $candidate = sprintf('%s - %d', $base, $number); + } while (true); +}; diff --git a/contao/languages/de/modules.php b/contao/languages/de/modules.php index 64b0bde..165fd43 100644 --- a/contao/languages/de/modules.php +++ b/contao/languages/de/modules.php @@ -2,5 +2,5 @@ declare(strict_types=1); -$GLOBALS['TL_LANG']['MOD']['pinnwand'] = ['Pinwand', 'Pinnwandeinträge verwalten']; -$GLOBALS['TL_LANG']['FMD']['pinnwand'] = ['Pinwand', 'Zeigt veröffentlichte Pinnwandeinträge als frei angeordnete Notizzettel an']; +$GLOBALS['TL_LANG']['MOD']['pinnwand'] = ['Pinnwand', 'Pinnwandeinträge verwalten']; +$GLOBALS['TL_LANG']['FMD']['pinnwand'] = ['Pinnwand', 'Zeigt veröffentlichte Pinnwandeinträge als frei angeordnete Notizzettel an']; diff --git a/src/Controller/FrontendModule/PinboardController.php b/src/Controller/FrontendModule/PinboardController.php index 1b94044..391d50b 100644 --- a/src/Controller/FrontendModule/PinboardController.php +++ b/src/Controller/FrontendModule/PinboardController.php @@ -5,16 +5,16 @@ declare(strict_types=1); namespace Eiswurm\ContaoPinboardBundle\Controller\FrontendModule; use Contao\CoreBundle\Controller\FrontendModule\AbstractFrontendModuleController; +use Contao\CoreBundle\Twig\FragmentTemplate; use Contao\FilesModel; use Contao\ModuleModel; -use Contao\Template; use Eiswurm\ContaoPinboardBundle\Model\PinboardModel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; final class PinboardController extends AbstractFrontendModuleController { - protected function getResponse(Template $template, ModuleModel $model, Request $request): Response + protected function getResponse(FragmentTemplate $template, ModuleModel $model, Request $request): Response { $collection = PinboardModel::findBy( ['published = ?'], @@ -46,9 +46,9 @@ final class PinboardController extends AbstractFrontendModuleController } } - return $this->render('@Contao/frontend_module/pinnwand.html.twig', [ - 'entries' => $notes, - 'module' => $model, - ]); + $template->set('entries', $notes); + $template->set('module', $model); + + return $template->getResponse(); } } diff --git a/src/EventListener/DataContainer/PinboardTimestampListener.php b/src/EventListener/DataContainer/PinboardTimestampListener.php index 355fa8a..b8a1adc 100644 --- a/src/EventListener/DataContainer/PinboardTimestampListener.php +++ b/src/EventListener/DataContainer/PinboardTimestampListener.php @@ -5,31 +5,30 @@ declare(strict_types=1); namespace Eiswurm\ContaoPinboardBundle\EventListener\DataContainer; use Contao\DataContainer; -use Contao\Database; +use Contao\Input; final class PinboardTimestampListener { - public function __invoke(DataContainer $dataContainer): void + /** + * @param array $values + * + * @return array + */ + public function onBeforeSubmit(array $values, DataContainer|null $dataContainer = null): array { - if (null === $dataContainer->id) { - return; - } - $timestamp = time(); + $isCopyAction = 'copy' === Input::get('act'); - $record = Database::getInstance() - ->prepare('SELECT dateAdded FROM tl_pinnwand WHERE id = ?') - ->limit(1) - ->execute($dataContainer->id); - - if (!$record->numRows) { - return; + if ($isCopyAction || empty($values['dateAdded'])) { + $values['dateAdded'] = $timestamp; } - $dateAdded = (int) $record->dateAdded; + if ($isCopyAction || empty($values['dateModified'])) { + $values['dateModified'] = $timestamp; + } - Database::getInstance() - ->prepare('UPDATE tl_pinnwand SET dateAdded = ?, dateModified = ?, tstamp = ? WHERE id = ?') - ->execute($dateAdded > 0 ? $dateAdded : $timestamp, $timestamp, $timestamp, $dataContainer->id); + $values['tstamp'] = $timestamp; + + return $values; } } diff --git a/templates/frontend_module/pinnwand.html.twig b/templates/frontend_module/pinnwand.html.twig index 9b6fb26..ecc713b 100644 --- a/templates/frontend_module/pinnwand.html.twig +++ b/templates/frontend_module/pinnwand.html.twig @@ -20,7 +20,7 @@ {% endif %}

{{ entry.headline }}

-
{{ entry.text|raw }}
+
{{ entry.text|e|nl2br }}
{% if entry.link %}