Am 25.03.2014 wurde die neueste Version TYPO3 CMS 6.2 LTS mit Langzeitsupport bis 2017 veröffentlicht. Zu den wichtigsten Änderungen gehören:
- Rewrite des Install Toos
- Entschlackung der Code-Basis
- Portierung des Package-Managements von TYPO3 Flow
- Einführung eines Distribution-Managers um Distributionen (wie Introduction Package, Government Package, …) zu verwalten
- Responsive Image Rendering in den Core integriert
- Core Updater (auf Knopfdruck Minor-Versionen aktualisieren)
- Data-Provider für Backend-Layouts
- Übersetzungsmöglichkeit von FAL Medadaten
- u.v.a.m
Alle Änderungen finden sich in dem Dokument „TYPO3 CMS 6.2 LTS – Die Neuerungen„.
Natürlich wurde aber auch zahlreiche Änderunge im Bereich Extbase und Fluid zugefügt, welche hier im Folgenden genauer aufgelistet werden.
Änderungen in Extbase
Object Manager
Der Object Manager hat die Methode getScope hinzubekommen, mit der es möglich ist, zu prüfen, ob eine Klasse vom Typ Singleton oder Prototyp ist:
|
/** * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface * @inject */ protected $objectManager; $this->objectManager->getScope($propertyTargetClassName) === \TYPO3\CMS\Extbase\Object\Container\Container::SCOPE_PROTOTYPE $this->objectManager->getScope($propertyTargetClassName) === \TYPO3\CMS\Extbase\Object\Container\Container::SCOPE_SINGLETON |
Automatische Ermittlung des PageTypes in URLs
Wenn man einen Link setzt, hinter dem das Format geändert werden soll, muss gleichzeitig auch der Parameter pageType gesetzt werden:
|
<f:link.action arguments="{blog: blog}" pageType="{settings.plaintextPageType}" format="txt">[plaintext]</f:link.action> |
Über eine neue TypoScript Option formatToPageTypeMapping, kann nun ein Mapping hinterlegt werden, welches automatisch zur Erkennung des PageTypes beim Wechsel des Formats sorgt:
|
plugin.tx_myext { view.formatToPageTypeMapping { txt = 99 pdf = 123 } } |
Nun reicht:
|
<f:link.action arguments="{blog: blog}" format="txt">[plaintext]</f:link.action> |
Portierung des Object Type Converters
Der in TYPO3 Flow eingeführte „Object Type Converter“ wurde nach Extbase portiert. Damit ist es möglich, Arrays in nicht-persistente Objekte zu konvertieren.
Beispiel: Erstellen eines nicht-persistenten Objekts $demand aus einem GET-Request heraus:
Der GET-Request könnte beispielhaft nun wie folgt aussehen:
|
http://master.dev/index.php?id=299&tx_mapperexample_piexample[action]=list&tx_mapperexample_piexample[controller]=Entity&tx_mapperexample_piexample[demand][title]=foo&tx_mapperexample_piexample[demand][relation]=1 http://master.dev/index.php?id=299&tx_mapperexample_piexample[action]=list&tx_mapperexample_piexample[controller]=Entity&tx_mapperexample_piexample[demand][title]=foo&tx_mapperexample_piexample[demand][relation][title]='foobar' |
Die initializeListAction() des Entity-Controllers enthält dabei den folgenden Code:
|
use [Vendor]\[ExtKey]\Domain\Dto\Demand;
public function initializeListAction() {
/** @var PropertyMappingConfiguration $demandConfiguration */
$demandConfiguration = $this->arguments['demand']->getPropertyMappingConfiguration();
$demandConfiguration->allowAllProperties()->forProperty('relation')
->allowAllProperties()->setTypeConverterOption(
'TYPO3\\CMS\\Extbase\\Property\\TypeConverter\\PersistentObjectConverter',
PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED,
TRUE);
} |
Die listAction() des Entity-Controllers:
|
use [Vendor]\[ExtKey]\Domain\Dto\Demand;
/**
* @param Demand $demand
*/
public function listAction(Demand $demand = NULL) {
$entities = $this->entityRepository->findAll();
$this->view->assign('entities', $entities);
} |
Die Model-Datei [Vendor]\[ExtKey]\Domain\Dto\Demand.php:
|
<?php
namespace [Vendor]\[ExtKey]\Domain\Dto;
use [Vendor]\[ExtKey]\Domain\Model\Relation;
class Demand {
protected $relation;
/**
* @param \TYPO3Friends\MapperExample\Domain\Model\Relation $relation
*/
public function setRelation($relation) {
$this->relation = $relation;
} } |
Chaining der QuerySettings
Das Chaining (Verketten) von QuerySettings ist nun auch mit den „neuen“ Optionen setIncludeDeleted und setIgnoreEnableFields (die mit TYPO3 CMS 6.0 eingeführt wurden) möglich:
|
$query->getQuerySettings()
->setRespectStoragePage(FALSE)
->setRespectSysLanguage(FALSE)
->setIgnoreEnableFields(TRUE)
->setIncludeDeleted(TRUE); |
RawQueryResult
Bisher war es möglich, mittels
$query->getQuerySettings()->setReturnRawQueryResult(TRUE)
dafür zu sorgen, dass keine Objekte vom QueryManager rekonstruiert werden, sondern das Query-Ergebnis „roh“ zurückgegeben wird.
Ab sofort gibt es diese Möglichkeit nicht mehr zentral, sondern man gibt dies per Query im execute-Statement mittels TRUE an:
Rekursive Validierung und optionale Werte
Extbase verwendet nun die von Flow portierte sogenannte „Rekursive Validierung“
Dies bedeutet, dass bei Erzeugung von verschachtelten Objekten (Objekt-Baum) durch den Property-Mapper auch die inneren Objekte validiert werden und nicht nur das äußere Objekt wie bisher.
Zudem ist es nun möglich, leere (optionale) Werte zu zulassen. Will man daher explizit erreichen, dass eine Eigenschaft angegeben werden muss, so muss der NotEmptyValidator verwendet werden.
Application Context
Innerhalb von Extbase kann man nun den von TYPO3 Flow bekannten ApplicationContext verwenden. Der Kontext wird über die Umgebungs-Variable TYPO3_CONTEXT gesetzt. Als Root-Kontext gibt es: „Development“, „Testing“ und „Production“. Anschließend kann es einen Sub-Kontext geben – z.B.: „Production/Staging“. Ist kein Kontext gesetzt, wird dieser per Default auf „Production“ gesetzt
Gesetzt werden kann der Kontext beispielsweise wie folgt (z.B. in der Datei .htaccess):
|
# Rules to set ApplicationContext based on hostname
RewriteCond %{HTTP_HOST} ^dev\.example\.com$
RewriteRule (.*) $1 [E=TYPO3_CONTEXT:Development]
RewriteCond %{HTTP_HOST} ^staging\.example\.com$
RewriteRule (.*) $1 [E=TYPO3_CONTEXT:Production/Staging]
RewriteCond %{HTTP_HOST} ^www\.example\.com$
RewriteRule (.*) $1 [E=TYPO3_CONTEXT:Production] |
Abgefragt werden kann der Kontext nun wie folgt:
|
\TYPO3\CMS\Core\Utility\GeneralUtility::getContext(); |
Prepared Statements
Es ist nun möglich, im Repository in der Funktion statement() neben einem SQL-String auch ein Prepared-Statement (welches das Interface TYPO3\CMS\Core\Database\PreparedStatement implementieren muss) zu verwenden. In den Typo3QuerySettings gibt es hierzu die Property $usePreparedStatement und die Funktionen usePreparedStatement() sowie getUsePreparedStatement(). Dabei sind Prepared Statements aber nur für SELECT Abfragen möglich.
Eingeschaltet werden kann das Verhalten per Query via:
|
$query->getQuerySettings()->setUsePreparedStatement(TRUE); |
Die Verwendung von Prepared Statements beschleunigt die lesenden Repository-Zugriffe unter Extbase wesentlich.
Einen Artikel zu Prepared Statements in TYPO3 gibt es hier:
http://buzz.typo3.org/teams/core/article/typo3-45-lts-prepared-queries-are-the-way-to-go/
Query Cache
Bislang war die Extbase Persistenz relativ langsam. Zum Teil war daran das Erstellen der Queries dafür zuständig. Für jeden Query mussten die Methoden parseQuery() und buildQuery() aufgerufen und erneut abgearbeitet werden. Daher wurde nun ein sogenannter „Query Cache“ eingeführt, der die Query-Struktur zwischen speichert. Damit kann der Query erneut verwendet werden – sogar mit unterschiedlichen Parametern.
Zuständig dafür ist der neu geschaffene QueryParser:
\TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser
Der Query Cache ist per Default eingeschaltet, kann aber manuell per Query ausgeschaltet werden, wenn der Cache zugespammt werden sollte:
|
$query->getQuerySettings()->useQueryCache(FALSE); |
Der zuständige Cache lautet: \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend und die Konfiguration: $GLOBALS[‚TYPO3_CONF_VARS‘][‚SYS‘][‚caching‘][‚cacheConfigurations‘]= array(‚groups‘ => array(‚system‘));
Infos hierzu finden sich hier:
http://forge.typo3.org/projects/typo3cms-core/repository/revisions/2583fd2a12dd3e740a9739f73aa602c2793999ec
JsonView Backport
Das Feature „JsonView“ wurde für die TYPO3 CMS 6.2 LTS von TYPO3 Flow nach Extbase portiert. Vor allem bei der Verwendung mittels Ajax oder als Webservice, wird vom Controller ein Datenformat als Rückgabe erwartet, welches leicht weiter verarbeitet werden kann.
Dies ist vermehrt JSON, da dies sehr leichtgewichtig und einfach zu parsen ist. Natürlich könnte man JSON durch ein entsprechendes Fluid-Template zur Verfügung stellen – allerdings ist ein „richtiger“ View deutlich praktischer.
Um den JSON-View im Controller benutzen zu können, wird er über die Variable $defaultViewObjectName aktiviert:
|
class FooController extends ActionController { /** * @var string */ protected $defaultViewObjectName = 'TYPO3\CMS\Extbase\Mvc\View\JsonView'; # … } |
Die Zuweisung erfolgt nun wie gehabt:
|
/**
* @param \Acme\Demo\Model\Product $product * @return void */ public function showAction(Product $product) { $this->view->assign('value', $product); } |
Per Default wird nur die Variable „value“ gerendert. Will man andere Variablen rendern lassen, so muss man dies entsprechend konfigurieren:
|
$this->view->setVariablesToRender(array('articles')); $this->view->assign('articles', $this->articleRepository->findAll()); |
Die Ausgabe sind dann wie folgt aus:
|
{"name":"Arabica","weight":1000,"price":23.95} |
Die Konfiguration des erzeugenden Arrays kann sehr detailliert durchgeführt werden:
|
$this->view->assign('value', $product); $this->view->setConfiguration(ARRAY); |
Das Array ARRAY kann dabei die folgenden Optionen besitzen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
array( 'value' => array( // Rendern der Eigenschaft "name" des Objekts value '_only' => array('name') ), 'anothervalue' => array( // Rendern von allen Eigenschaften mit Ausnahme der "password" // Eigenschaft des Objekts anothervalue '_exclude' => array('password') // Zusätzlich soll das Sub-Objekt "address" als verschachteltes // JSON Objekt inkludiert werden '_descend' => array( 'address' => array( // Hier kann man nun ebenfalls wieder // _only, _exclude und _descend verwenden ) ) ), 'arrayvalue' => array( // Hinheingehen in alle Sub-Objekte '_descendAll' => array( // Hier kann man nun ebenfalls wieder // _only, _exclude und _descend verwenden ) ), 'valueWithObjectIdentifier' => array( // Per Default wird der Objekt Identifier nicht in die Ausgabe // inkludiert, kann aber hier zugefügt werden '_exposeObjectIdentifier' => TRUE, // Der Objekt Identifier soll nicht als "__identity" gerendert // werden, sondern als "guid" '_exposedObjectIdentifierKey' => 'guid' ) ) |
Die möglichen Optionen lauten:
_only (array): Nur die angegebene Eigenschaft inkludieren
_exclude (array): Inkludieren von allen Eigenschaft, mit Ausnahme der angegebenen
_descend (associative array): Inkludieren der spezifizierten Sub-Objekte
_descendAll (array): Inkludieren aller Sub-Objekte (als numerisches Array)
_exposeObjectIdentifier (boolean): Inkludieren des Objekt-Identifier als __identifier
_exposeObjectIdentifierKey (string): Angabe des JSON-Feldnames
Änderungen in Fluid
Image-ViewHelper nun mit optionalem Title-Attribut
Im Image-ViewHelper kann nun das Attribut title weggelassen werden und dieses wird dann auch nicht mit ausgegeben.
Das Verhalten vor TYPO3 CMS 6.2 war so, dass in diesem Fall ein Attribut title gerendert und dafür der Inhalt des Attributs alt verwendet wurde:
<f:image src=“background.jpg“ alt=“Text“ />
führt zu
<img src=“background.jpg“ alt=“Text“ />
(und nicht wie vor TYPO3 CMS 6.2 zu)
<img src=“background.jpg“ alt=“Text“ title=“Text“ />.
Placeholder-Attribut für Textfield und Textarea
Die beiden ViewHelper form.textfield und form.textarea können nun mit einem Attribut placeholder ausgestattet werden:
|
<f:form.textfield id="powermail_field_{field.marker}" placeholder="{field.title -> vh:string.RawAndRemoveXss()}" name="field[{field.uid}]" value="{vh:Misc.PrefillField(field: '{field}')}" class="powermail_field powermail_input {vh:Misc.ValidationClass(field: '{field}')} {vh:Misc.ErrorClass(field: '{field}', class: 'powermail_field_error')}"
required="{field.mandatory}" /> |
Switch-ViewHelper
Es gibt nun einen Switch-ViewHelper der es ermöglicht, aufgrund eines Ausdrucks (Attribut expression) einen der Fälle (die mit dem case-ViewHelper realisiert werden, Default ist ebenfalls möglich) auszuwählen:
|
<f:switch expression="{person.gender}">
<f:case value="male">Mr.</f:case>
<f:case value="female">Mrs.</f:case>
<f:case default="TRUE">Mrs. or Mr.</f:case>
</f:switch> |
Achtung: Die exzessive Verwendung dieses ViewHelpers könnte auf eine schlechte Architektur hindeuten. So wäre in obigen Beispiel auch folgendes möglich:
<f:render partial=“title.{person.gender}“ />
mit den entsprechenden Partials title.male.html und title.female.html.
Benötigt man sehr viele case-ViewHelper, sollte man diese besser durch Partials ersetzen.
Format.bytes ViewHelper zugefügt
Dieser ViewHelper verwandelt eine Byte-Angabe (in Form eines Integers) in eine lesbare Version
.
Beispiel (fileSize = 1263616):
|
{fileSize -> f:format.bytes()} //
Ausgabe = 1234 KB
{fileSize -> f:format.bytes(decimals: 2, decimalSeparator: '.', thousandsSeparator: ',')}
//Ausgabe: 1,234.00 KB |
Backend ViewHelper Button.Icon finalisiert
Der Button.Icon ViewHelper, ist nun nicht mehr „experimental“, sondern finalisiert worden. Zweck des ViewHelpers ist es, ein Button-Icon zurückzuliefern (und ggf. zu verlinken)
|
<f:be.buttons.icon uri="{f:uri.action(action:'new')}" icon="actions-document-new" title="Create new Foo" />
<f:be.buttons.icon icon="actions-document-new" title="Create new Foo" /> |
Für das Attribut „icon“ können zahlreiche (über 310) Werte verwendet werden, die in der folgenden Datei unter dem Schlüssel $GLOBALS[‚TBE_STYLES‘][’spriteIconApi‘][‚coreSpriteImageNames‘] aufgelistet sind:
typo3/systext/core/ext_tables.php
addQueryStringMethod Support
Die Option addQueryString arbeitet bisher nur mit GET-Parametern, indem diese an den erzeugten Link wieder angehängt werden. Damit ist es aber nicht möglich POST Parameter (wie sie z.B. bei Widgets vorkommen) anzuhängen.
Über die Option addQueryStringMethod kann nun angegeben werden, welche Parameter verwendet werden sollen: GET oder POST oder GET,POST oder POST,GET – default ist GET. Der UriBuilder verfügt nun ebenfalls über diese Option.
Folgende ViewHelper wurden mit dieser Option ausgestattet: link.action, link.page, uri.action, uri.page, widget.link, widget.uri, widget.paginate
Fluid Template Fallback Support
Wenn man in Extbase Templates erweitern will, musste man bislang alle Templates kopieren. Ab sofort kann man „Fallback-Pfade“ definieren. Fluid schaut in dem Verzeichnis mit dem höchsten Index und geht (wenn das Template nicht gefunden wurde) runter bis zum kleinsten Index.
Fallbacks gibt es für Templates, Partials und Layouts:
templateRootPaths, partialRootPaths, layoutRootPaths
|
plugin.tx_simpleblog {
view {
templateRootPath = EXT:simpleblog/Resources/Private/Templates/
}
}
plugin.tx_simpleblog {
view {
templateRootPath >
templateRootPaths {
10 = fileadmin/simpleblog/templates
20 = fileadmin/special/simpleblog/templates } }
} |