Zurück zur Übersicht

TYPO3: Contextmenü erweitern und eigenes Modul mit Backend-Routen ansprechen

#Tutorials #TYPO3 #PHP

In diesem Tutorial geht es darum das Kontextmenü im Modul Dateiliste in TYPO3 8.7LTS zu erweitern und bei Klick auf eben diesen Eintrag im Menü ein eigenes Modul zu laden.

Auf der TYPO3 Seite gibt es schon ein wenig Dokumentation bei der ich mich bedient habe, hier zeige ich aber den kompletten Weg auf.

1. Kontextmenü erweitern

Als erstes fügt man in der ext_localconf eurer Extension zwei Zeilen ein, die das Kontextmenü ansprechen und benötigtes Javascript ins Backend einfügen.

ext_localconf.php

// Add Context Menu and JS
if (TYPO3_MODE=='BE') {
  $GLOBALS['TYPO3_CONF_VARS']['BE']['ContextMenu']['ItemProviders'][1505197586] = \AR\ArExt\ContextMenu\Mymodule::class;
}
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/backend.php']['constructPostProcess'][] = \AR\ArExt\Hooks\BackendControllerHook::class . '->addJavaScript';

Nun müssen natürlich die beiden Dateien, die dort angesprochen werden angelegt werden. Fangen wir mit der \AR\ArExt\ContextMenu\Mymodule an. 

Classes/ContextMenu/Mymodule.php

<?php
namespace AR\ArExt\ContextMenu;

class Mymodule extends \TYPO3\CMS\Backend\ContextMenu\ItemProviders\AbstractProvider{

  protected $itemsConfiguration = [
    'filetest' => [
      'type' => 'item',
      'label' => 'File Test Module', // you can use "LLL:" syntax here
      'iconIdentifier' => 'actions-document-open',
      'callbackAction' => 'fileTest' // Hier die fileTest beachten! Diese Funktion taucht unten in der ContextMenuActions.js wieder auf
    ]
  ];

  /**
   * Checks if this provider may be called to provide the list of context menu items for given table.
   *
   * @return bool
   */
  public function canHandle(): bool
  {
    // Current table is: $this->table
    // Current UID is: $this->identifier
    return $this->table === 'sys_file';
  }

  /**
   * Returns the provider priority which is used for determining the order in which providers are processing items
   * to the result array. Highest priority means provider is evaluated first.
   *
   * This item provider should be called after PageProvider which has priority 100.
   *
   * BEWARE: Returned priority should logically not clash with another provider.
   *   Please check @see \TYPO3\CMS\Backend\ContextMenu\ContextMenu::getAvailableProviders() if needed.
   *
   * @return int
   */
  public function getPriority(): int
  {
    return 90;
  }

  /**
   * Registers the additional JavaScript RequireJS callback-module which will allow to display a notification
   * whenever the user tries to click on the "Hello World" item.
   * The method is called from AbstractProvider::prepareItems() for each context menu item.
   *
   * @param string $itemName
   * @return array
   */
  protected function getAdditionalAttributes(string $itemName): array
  {
    return [
      // BEWARE!!! RequireJS MODULES MUST ALWAYS START WITH "TYPO3/CMS/" (and no "Vendor" segment here)
      'data-callback-module' => 'TYPO3/CMS/ArExt/ContextMenuActions',
      // Here you can also add any other useful "data-" attribute you'd like to use in your JavaScript (e.g. localized messages)
    ];
  }

  /**
   * This method adds custom item to list of items generated by item providers with higher priority value (PageProvider)
   * You could also modify existing items here.
   * The new item is added after the 'info' item.
   *
   * @param array $items
   * @return array
   */
  public function addItems(array $items): array
  {

    $this->initDisabledItems();
    $localItems = $this->prepareItems($this->itemsConfiguration);
    $items = $items + $localItems;
    //passes array of items to the next item provider
    return $items;
  }

  /**
   * This method is called for each item this provider adds and checks if given item can be added
   *
   * @param string $itemName
   * @param string $type
   * @return bool
   */
  protected function canRender(string $itemName, string $type): bool
  {
    // checking if item is disabled through TSConfig
    if (in_array($itemName, $this->disabledItems, true)) {
      return false;
    }
    $canRender = false;
    switch ($itemName) {
      case 'filetest':
      $canRender = true;
      break;
      default:
        $canRender = false;
    }
    return $canRender;
  }
}

