Monday, October 29, 2012

Integrating TYPO3 Flow commands to the PhpStorm command line tool

Last week I read about the possibility to integrate composer to the PhpStorm command line tool. Inspired by this article, I created a configuration file for TYPO3 Flow commands.

TYPO3 Flow command line integration in PhpStorm
I published the configuration file on github, so it can easily be shared, extended, forked or whatever.

Sadly I did'nt get the Quick Definition View to work as it was described in the original article from Jetbrains.

Configuration:
  1. Navigate to Settings | Command Line Tool Support and add custom configuration
  2. Add the Framework Name (e.g. "TYPO3 Flow"), the Tool path (e.g. "./flow") and the Alias (e.g. "flow")
  3. Import the XML configuration file available here: https://github.com/derhansen/typo3-flow-phpstorm-cl-xml
Be sure to check, that the Tool path doesn't contain an absolute path to the flow executable.

How to use it?
  1. Open a TYPO3 Flow project in PhpStorm and press CTRL + SHIFT + X
  2. Check, that the current directory contains the TYPO3 Flow executable (in Linux systems you can use pwd to check the current directory). If not, navigate to that directory.
  3. Enter a TYPO3 Flow command by using the alias defined in the configuration (in this example "flow")

FlashMessages in TYPO3 Flow überschreiben

In TYPO3 Flow kann man Domain-Models sehr einfach per Annotations validieren. So definiert man in seinem Domain Model lediglich die Eigenschaften und die dazugehörigen Validierungsregeln. Will man nun über ein Formular Daten speichern, gibt TYPO3 Flow wie erwartet Fehlermeldungen passend zu den definierten Validierungsregeln aus.

Beispiel:

/**
 * The firstname
 *
 * @var string
 * @Flow\Validate(type="String")
 * @Flow\Validate(type="NotEmpty")
 */
 protected $firstname;

Die Eigenschaft "firstname" muss ein String und darf nicht leer sein. Erstellt man dafür nun ein Formular, würde das so aussehen.

<f:form action="create" controller="Register">
  <label for="firstname">Firstname:</label>
  <f:form.textfield=" id="firstname" name="data[firstname]" property="firstname" />
  <f:form.submit value="Submit" />
</f:form>

Um die Validierungsergebnisse auszugeben, muss das Formular wie folgt ergänzt werden.

<f:flashMessages />
<f:form.validationResults for="data">
    <f:if condition="{validationResults.flattenedErrors}">
        <div class="error">
            <f:for each="{validationResults.flattenedErrors}" key="propertyPath" as="errors">{propertyPath}: <f:for each="{errors}" as="error">{error}</f:for></f:for>
        </div>
    </f:if>
</f:form.validationResults>

Wenn man die das Formular nun absendet, erhält man in den validationResults die Meldungen bzgl. des Domain-Models. Aber im flashMessage Container erscheint noch eine nicht sehr schöne Fehlermeldung von TYPO3 Flow.
An error occurred while trying to call Your\Package\Controller\RegisterController->createAction()

Diese Meldung kann man überschreiben, indem man im Controller die Methode getErrorFlashMessage() überschreibt.

/**
 * @return \TYPO3\Flow\Error\Message
 */
protected function getErrorFlashMessage() {
 switch ($this->actionMethodName) {
  case 'createAction' :
   return new \TYPO3\Flow\Error\Message('Could not save form, because some fields are not filled out correctly');
  default:
   return parent::getErrorFlashMessage();
 }
}

Abhängig von der aufgerufenen Action, kann man die ausgegebene Fehlermeldung überschreiben.

Thursday, October 18, 2012

TYPO3 Flow 1.2 - Kickstarter Package über Composer installieren

Heute wollte ich mal die aktuelle Developer Version von TYPO3 Flow 1.2 installieren nachdem ich ein Tweet von Robert Lemke über TYPO3 flow und Composer gelesen hatte. Da mir Composer nicht nicht sehr geläufig ist, habe ich etwas länger gebraucht um das alles zum laufen zu bekommen.

Die Installation von TYPO3 Flow über Composer ist wirklich sehr einfach und mit einem simplen Befehl erhält man (fast) alle benötigten Dateien und Abhängigkeiten

composer create-project typo3/flow-base-distribution

Wer nun erwartet, dass man wie in Flow 1.1 einfach mit dem Kickstarter loslegen und Packages erstellen kann, der wird  feststellen, dass der TYPO3 Kickstarter gar nicht in der flow-base-distribution enthalten ist.

Nachdem ich dann etwas in der composer.json Datei reingeschaut hatte, fiel mir die Zeile "require-dev" auf. Dort stand unter anderem etwas vom TYPO3 Kickstarter. Die dort erwähnten Pakete installiert man mit folgendem Befehl:

composer install --dev

Nun kann man mit dem TYPO3 Kickstarter neue Packages erstellen.

Wednesday, October 3, 2012

