Schlagwort-Archiv: Extbase

TypoScript-Konfiguration in Extbase Command Controller

Für die Umsetzung einer komfortablen Import-Funktion griff ich bei einem aktuellen Projekt auf das Command-Framework von Extbase zurück. Damit zu arbeiten ist eine wahre Freude; so wird z.B. der DocComment-Block von Kommando-Methoden automatisch ausgewertet und als Hilfetext im CLI-Dispatcher angezeigt. Selbst die Methoden-Argumente werden automatisch von $propertyName CLI-typisch als --property-name zur Verfügung gestellt. Ganz nebenbei wird hiermit auch gleich noch ein Scheduler-Task ohne jegliche weitere Konfiguration angelegt. Achja, die Einrichtung beschränkt sich übrigens auf eine einzige Zeile in der ext_localconf.php. In TYPO3 Flow genügt sogar allein die Existenz des Command-Controllers. ;-)

Neben allen Lobeshymnen stieß ich jedoch auf ein großes Problem: Im CLI-Kontext wurde meine TypoScript-Konfiguration nicht geladen.

Weiterlesen

Let’s bring the magic to Extbase

Beim Durchstöbern der Meldungen des Extension-Builder bin ich eher zufällig auf etwas gestoßen, was die Entwicklung von TYPO3-Erweiterungen mit Extbase revolutionieren könnte:

Workpaper: Magic for Domain Models
– A Plan for the Future of Models in Extbase

Um die Idee hinter dem Vorhaben zu verstehen, hier einmal eine kurze Auflistung der zum Hinzufügen eines einzelnen Felds zu einer einzigen Tabelle typischerweise notwendigen Schritte:

  1. Definition des Datenbank-Feldes (plus einer weiteren Tabelle bei MM-Beziehungen) in der ext_tables.sql,
  2. Hinzufügen der Eigenschaft nebst Getter und Setter zum betreffenden Model (plus ggf. Methoden zum Hinzufügen oder Entfernen von Elementen bei MM-Beziehungen),
  3. Hinzufügen des Felds zum TYPO3-Backend durch Anpassung der TCA-Definition der Tabelle,
  4. Ergänzen der notwendigen Übersetzungen (locallang_db.xml) und ggf. Beschreibungen/Hilfetexte (locallang_csh_*.xml)

Weitere Schritte ergeben sich, wenn z.B. MM-Beziehungen auch auf der Gegenseite bearbeitet/abgerufen werden können sollen. Insgesamt also eine Menge Schritte für eine eigentlich lapidare Erweiterung. Zudem verteilen sich die Schritte über mehrere Dateien deren Zusammenhang nicht unbedingt direkt ersichtlich ist. All dies zentral und mit minimalen Anpassungen vornehmen zu können würde Zeit und Aufwand sparen sowie mögliche Fehlerquellen reduzieren. Genau dies stellt das Projekt „Magic for Domain Models“ in Aussicht:

The core purpose is to make extension development, particularly modelling, more centralized and less prone to errors – and as a side bonus making it dynamic if so requested.

Erreicht werden soll dies um stark erweiterte Kennzeichnungen in den Kommentaren für Domain-Model und dessen Eigenschaften, was sich stark an die Möglichkeiten in FLOW3 anlehnt. Eine Beispiel-Konfiguration von der Projekt-Seite:

/**
 * Refrigerator Model
 *
 * (description and model annotiations ... )
 */
class Tx_Fedexample_Domain_Model_Refrigerator extends Tx_Extbase_DomainObject_AbstractEntity {
 
 // Other properties ...
 
 /**
 * Food content
 *
 * The parameters given to the "OneToMany" annotation are the default values which
 * will be used if not overridden - so they are shown for illustration only. You
 * can leave them out (just use @Magic\OneToMany) to use the table name in the relation
 * (tx_fedexample_domain_model_fooditem because Tx_FedExample_Domain_Model_FoodItem
 * is the type of relation. And the target field name from this Model (refrigerator).
 *
 * Note that a @Magic\Database annotations is not required here, it is automatically
 * applied based on the relation type. Although we use @Magic\Inline here there are
 * other options - like @Magic\Select and @Magic\Group, each with their own options.
 *
 * @var Tx_Extbase_Persistence_ObjectStorage<Tx_Fedexample_Domain_Model_FoodItem>
 * @Magic\Field(type="relation")
 * @Magic\OneToMany(foreignTable="tx_fedexample_domain_model_fooditem", foreignField="refrigerator")
 * @Magic\Inline(maxItems="1000")
 * @Magic\Column(provider="Tx_Magic_Provider_Column_InlineProvider", dynamic="TRUE")
 */
 protected $food;
 
}

Aus diesen Angaben kann automatisch geschlussfolgert werden, dass für die Datenbank-Tabelle tx_fedexample_domain_model_refrigerator ein Feld namens food definiert, als MM-Beziehung gekennzeichnet und im TYPO3-Backend via IRRE bearbeitet werden soll.

