Vor TYPO9 war es zwar nicht einfacher, den Titel des eigenen Datensatzes in der Breadcrumb (oder auch Rootline) Navigation anzuzeigen, aber es gab Beispiele wie Sand am Meer. Falls man nun bei der Generierung der Menüs auf Data Processoren setzt, dann findet man (also ich per Google) einige Anfragen in Foren, jedoch keine gute Anleitung. Und wie immer in solchen Fällen schaue ich in die Extension news, die mir schon so häufig weitergeholfen hat. Diese Extension ist einfach auf dem neuesten Stand und wenn man mal nicht weiter weiß, dann lohnt sich immer ein Blick in diese Extension. Danke Georg!
Das ist eine kleine Anleitung, wie man die Breadcrumb um den Titel der eigenen Datensätze bereichert. Jede Extension ist anders implementiert, daher ist das nicht als Copy&Paste einfach verwendbar.
Als erstes muss man einen Data Processor anlegen, das kann entweder in der Extension sein, deren Datensätze man anzapft oder in einer anderen. In diesem Beispiel lege ich die Datei AddRecordToMenuProcessor.php an im Unterordner Classes/DataProcessing.
Irgendwo in TypoScript hat man nun die Page-Definition, die an irgendeiner Stelle so aussieht:
page.10 = FLUIDTEMPLATE page.10 { dataProcessing { [...] 30 = TYPO3\CMS\Frontend\DataProcessing\MenuProcessor 30 { special = rootline special.range = 0|-1 includeNotInMenu = 1 as = menuBreadcrumb } } }
Hinter die vorhandenen Data Processoren wird nun ein eigener angehängt:
page.10 = FLUIDTEMPLATE page.10 { dataProcessing { [...] 40 = Vendor\MyExtension\DataProcessing\AddRecordToMenuProcessor 40.menus = menuBreadcrumb } }
Nun arbeitet man in der angelegten Datei weiter.
namespace Vendor\MyExtension\DataProcessing; use TYPO3\CMS\Core\Utility\ExtensionManagementUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Object\ObjectManager; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface; class AddRecordToMenuProcessor implements DataProcessorInterface { /** * @param ContentObjectRenderer $cObj * @param array $contentObjectConfiguration * @param array $processorConfiguration * @param array $processedData * @return array */ public function process( ContentObjectRenderer $cObj, array $contentObjectConfiguration, array $processorConfiguration, array $processedData ) { if (!$processorConfiguration['menus']) { return $processedData; } if (!ExtensionManagementUtility::isLoaded('my_record_extension')) { return $processedData; } $record = $this->getRecord(); if ($record) { $menus = GeneralUtility::trimExplode(',', $processorConfiguration['menus'], true); foreach ($menus as $menu) { if (isset($processedData[$menu])) { $this->addRecordToMenu($record, $processedData[$menu]); } } } return $processedData; } public function addRecordToMenu($record, array &$menu) { // remove last element array_pop($menu); $menu[] = [ 'data' => $record, 'title' => $record['name'], 'active' => 1, 'current' => 1, 'link' => GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), 'isRecord' => true ]; } /** * @return array */ public function getRecord() { $vars = GeneralUtility::_GET('tx_myrecordextension_pluginname'); if(!isset($vars['record']) { return; } $recordUid = (int)$vars['record']; $objectManager = GeneralUtility::makeInstance(ObjectManager::class); $recordRepository = $objectManager->get(Vendor\MyRecordExtension\RecordRepository::class); $record = $recordRepository->findByUid($recordUid); $fields = ['name', 'title', 'email', 'phone']; $recordAsArray = []; foreach ($fields as $field) { $recordAsArray[$field] = $record->_getProperty($field); } return $recordAsArray; } }
Die Funktion process ist notwendig, da man das Interface DataProcessorInterface implementiert. In meinem Fall hab ich den Data Processor in eine andere Extension packen müssen und daher brauche ich die Abfrage, ob die Extension geladen ist (Zeile 28). Ansonsten kann man sich das sparen.
Es wird versucht einen Datensatz der Extension zu holen und falls es funktioniert, wird das Menü um einen Eintrag mit den Daten des Datensatzes erweitert.
In der Funktion getRecord wird der Datesatz geholt. Georg nutzt in seiner news-Extension einen anderen Ansatz: nämlich mit ConnectionPool und QueryBuilder. Es hat den Vorteil, dass man ein Array und nicht wie in meinem Fall ein Object zurückbekommt. Daher brauche in dann die Konvertierung in ein Array. Es ist bestimmt nicht der beste Weg ein Objekt in ein Array zu konvertieren. Ich habe bisher nur nichts anderes gefunden, bin daher für Tipps in diese Richtung dankbar.
In der Funktion addRecordToMenu wird das Menü erweitert. Da habe ich auch einen etwas anderen Ansatz als in news. Dort wird das Menü erweitert. Ich schmeiße den letzten Eintrag raus und füge stattdessen meinen hinzu. Das hat aus meiner Sicht den Vorteil, dass man keinen Link zur Detailseite ohne Parameter hat. Den Ansatz aus News also dann verwenden, wenn die Detailansicht die Listenansicht überlädt. Falls man so wie in meinem Fall, eine separate Detailseite hat, die ohne Parameter keinen Sinn macht oder womöglich gar nicht funktioniert, dann muss man den Ansatz mit rausschmeißen-hinzufügen verfolgen.
Neueste Kommentare