Erstellung eines Newsletters durch Frontend-Benutzer
Luxletter im Einsatz
Die TYPO3-Extension luxletter dient als hervorragende Basis zur Erstellung von Newslettern durch Redakteure im Backend. Für das Intranet der Hochschülerinnen- & Hochschülerschaft der FH Oberösterreich bestand die Anforderung darin dass eingeloggte Benutzer im Frontend einen Newsletter erstellen können.
Die folgenden Codebeispiele zeigen wie eine eine Extension erweitert werden kann, sodass ein Benutzer einen Newsletter erstellen kann. Die einzelnen Schritte sind:
- formAction: Der Newsletter wird zusammengestellt. Es müssen Betreff, Text und gewünschten Zielgruppen ausgefüllt werden.
- sendAction: Ein Newsletter-Datensatz wird erstellt
- Das QueueService wird genutzt um pro Empfänger einen Eintrag in der Queue-Tabelle zu generieren.
- Im ParseMailTextSlot werden eigene Variablen ersetzt.
MailController
Der folgende Code zeigt einen Auszug aus dem Controller auf Basis von Extbase mit den beiden Actions index und send.
- Die Konfiguration ($configuration) ist ein einmalig zu erstellender Datensatz der Einstellungen wie Absenderinformationen beinhaltet.
- Für jede Zielbenutzergruppe wird ein eigener Newsletter-Datensatz erstellt
<?php
declare(strict_types=1);
namespace StudioMitte\Intranet\Controller;
use In2code\Luxletter\Domain\Model\Newsletter;
use In2code\Luxletter\Domain\Model\Usergroup;
use In2code\Luxletter\Domain\Repository\ConfigurationRepository;
use In2code\Luxletter\Domain\Repository\NewsletterRepository;
use In2code\Luxletter\Domain\Repository\UsergroupRepository;
use StudioMitte\Intranet\Domain\Model\Dto\Mail;
use StudioMitte\Intranet\Service\QueueService;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class MailController extends ActionController
{
protected NewsletterRepository $newsletterRepository;
protected UsergroupRepository $usergroupRepository;
protected ConfigurationRepository $configurationRepository;
protected QueueService $queueService;
public function indexAction(): void
{
$mail = new Mail();
$this->view->assignMultiple([
'mail' => $mail,
'groups' => $this->mailRepository->getAllowedNewsletterGroups()
]);
}
public function sendAction(Mail $mail): void
{
$configuration = $this->configurationRepository->findByIdentifier($mail->getConfiguration());
foreach ($mail->getGroups() as $usergroupId => $usergroupName) {
/** @var Usergroup $usergroup */
$usergroup = $this->usergroupRepository->findByIdentifier($usergroupId);
$newsletter = new Newsletter();
$newsletter
->setTitle(sprintf('%s => %s', $mail->getSubject(), $usergroupName))
->setSubject($mail->getSubject())
->setBodytext($mail->getText())
->setConfiguration($configuration)
->setReceiver($usergroup);
$this->newsletterRepository->add($newsletter);
$this->newsletterRepository->persistAll();
$this->queueService->fillQueue($newsletter->getUid(), $usergroupId);
}
$this->redirect('success');
}
}
QueueService
Luxletter selbst bietet ein ähnliches Service an, das aber mit Objekten auf Basis von Extbase arbeitet und daher um einiges langsamer ist. Sind nur wenige Abonennten vorhanden, kann auch auf dieses zurückgegriffen werden.
<?php
declare(strict_types=1);
namespace StudioMitte\Intranet\Service;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class QueueService
{
protected int $pageId;
public function __construct($pageId)
{
$this->pageId = $pageId;
}
public function fillQueue(int $newsletterId, int $usergroupId): int
{
$connection = $this->getConnectionFor('tx_luxletter_domain_model_queue');
$users = $this->getUserByGroup($usergroupId);
$items = [];
foreach ($users as $user) {
$items[] = [
'pid' => $this->pageId,
'crdate' => time(),
'tstamp' => time(),
'user' => $user['uid'],
'email' => $user['email'],
'newsletter' => $newsletterId,
'datetime' => time()
];
}
return $connection->bulkInsert('tx_luxletter_domain_model_queue', $items, array_keys($items[0]));
}
protected function getUserByGroup(int $usergroupId)
{
$queryBuilder = $this->getConnectionFor('fe_users')->createQueryBuilder();
return $queryBuilder
->select('uid', 'email')
->from('fe_users')
->where(
$queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($this->pageId, \PDO::PARAM_INT)),
$queryBuilder->expr()->eq('usergroup', $queryBuilder->createNamedParameter($usergroupId, \PDO::PARAM_STR))
)
->execute()
->fetchAll();
}
protected function getConnectionFor(string $tableName): Connection
{
return GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($tableName);
}
}
ParseMailTextSlot
Signals & Slots werden genutzt um Änderungen durch zusätzliche Extensions durchzuführen. Ein Signal von luxletter kann dazu genutzt werden, um den Text des Newsletters vor dem Versand zu ändern. In diesem Beispiel werden folgende Anpassungen vorgenommen:
- Um den RedakteurInnen die Verwendung von Variablen zu vereinfachen, gibt es Variablen wie #name# die mit dem Namen des Empfängers ersetzt werden
- Der selbst erstellte Inhalt wird in ein für Newsletter optimiertes HTML gefüllt
<?php
declare(strict_types=1);
namespace StudioMitte\Intranet\Slots\Luxletter;
use In2code\Luxletter\Domain\Service\ParseNewsletterService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FrontendUser;
use TYPO3\CMS\Fluid\View\StandaloneView;
class ParseMailTextSlot
{
public function parseMailText(string &$string, array $properties, ParseNewsletterService $parseNewsletterService)
{
if (strpos($string, LF) !== false) {
$string = $this->modifyBodytext($string, $properties);
}
}
protected function modifyBodytext(string $text, array $properties)
{
/** @var FrontendUser $user */
$user = $properties['user'];
$searchReplace = [
'#name#' => $this->getName($user),
LF => LF . '<br />'
];
$text = str_replace(array_keys($searchReplace), array_values($searchReplace), $text);
$text = $this->wrapContentIntoHtmlTemplate($text);
return $text;
}
protected function wrapContentIntoHtmlTemplate(string $content): string
{
$standaloneView = GeneralUtility::makeInstance(StandaloneView::class);
$standaloneView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:intranet/Resources/Private/Templates/Emails/LuxNewsletter.html'));
$standaloneView->assign('content', $content);
return $standaloneView->render();
}
protected function getName(FrontendUser $user): string
{
$items = [$user->getTitle(), $user->getFirstName(), $user->getLastName()];
return implode(' ', array_filter($items));
}
}