Darüber hinaus soll es aber auch möglich sein, das Bearbeiten von Feldern im TYPO3-Backend durch neue und benutzerdefinierte Widgets zu verbessern. Im Endeffekt sollen Datenbank-Definition, TCA-Konfiguration und Backend-Bearbeitungsmöglichkeiten an einer einzigen zentralen Stelle zusammengeführt werden: dem Model. Alle dafür von TYPO3 benötigten Angaben sollen automatisch und dynamisch generiert werden. All dies soll gänzlich optional sein, wobei nach einer gewissen Reifephase sicher nichts dagegen spricht, dies zum Standardverhalten zu machen. Wer spart sich nicht gerne Arbeit und Zeit. ;-)

Um das ganze performant zu halten, soll das Ergebnis der automatischen Code-Generierung natürlich Cache-fähig sein, was eingeplant, aber momentan noch ein offener Punkt ist. Der aktuelle Entwicklungsverlauf kann im TYPO3-Git-Repository der Magic-Erweiterung verfolgt werden. Initiiert und voran getrieben wird die Entwicklung von keinem geringeren als Claus Due, dem Kopf hinter den unschätzbar hilfreichen fed- und flux-Erweiterungen. Die Wahrscheinlichkeit, dass dieses Projekt also Realität wird ist sehr hoch. Hilfe in jeder Form ist allerdings sehr willkommen.

So muss Magie der Neuzeit aussehen.

Extbase: Model-Zugriff in Validatoren

Für den Fall, dass die Standard-Validatoren von Extbase oder benutzerdefinierte Validatoren für einzelne Eigenschaften eines Models nicht genügen, gibt es noch die Option eines benutzerdefinierten Validators mit vollem Zugriff auf die neue Instanz eines Models.

Dafür kann man sich eine gänzlich undokumentierte Feinheit des Extbase-Frameworks zunutze machen: standardmäßig wird in einem Standardpfad versucht, einen passenden Validator passend zu einem Model zu finden. Wieder ein Beispiel für „Konvention über Konfiguration“, worauf in Extbase und FLOW3 Wert gelegt wird.

Der besagte Validator wird standardmäßig unter Classes/Domain/Validator/ModelNameValidator.php gesucht. Wie bei allen Extbase-Validatoren üblich ist zur Erfüllung der Schnittstelle Tx_Extbase_Validation_Validator_ValidatorInterface (OOP-Konvention wäre hier eigentlich IValidator) eine Ableitung von Tx_Extbase_Validation_Validator_AbstractValidator empfehlenswert. Dessen isValid-Methode erhält als einziges Argument die betreffende Instanz des Models, womit dann beliebige Überprüfungen vorgenommen werden können. Da hier ein uneingeschränkter Zugriff auf alle Eigenschaften des Models gegeben ist, können so auch komplexe Validierungen mit Abhängigkeiten zwischen Eigenschaften und dergleichen vorgenommen werden.

Der Validator sollte zu guter Letzt wie immer true oder false zurückgeben um über das Ergebnis der Validierung zu informieren und im Fehlerfall zuvor noch eine aussagekräftige Fehlermeldung vermerken. Dies kann entweder über die addError-Methode oder direkt per Manipulation der errors-Eigenschaft geschehen:

// 1) addError()
$this->addError('Descriptive error message', 0000000000); // Hier sollte 0000000000 eine eindeutige Nummer sein
 
// 2) errors
$this->errors[] = new Tx_Extbase_Validation_Error('Descriptive error message', 0000000000); // Siehe oben

Letztere Variante bietet die Möglichkeit, manuell Instanzen von Tx_Extbase_Validation_PropertyError einzufügen. Dadurch können bestehende, auf Model-Eigenschaften optimierte, Partials für die Ausgabe von Validierungsfehlern ohne Anpassung verwendet werden. Dazu hängt man die eigentlichen Fehlermeldungen an eine Fake-Eigenschaft:

// Container für gruppierte Fehlermeldungen über eine Fake-Eigenschaft anlegen
if (!isset($this->errors['fakeProperty']) {
 
  $this->errors['fakeProperty'] = new Tx_Extbase_Validation_PropertyError('fakeProperty');
}
 
// Eigentliche Fehlermeldungen an den Container anhängen
$this->errors['fakeProperty']->addErrors(array(
  new Tx_Extbase_Validation_Error('Descriptive error message', 0000000000); // See above
));

Da dieser Validator allgemein für das Model gilt, wird er immer dann zur Rate gezogen, wenn eine neue Instanz des Models im Zuge einer Aktion angelegt werden soll. Wahlweise kann man dies allerdings auch manuell für die gewünschten Aktionen eines Controllers über die  @validate …Validator.php DocComment-Notation erfolgen. Allerdings sollte man dann darauf achten, dass der Validator nicht der oben beschriebenen Pfad-Konvention folgt. Andernfalls wird der Validator wie gehabt immer aufgerufen, @dontvalidate einmal ausgenommen. Auf diese Weise können der Zielaktion auch beliebige weitere Validatoren hinzugefügt werden, welche jeweils den gleichen Zugriff auf das Model haben.