For coders TYPO3 Tech Corner

[PHP] Show the editor responsible for a page tree in the TYPO3 backend

[PHP] Show the editor responsible for a page tree in the TYPO3 backend

In the college and university sector in particular, it is important to indicate an editorially responsible person in the TYPO3 backend. You can contact them if you have any questions. You can easily add this function via your website package.

ext_tables.sql:

CREATE TABLE pages ( responsible_name varchar(255) DEFAULT '' NOT NULL, responsible_email varchar(255) DEFAULT '' NOT NULL, );

ext_localconf.php:

<?php defined('TYPO3_MODE') || die(); call_user_func( function () { /** * Show responsible person in backend page module */ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/db_layout.php']['drawHeaderHook'][] = \Unitue\Project\Hooks\PageModule::class . '->manipulate'; } );

PageModule.php:

<?php declare(strict_types=1); namespace Unitue\Project\Hooks; use TYPO3\CMS\Backend\Controller\PageLayoutController; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException; use TYPO3\CMS\Fluid\View\StandaloneView; use Unitue\Project\Utility\DatabaseUtility; use Unitue\Project\Utility\ObjectUtility; /** * Class PageModule */ class PageModule { /** * @var string */ protected $templatePathAndFile = 'EXT:project/Resources/Private/Templates/Hooks/ResponsiblePageModule.html'; /** * @param array $params * @param PageLayoutController $pageLayoutController * @return string * @throws InvalidExtensionNameException */ public function manipulate(array $params, PageLayoutController $pageLayoutController): string { unset($params); $pageIdentifier = $pageLayoutController->id; $properties = $this->getResponsiblePropertiesToPage($pageIdentifier); $properties = $properties + $this->getLastChangedPropertiesToPage($pageIdentifier); $properties = $properties + $this->getUserPropertiesToIdentifier($properties['userid']); return $this->renderMarkup($properties); } /** * @param int $pageIdentifier * @return array */ protected function getResponsiblePropertiesToPage(int $pageIdentifier): array { $properties = $this->getPropertiesToPage($pageIdentifier, ['responsible_name', 'responsible_email']); if (empty($properties['responsible_name']) && empty($properties['responsible_email'])) { $parentPageIdentifier = $this->getPropertiesToPage($pageIdentifier, ['pid'])['pid']; if ($parentPageIdentifier > 0) { $properties = $this->getResponsiblePropertiesToPage($parentPageIdentifier); } } return $properties; } /** * @param int $pageIdentifier * @param array $properties * @return array */ protected function getPropertiesToPage(int $pageIdentifier, array $properties): array { $queryBuilder = DatabaseUtility::getQueryBuilderForTable('pages', true); $rows = $queryBuilder ->select(...$properties) ->from('pages') ->where('uid=' . (int)$pageIdentifier) ->setMaxResults(1) ->execute() ->fetchAll(); return $rows[0]; } /** * @param int $pageIdentifier * @return array */ protected function getLastChangedPropertiesToPage(int $pageIdentifier): array { $contentElements = $this->getContentElementsToPage($pageIdentifier); $queryBuilder = DatabaseUtility::getQueryBuilderForTable('sys_log'); $rows = $queryBuilder ->select('userid', 'tstamp') ->from('sys_log') ->where('tablename="tt_content" and recuid in (' . implode(',', $contentElements) . ')') ->orderBy('tstamp', 'desc') ->setMaxResults(1) ->execute() ->fetchAll(); $properties = [ 'userid' => 0, 'tstamp' => 0 ]; if (!empty($rows[0])) { $properties = $rows[0]; } return $properties; } /** * @param int $userIdentifier * @return array */ protected function getUserPropertiesToIdentifier(int $userIdentifier): array { $queryBuilder = DatabaseUtility::getQueryBuilderForTable('be_users'); $rows = $queryBuilder ->select('username', 'realName', 'email') ->from('be_users') ->where('uid=' . (int)$userIdentifier) ->execute() ->fetchAll(); $properties = [ 'username' => '', 'realName' => '', 'email' => '' ]; if (!empty($rows[0])) { $properties = $rows[0]; } return $properties; } /** * @param int $pageIdentifier * @return array */ protected function getContentElementsToPage(int $pageIdentifier): array { $queryBuilder = DatabaseUtility::getQueryBuilderForTable('tt_content', true); $rows = $queryBuilder ->select('uid') ->from('tt_content') ->where('pid=' . (int)$pageIdentifier . ' and deleted=0') ->execute() ->fetchAll(); $contentElements = [0]; foreach ($rows as $row) { $contentElements[] = $row['uid']; } return $contentElements; } /** * @param array $properties * @return string * @throws InvalidExtensionNameException */ protected function renderMarkup(array $properties): string { /** @var StandaloneView $standaloneView */ $standaloneView = ObjectUtility::getObjectManager()->get(StandaloneView::class); $standaloneView->getRequest()->setControllerExtensionName('in2template'); $standaloneView->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName($this->templatePathAndFile)); $standaloneView->assignMultiple($properties); return $standaloneView->render(); } }

ResponsiblePageModule.html:

{namespace p=Unitue\Project\ViewHelpers} <f:if condition="{responsible_name} || {responsible_email}"> <div class="callout callout-warning"> <div class="media"> <div class="media-left"> <span class="fa-stack fa-lg callout-icon"> <i class="fa fa-circle fa-stack-2x"></i> <i class="fa fa-info fa-stack-1x"></i> </span> </div> <div class="media-body"> <h4 class="callout-title"> <f:translate key="LLL:EXT:project/Resources/Private/Language/Backend/locallang.xlf:pageModuleResponsible.responsiblename">Responsible</f:translate> </h4> <div class="callout-body"> <f:render section="ResponsibleName" arguments="{_all}" /> <f:render section="LastChange" arguments="{_all}" /> </div> </div> </div> </div> </f:if> <f:section name="ResponsibleName"> <p> <strong> <f:link.typolink parameter="{responsible_email}"> <f:if condition="{responsible_name}"> <f:then>{responsible_name}</f:then> <f:else>{responsible_email}</f:else> </f:if> </f:link.typolink> </strong> </p> </f:section> <f:section name="LastChange"> <f:if condition="{userid} > 0"> <p> <f:translate key="LLL:EXT:project/Resources/Private/Language/Backend/locallang.xlf:pageModuleResponsible.lastchangename">Last change</f:translate> <f:render section="UserName" arguments="{_all}" /> <span title="{f:format.date(format:'%d.%m.%Y %H:%M', date:'@{tstamp}')}">(<p:format.readableDate>{tstamp}</p:format.readableDate>)</span> </p> </f:if> </f:section> <f:section name="UserName"> <f:link.typolink parameter="{email}"> <f:if condition="{realName}"> <f:then>{realName}</f:then> <f:else>{username}</f:else> </f:if> </f:link.typolink> </f:section>

"Code faster, look at the time" - does this sound familiar to you?

How about time and respect for code quality? Working in a team? Automated tests?

Join us

SQL: Show all tables sorted by size in descending order

Lately I've been using the SQL command more often to find out which tables in the TYPO3 database are the largest. I've published the snippet once.

Go to news

TYPO3 12 with CKEditor 5: Styles in a single selection

If you set a link in the RTE in TYPO3, you may have to choose between different link classes, for example to create buttons in the frontend. What's new in TYPO3 12 is that you can select not just one...

Go to news

Null-Safe Operator in the TYPO3 area

With the introduction of PHP8, problems with undefined arrays or variables in general can arise in many places. Here are a few examples and simple solutions.

Go to news

Delete the first/last lines of a (SQL) file

There isn't much to say about the following commands. Sometimes it can be useful to delete the first (or last) X lines from a file. And if the file is too large to open with a conventional program, a...

Go to news

b13/container: Add and modify child elements in edit view

Unlike gridelements, you cannot manage the child elements in the B13 Container extension when you open the container in the editing view. I would be happy to show you how you can quickly install this...

Go to news

Menu comparison: Numbers, numbers, numbers

Go to news