Mapping anderer Tabellen in Extbase

Neulich stand ich vor der eigentlich recht simplen Aufgabe aus einer Extbase Extension heraus auf die erzeugten Daten einer anderen Extbase Extension zuzugreifen. Im Web gibt es auch einige Tutorials, welche beschreiben wie man dieses macht, aber fast alle zeigen, wie man auf die Tabellen fe_users und fe_groups zugreift, welche beide schon als Domain-Model bei Extbase mitgeliefert werden. Ein funktionierendes Praxisbeispiel für den Zugriff auf eigene Datenstrukturen konnte ich leider nicht finden.

In diesem Beitrag zeige ich deshalb, wie man aus einer Extbase Extension heraus auf die Daten einer anderen Extbase Extensions zugreifen kann.

Ausgangssituation:

In einer TYPO3 Installation wurden 2 Extbase Extensions (testext1 und testext2) eingerichtet, welche jeweils eigene Repositories und Storagefolder haben. Die Typoscript Constants der Extensions sind wie folgt eingerichtet:

plugin.tx_testext1 {
  persistence {
    storagePid = 5
  }
}

plugin.tx_testext2 {
  persistence {
    storagePid = 6
  }
}

Die Datensätze von testext1 werden also im Sysordner mit der Pid 5 abgelegt und die Datensätze von testext2 im Sysordner mit der Pid 6. In testext1 gibt es ein Domainmodel mit dem Namen Testext1Table und in testext2 gibt es ein Domainmodel mit dem Namen Testext2Table.

Ziel ist es nun, aus einem Controller in testext2 auf die angelegten Daten von testext1 zuzugreifen.

Vorgehensweise:

Als erstes muss in testext2 ein Domainmodel angelegt werden, welches das Domainmodel von textext1 extended. Also wird in textext2\Classes\Domain\Model\ die Datei Testext1Table.php angelegt.

class Tx_Testext2_Domain_Model_Testext1Table extends Tx_Testext1_Domain_Model_Testext1Table {

}

Somit wurde der testext2 schon mal das Domainmodel aus testext1 bekannt gemacht. Damit wir auf die Daten aus testext1 zugreifen können, wird noch ein entsprechendes Repository benötigt. Dieses wird in  textext2\Classes\Domain\Repository\Testext1TableRepository.php definiert.

class Tx_Testext2_Domain_Repository_Testext1TableRepository extends Tx_Extbase_Persistence_Repository {

}

Nun kennt die Extension testext2 das Domainmodel und hat auch ein entsprechendes Repository. Das neue Repository wird in einem Controller von testext2 per Dependency Injection implementiert.

/**
 * testext1TableRepository
 *
 * @var Tx_Testext2_Domain_Repository_Testext1TableRepository
 */
protected $testext1TableRepository;

/**
 * injectTestext1TableRepository
 *
 * @param Tx_Testext2_Domain_Repository_Testext1TableRepository $testext1TableRepository
 * @return void
 */
public function injectTestext1TableRepositoryRepository(Tx_Testext2_Domain_Repository_Testext1TableRepository $testext1TableRepository) {
 $this->testext1TableRepository = $testext1TableRepository;
}

Wer an dieser Stelle jetzt schon erste Ergebnisse aus dem implementierten Repository erwartet, wird enttäuscht und bekommt beim Versuch Daten aus dem Repository abzufragen/anzuzeigen eine Exception vom Typ Tx_Extbase_Persistence_Storage_Exception_SqlError, welche besagt, dass eine Tabelle nicht existiert.

Die Extension testext2 weiß also anscheinend noch gar nicht, aus welcher Tabelle die Daten des neuen Repositories abgefragt werden sollen. Um dieses einzurichten, muss man im Typoscript Setup von testext2 ein Mapping einrichten.

config.tx_extbase {
 persistence {
    classes { 
        Tx_Testext2_Domain_Model_Testext1Table {
            mapping.tableName = tx_testext1_domain_model_testext1table
        }
    }
 }
}

An dieser Stelle ist es wichtig, dass das Mapping direkt auf den Tabellennamen in der Datenbank stattfindet.

Auch jetzt erhalten wir über das neue Repository in testext2 noch keine Daten, da die testext2 noch nicht weiß, in welcher StoragePid die Datensätze von testext1 liegen. Hierzu ergänzt man lediglich die Typoscript Constants von testext2 wie folgt.

plugin.tx_testext2 {
  persistence {
    storagePid = 6,5
  }
}

Die StoragePid von testext1 wurde hinter der StoragePid von testext2 angehängt. Nun kann das neue Repository in testext2 angesprochen und die erwarteten Daten erfolgreich zurückgeliefert werden.


Sunday, September 16, 2012

PhpStorm und leere remote git Repositories

