sys_category: Systemkategorien in Datensätzen der eigenen Extension verfügbar machen

Teil 2: Systemkategorien in Datensätzen der eigenen Extension verfügbar machen

Leider lassen sich die Kategorien nicht mit dem Extension Builder direkt in die neue Extension integrieren. Stattdessen legt man ein ein Feld als „Verweis“ an, Verbindet diesen Verweis aber nicht mit einem anderen Model. Wenn es möglich sein soll, mehrere Kategorien auszuwählen, nennt man das Feld „categories“.

Modellierung der Beziehung zu den Kategorien im Extbase-Model

Nun bearbeitet man das Model, das kategorisiert werden soll, bei mir lw_pinboard/Classes/Domain/Model/Message.php

In der Regel ist es ja möglich, einem Datensatz mehrere Kategorien zuzuweisen. Und natürlich kann auch eine Kategorie viele Datensätze enthalten. Deshalb handelt es sich um eine m:n Beziehung. Diese lässt sich in Extbase wie folgt modelieren.

Das Feld muss ein ObjectStorage sein:

/**
 * category
 * 
 * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\LW\LwPinboard\Domain\Model\Category>
 */
protected $categories = null;

man darf nicht vergessen, den ObjectStorage im Konstruktor des Models zu initialisieren, denn sonst kommt es zu Fehlermeldungen.

public function __construct()
{
	$this->setCategories(new \TYPO3\CMS\Extbase\Persistence\ObjectStorage);
}

Nun müssen neben dem klassischen Getter und Setter auch noch ein Adder und Remover zum Model hinzugefügt werden:

/**
 * Returns the categories
 * 
 * @return $categories
 */
public function getCategories()
{
	return $this->categories;
}

/**
 * Sets the category
 * 
 * @param  \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\LW\LwPinboard\Domain\Model\Category> $categories
 * @return void
 */
public function setCategories(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $categories)
{
	$this->categories = $categories;
}

/**
 * Adds a category
 * 
 * @param  \LW\LwPinboard\Domain\Model\Category $category
 * @return void
 */
public function addCategory(\LW\LwPinboard\Domain\Model\Category $category) {
	$this->categories->attach($category);
}

/**
 * Removes a category
 * 
 * @param  \LW\LwPinboard\Domain\Model\Category $category
 * @return void
 */
public function removeCategory(\LW\LwPinboard\Domain\Model\Category $category) {
	$this->categories->detach($category);
}

Anpassung des TCA zum Anzeigen und Ändern der Kategorien im Backend

Nun muss noch das TCA der Tabelle des Models Message angepasst werden, in meinem Fall: lw_pinboard/Configuration/TCA/tx_lwpinboard_domain_model_message.php

Das Feld categories wird wie folgt in den columns angepasst:

'categories' => [
	'exclude' => true,
	'label' => 'LLL:EXT:lw_pinboard/Resources/Private/Language/locallang_db.xlf:tx_lwpinboard_domain_model_message.category',
	'config' => [
		'type' => 'inline',
		'foreign_table' => '',
		'minitems' => 0,
		'maxitems' => 1,
		'appearance' => [
			'collapseAll' => 0,
			'levelLinksPosition' => 'top',
			'showSynchronizationLink' => 1,
			'showPossibleLocalizationRecords' => 1,
			'showAllLocalizationLink' => 1
		],
	],
],

Zusätzlich muss das Feld noch kategorisiert werden. Dazu vor dem return in der selben Datei folgendes aufrufen:

\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable(
	'LW.' . $_EXTKEY,
	'tx_lwpinboard_domain_model_message',
	'categories'
);

Die Kategorien im eigenen Controller der Extension

Nun kann man z.B. im Controller eine Ansicht mit nur den Nachrichten einer Kategorie konfigurieren: lw_pinboard/Classes/Controller/MessageController.php

/**
 * action list
 * 
 * @return void
 */
public function listAction()
{
	$arguments = $this->request->getArguments();
	$category = 0;
	if($arguments && $arguments['cat']) {
		$category = intval($arguments['cat']);
	}
	if ($category != 0) {
		$messages = $this->messageRepository->findByCategory($category);
	} else {
		$messages = $this->messageRepository->findAll();
	}
	$categoryList = $this->categoryRepository->findAll();
	$this->view->assign('messages', $messages);
	$this->view->assign('categoryList', $categoryList);
}

Die Methode findByCategory ist nicht standardmäßig in einem Repository vorhanden, sondern muss noch implementiert werden. Auf keinen Fall darf man die Magic Methode findByCategories nutzen. Diese liefert nämlich die falschen Daten und ggf keine Fehlermeldung und das kommt so: TYPO3 speichert im Feld categories in der Datenbank bei einer m:n Beziehung die ANZAHL der Kategorien. Wenn nun Mein Datensatz zwei Kategorien hat, steht hier also eine 2. Wenn ich nun nach Nachrichten in der Kategorie mit uid 2 suche und die Magic Methode findByCategories nutze, so liefert mir nun Extbase alle Nachrichten zurück, die zu zwei Kategorien zugewiesen wurden.