Kommen wir nun zur zweiten genannten Datei, die etwas Javascript für das Backend ergänzt.

Classes/Hooks/BackendControllerHook.php

<?php
namespace AR\ArExt\Hooks;

use TYPO3\CMS\Backend\Controller\BackendController;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Page\PageRenderer;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
 * This class adds Filelist related JavaScript to the backend
 */
class BackendControllerHook
{
    /**
     * Adds Filelist JavaScript used e.g. by context menu
     *
     * @param array $configuration
     * @param BackendController $backendController
     */
    public function addJavaScript(array $configuration, BackendController $backendController)
    {
        $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
        $pageRenderer->addInlineSetting('FileTest', 'moduleUrl', BackendUtility::getModuleUrl('file_test'));
    }
}

Als nächstes müssen wir, wie in der Doku von TYPO3 beschrieben noch eine Javascript an folgende Stelle tun:

EXT:extension_key/Resources/Public/JavaScript/ContextMenuActions.js

/**
 * Module: TYPO3/CMS/ExtensionKey/ContextMenuActions
 *
 * JavaScript to handle the click action of the "Hello World" context menu item
 * @exports TYPO3/CMS/ExtensionKey/ContextMenuActions
 */
define(function () {
  'use strict';

  /**
   * @exports TYPO3/CMS/ExtensionKey/ContextMenuActions
   */
  var ContextMenuActions = {};

  /**
   * Say hello
   *
   * @param {string} table
   * @param {int} uid of the page
   */

    ContextMenuActions.getReturnUrl = function () {
      return top.rawurlencode(top.list_frame.document.location.pathname + top.list_frame.document.location.search);
    };

    ContextMenuActions.fileTest = function (table, uid) { // Hier die fileTest beachten! Diese Funktion haben wir in der ContextMenu Klasse unter callback definiert!
      if (table === 'sys_file') {
        //If needed, you can access other 'data' attributes here from $(this).data('someKey')
        //see item provider getAdditionalAttributes method to see how to pass custom data attributes
        // hier springen wir auf das module FileTest
        top.TYPO3.Backend.ContentContainer.setUrl(
          top.TYPO3.settings.FileTest.moduleUrl + '&target=' + top.rawurlencode(uid) + '&returnUrl=' + ContextMenuActions.getReturnUrl()
        );
      }
    };
    return ContextMenuActions;
});

Wenn wir so weit sind, dann kommt nun schon unser Punkt im Kontext-Menü und man kann ihn klicken. Danach kommt man allerdings noch nicht weiter, da das Backend die Route file_test noch nicht kennt.

Eine Route definiert man, in dem man Configuration/Backend/Routes.php anlegt.

<?php
use AR\ArExt\Controller;

/**
 * Definitions for routes provided by EXT:backend
 * Contains all "regular" routes for entry points
 *
 * Please note that this setup is preliminary until all core use-cases are set up here.
 * Especially some more properties regarding modules will be added until TYPO3 CMS 7 LTS, and might change.
 *
 * Currently the "access" property is only used so no token creation + validation is made,
 * but will be extended further.
 */
return [
  //
  'file_test' => [
    'path' => '/file/test',
    'target' => Controller\FileTestController::class . '::mainAction'
  ],
];

Wie man hier sieht, kann man hier einen belieben Controller und eine beliebige Action laden. In meinem Fall den FileTestController mit der mainAction. Sobald diesen angelegt und auch die passende Action dazu und dort zum Beispiel ein echo 'Test'; hineinschreibt, so wird nach Klick auf den neuen Kontext-Menü Eintrag das Module geladen und es wird Test angezeigt. Ab hier ist es jedem selbst überlassen, was er tun möchte.

Ich hoffe ich konnte einen groben Einblick verschaffen, wie man einen Kontext-Menü Eintrag hinzufügt und ein eigenes Modul aufruft.


Kommentare

Es gibt noch keine Kommentare. Sei der Erste!

Hinterlasse einen Kommentar

Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Kommentar wird gespeichert
Danke für deinen Kommentar! Sobald er freigegeben wurde erscheint er hier.