Nachdem ich nun auf PhpStorm umgestiegen bin, habe ich mich damit beschäftigt die Projekte aus meinem Git Repositories zu clonen. Zum Test wollte ich auch mal ausprobieren, wie man eine lokales Git Repository aus der IDE auf ein leeres remote Repository pusht. Tja, nach einigen Rumprobieren bin ich auf ein Foren-Eintrag bei Jetbrains gestoßen, der besagte, dass dieses wohl aus der IDE nicht möglich ist.

Also schnell in die Kommande-Zeile gewechselt und das lokale Git Repository in ein leeres remote Repository gepusht.

Dazu nutzt man folgende Befehle:
git remote add origin ssh://user@example.com/GIT/project.git
git push --set-upstream origin master
Nachdem man die Befehle ausgeführt hat, kann man in der IDE dann auch zukünftig die lokalen Änderungen an das remote Repository pushen. Irgendwie merkwürdig, dass diese Funktion nicht in PhpStorm implementiert ist. Oder ich habe sie einfach nicht gefunden ;-)

Tuesday, September 4, 2012

TYPO3 - Kopfgrafik als Resource per Inline CSS sliden

In einem Projekt wollte ich es dem Redakteur erlauben, die Kopfgrafik der Webseite auszutauschen. Die Kopfgrafik sollte sliden, sprich sich auf alle Unterseiten runter erben. Generell ist das ja auch kein Problem, wenn die Kopfgrafik ein eigenständiges Bild ist, welches direkt im Quelltext ausgegeben werden kann. Man definiert in TemplaVoila einen Marker, stellt dem User im TemplaVoila Template ein Feld zur Verfügung wo er das Bild ändern kann und schon ist man fertig. Will man das ganze noch sliden, dann nutzt man die Extension kb_tv_cont_slide. So weit, so gut.

Wenn man nun aber die Kopfgrafik per CSS festgelegt hat, dann wird es schon etwas schwieriger. Man müsste praktisch per TypoScript eine CSS generieren, welches eine vom User ausgewählte Kopfgrafik einbindet. Wie dieses geht, zeige ich in diesem Artikel.

In den Seiteneigenschaften kann der Redakteur eine (oder auch mehrere) Kopfgrafiken in den Ressourcen unter "Datei" hochladen.


Um den Verweis auf diese  Datei nun in eine CSS auszugeben, muss man im TS folgendes hinzufügen.

page.cssInline {
  10 = TEXT
  10 {
    wrap (
      .header {
        background-image: url(../'uploads/media/|');  
      }
    )
    data = levelmedia:-1,slide
  }
}

Dieses TS generiert die gewünschte CSS Datei. Glücklicherweise wird dieses auch ab TYPO3 4.5 per <link>-Tag gemacht und nicht direkt per Inline CSS ausgegeben, wie man anhand der Bezeichnung meinen könnte.

Man muss beachten, dass die CSS Datei im typo3temp-Ordner erstellt wird, was dazu führt, dass man bei der URL für das Hintergrundbild wieder eine Verzeichnis-Ebene höher muss um im upload-Ordner zu landen.

Der Wert bei "data" kann auch einfach "field:media" enthalten, wenn man den Inhalt nicht sliden möchte.

Friday, August 3, 2012

TYPO3 und Chrome 21.0.1180.60 - Flash Uploader ohne Funktion

Seit heute Morgen funktioniert bei mir in TYPO3 der Flash Uploader nicht mehr richtig - zumindest nicht in meinem Chrome (Version 21.0.1180.60) auf einem 64 Bit Windows 7. Man kann auf dem "Select Files" Button klicken, aber nichts passiert. Da der Flash Uploader in allen anderen Browsern (Firefox, Sarafi, Internet Explorer und Opera) ohne Probleme funktioniert, muss das Problem also irgendwie mit dem Chrome Update zusammen hängen, welches sich heute morgen automatisch installiert hat.

Nach einigen Testen habe ich dann einen Workaround gefunden, wie man im Chrome (Version 21.0.1180.60) den Flash Uploader wieder zum "Leben" erweckt. Ein sehr kleiner Bereich des "Select Files" Buttons scheint nämlich doch noch zu funktionieren.


Der rot markierte Bereich des Buttons funktioniert noch um Dateien für den Upload zu selektieren. Der Rest des Buttons ist ohne Funktion.

Hier zeigt sich  ein Nachteil an automatischen Updates, welche sich im Hintergrund und ohne Mitteilung an den User installieren. Da Chrome dem User nicht benachrichtigt, dass ein Update installiert wurde, wäre es auch nahe liegend gewesen, als erstes TYPO3 als Ursache für den nicht funktionierenden Flash Uploader zu vermuten.

Die Frage ist nun, wo genau das Problem zu reporten ist, denn so richtig klar ist es mir noch nicht, wer (TYPO3 oder Chrome) für das Problem verantwortlich ist. Meine Vermutung geht stark in Richtung Chrome, aber vielleicht enthält der TYPO3 Flash Uploader ja auch irgendwie einen Fehler, der sich nun durch das Chrome Update bemerkbar macht.