Methode findByCategory im Repository der Message implementieren

Also editieren wir nun noch das Repository unseres eigenen Datensatzes, hier der Message: lw_pinboard/Classes/Domain/Repository/MessageRepository.php

/**
 * Finds an object matching the given identifier.
 *
 * @param int $categoryid The identifier of the category to find Messages from
 * @return object The matching object if found, otherwise NULL
 * @api
 */
public function findByCategory($categoryid) {
	$query = $this->createQuery();
	$query->matching($query->contains('categories', $categoryid));
	return $query->execute();
}

sys_category: Systemkategorien in eigener Extension einbinden und erweitern

Seit Version 6.0 bietet TYPO3 systemeigene Kategorien an, die sich komfortabel in eigene Extensions integrieren lassen.

Teil 1: Systemkategorien in eigener Extension einbinden und erweitern

Leider ist deren Integration nicht ganz trivial. Die beste Verfügbare Anleitung zum integrieren der Systemkategorien in eine eigene Extension (engl) habe ich bisher auf Github gefunden. daher hier eine Anleitung, wie man vorgehen kann.

Es gibt in der Systemextension Extbase, zu finden unter TYPO3ROOT/typo3/sysext/extbase bereits ein vorbereitetes Model und Repository für die System Category. Diese muss man in seiner eigenen Extension nun nur erweitern und das geht so:

in my_extension/Classes/Domain/Model/Category.php ablegen mit folgendem Inhalt:

<?php
namespace LW\LwPinboard\Domain\Model;

class Category extends \TYPO3\CMS\Extbase\Domain\Model\Category {}

analog das Repository unter my_extension/Classes/Domain/Repository/CategoryRepository.php

<?php
namespace LW\LwPinboard\Domain\Repository;

class CategoryRepository extends \TYPO3\CMS\Extbase\Domain\Repository\CategoryRepository {}

Wenn man keine zusätzlichen Anforderungen an die Funktionalität hat, kann man die Klassen von Category Model und Repository erstmal unverändert lassen. Damit Extbase weiß, in welcher Datenbanktabelle es schauen muss, muss man nun noch per TypoScript ein Mapping durchgeführt werden. Dies geht z.B. in my_extension/Configuration/TypoScript/setup.ts mit:

plugin.tx_myextension.persistence.classes {
	ABC\MyExtension\Domain\Model\Category {
		mapping {
			recordType = 0
			tableName = sys_category
		}
	}
}

Nun sind die Kategorien generell in der Extension verfügbar. Man könnte diese z.B. im Controller an das View hängen, um eine Liste aller Kategorien auszugeben:

Dazu muss man im eigenen Controller der Extension, bei mir my_extension\Classes\Controller\MessageController.php zunächst das CategoryRepository  hinzufügen und injecten:

 /**
 * @var \ABC\MyExtension\Domain\Repository\CategoryRepository
 * @inject
 */
protected $categoryRepository = null;

Nun kann in der entsprechenden Action das Repository so wie jedes andere auch abgefragt werden, z.B:

$categoryList = $this->categoryRepository->findAll();
$this->view->assign('categoryList', $categoryList);

Wir können nun eine Liste von System Kategorien per FLUID anzeigen, schön, aber wir wollten doch unsere Messages kategorisieren.

Dazu weiter mit Teil 2

TYPO3 8.7 LTE Erweiterung manuell deinstallieren


Oops, an error occurred!

Es kann passieren, dass eine inkompatible oder fehlerhafte Erweiterung (Extension) dafür sorgt, dass das ganze TYPO3 Backend und selbst das Install Tool nicht mehr ansprechbar sind. Mir ist das z.B. passiert, nachdem ich versucht habe, die Extension blog_example zu installieren. Ok zugegeben, sie wurde auch schon lange nicht mehr gepflegt, das hatte ich übersehen.

TYPO3 zeigte dann nur noch einen hübschen roten Kasten mit der Fehlermeldung „Oops, an error occurred! Class ‚Tx_Extbase_Utility_Extension‘ not found“ an.

In so einem Fall ist es natürlich nicht möglich, die Erweiterung über den Extensionmanager zu deaktivieren. Wenn man aber FTP Zugang auf den Server hat, ist das kein Problem.

In folgender Datei: TYPO3ROOT/typo3conf/PackageStates.php den Eintrag der fehlerhaften Extension löschen, in diesem Fall:

    'blog_example' => [
        'packagePath' => 'typo3conf/ext/blog_example/',
    ],