Kolumne: Alles im Flow

Von Open Source, Dependency Injection und vielem mehr
Kommentare

Diesmal geht es um Gemeinsamkeiten und Unterschiede zwischen Open-Source-Projekten, einen 5-Minuten-Audit-Log mit Dependency Injection und AOP, Code-Sprints und um die anstehende Konferenz Inspiring Flow.

PHP Magazin

Die Kolumne „Alles im Flow “ von Robert Lemke ist erstmalig erschienen im PHP Magazin 3.2013

Gemeinsamkeiten

Vor Kurzem fand in Brüssel die FOSDEM statt – eine Konferenz, die eher eine Art Familientreffen von über 5 000 Entwicklern und Open-Source-Interessierten ist. Ein Novum dieses Jahr war der eigene Track zum Thema PHP. Neben unseren eigenen Vorträgen nutzten Lukas Smith (Symfony), Karsten Dambekalns (TYPO3), Johan Janssens (Joomla!) und ich die Gelegenheit, gemeinsame Probleme zu diskutieren und Anknüpfungspunkte auszuloten. Die weitere Professionalisierung in der PHP-Community stellt Projekte wie unsere vor spannende Aufgaben: Wie schafft man es, Entwicklern sehr unterschiedlicher Stufen des Könnens und mit verschiedenen Ambitionen den Einstieg zu ermöglichen und sie langfristig zufriedenzustellen? Eine abschließende Antwort haben wir nicht gefunden, wohl aber eine Menge Gemeinsamkeiten – und die erneute Erkenntnis, dass es sich lohnt, auch über Projektgrenzen hinaus zusammenzuarbeiten.

Abb. 1: Karsten Dambekalns und Lukas Kahwe Smith (im Hintergrund) auf der FOSDEM 2013
Unterschiede

Das Thema Dependency Injection ist – glücklicherweise – längst auch in der PHP-Welt angekommen, und kaum ein modernes Framework mag inzwischen darauf verzichten. So unterschiedlich wie die Frameworks sind auch ihre Umsetzungen dieses Design Patterns. Auch wenn es dabei selten ein „richtig“ oder „falsch“ gibt, lässt sich anhand dieses Features gut der Ansatz des entsprechenden Frameworks erklären. Bei TYPO3 Flow lautet dieser: möglichst wenig Schreibarbeit. In der Kombination mit aspektorientiertem Programmieren ergibt dieses Feature ein richtiges Powerpaket. Dazu ein kleines Beispiel aus der Praxis …

Audit Log in 5 Minuten

Eine klassische Projektanforderung ist das Protokollieren von wichtigen Vorgängen. Geschäftsprozesse werden allerdings nicht nur in einer einzelnen Klasse verarbeitet, sondern erstrecken sich verteilt auf viele Controller, Models und (Domain-)Services. Anstatt ein Logging in jeder dieser Klassen gesondert zu berücksichtigen, kann man in Flow auf Aspekte zurückgreifen, die es erlauben, diese so genannten „Cross-Cutting Concerns“ zu zentralisieren.

Ein Logging-Aspekt

Jedes Mal, wenn Rechnungen oder Produkte neu angelegt oder verändert werden, soll in unserem Beispielprojekt ein Eintrag in eine Log-Datei geschrieben werden. In Listing 1 sehen wir uns zunächst an, wie eine Rechnung erstellt oder verändert wird.

Listing 1
public function createInvoiceAction(Invoice $invoice) {
  $this->invoiceRepository->add($invoice);
}

public function updateInvoiceAction(Invoice $invoice) {
  $invoice->setLastModified(new DateTime());
  $this->invoiceRepository->update($invoice);
}

Im Wesentlichen werden die Methoden add() und update() des invoiceRepositorys aufgerufen. Analog dazu wird remove() verwendet, um eine Rechnung wieder zu entfernen. Mithilfe von AOP können wir Aufrufe dieser Methoden abfangen – dazu benötigen wir einen Filter, der definiert, welche Klassen-/Methodennamen für uns interessant sind:

AcmeDemoDomainRepository.*Repository->(add|update|remove)()

Dieser Ausdruck greift nicht nur bei invoiceRepository und productRepository, sondern auch bei allen weiteren – auch zukünftig entwickelten – Repositories innerhalb des angegebenen PHP-Namensraumes. Im nächsten Schritt erstellen wir einen Aspekt, der eine Methode enthält, die nach jedem add()-, update()– oder remove()-Aufruf eines Repositories involviert wird.

Aspekte sind kein Sprachbestandteil von PHP, deshalb verwenden wir Klassen, die in ihrem Kommentar als Aspekt gekennzeichnet werden (Listing 2).

Listing 2
namespace AcmeDemo;

/**
 * @FlowAspect
 */
class LoggingAspect {

  /**
   * @param JoinPointInterface $joinPoint
   * @return void
   * @FlowAfterReturning("method(AcmeDemoDomainRepository.*Repository->(add|update|remove)())")
   */
  public function repositoryActivityAdvice(JoinPointInterface $joinPoint) {
    $object = $joinPoint->getMethodArgument('object');
    // TODO: diese Aktion ins System Log schreiben
  }
}

Dieser Aspekt ist schon fast einsatzbereit: Jedes Mal, wenn nun eine add()-, update()– oder remove()-Methode aufgerufen wird, wird unsere Methode repositoryActivityAdvice() ausgeführt. In dem $joinPoint-Objekt erhalten wir Informationen über den aktuellen Kontext – zum Beispiel die Argumente, die der überwachten Methode übergeben wurden. In $object befindet sich nun also das Objekt, das hinzugefügt, geändert oder gelöscht werden soll.

Bleibt noch die Frage: Wie komme ich möglichst effektiv an einen System-Logger?

Dependency Injection in 15 Sekunden

Wer sich bereits mit Dependency Injection befasst hat, mag sich daran erinnern, dass es verschiedene Typen gibt: Constructor und Setter Injection. Flow bietet noch eine dritte Art, eine Abhängigkeit zu übergeben: Property Injection. Anstatt das benötigte Objekt (in unserem Fall der System-Logger) dem Constructor oder einer Setter-Methode zu übergeben, genügt es, eine Eigenschaft mit dem Klassen- bzw. Interface-Namen zu dokumentieren, und die @FlowInject-Annotation zu verwenden (Listing 3).

Listing 3
/**
 * @FlowAspect
 */
class LoggingAspect {

  /**
   * @FlowInject
   * @var TYPO3FlowLogSystemLoggerInterface
   */
  protected $systemLogger;

Nun befindet sich in der Member-Variable $systemLogger automatisch die System-Logger-Instanz – keine weitere Konfiguration ist notwendig. Schließlich kann man den Logger in einem „Advice“ verwenden, um den Geschäftsvorfall zu dokumentieren (Listing 4).

/**
 * @param JoinPointInterface $joinPoint
 * @return void
 * @FlowAfterReturning("method(AcmeDemoDomainRepository.*Repository->(add|update|remove)())")
 */
public function repositoryActivityAdvice(JoinPointInterface $joinPoint) {
  $object = $joinPoint->getMethodArgument('object');
  $message = sprintf('%s() called for object of type %s',
    $joinPoint->getMethodName(),
    get_class($object)
    );
  $this->systemLogger->log($message);
}

Eine umfangreiche Einführung in aspektorientiertes Programmieren sowie die vollständige Beschreibung des Depedency Injection Containers in Flow findet sich auf der neuen Dokumentationswebsite. [3]

Performance-Code-Sprint

Pünktlich zum Erscheinungsdatum dieser Ausgabe findet ein Code-Sprint des Flow-Teams statt, der sich ganz auf die weitere Verbesserung der Performance konzentriert. Voraussichtlich acht Entwickler sponsern ihre Zeit, um eine knappe Woche über Erfahrungswerte aus Kundenprojekten zu diskutieren und die Erkenntnisse konkret in Verbesserungen umzusetzen. Wer mithelfen oder einfach eine Pizza für das Team ausgeben möchte, findet weitere Informationen im TYPO3-Wiki [2].

Inspiring Flow

Am 19. und 20. April findet die dieses Jahr größte Konferenz zum Thema TYPO3 Flow statt, die Inspiring Flow 2013[4]. Neben Workshops gibt es wieder jede Menge Hintergrundinformationen zu Flow und benachbarten Themen sowie Praxisberichte aus umgesetzten Kundenprojekten.

Robert Lemke ist Projektgründer und Architekt des TYPO3-Flow-Frameworks und von TYPO3 Neos, einem neuen Content-Management-System des TYPO3-Projekts. Er hat eine besondere Leidenschaft für sauberen Code und unterstützt als freier Softwarearchitekt und Coach Firmen dabei, erfolgreiche Flow-Projekte umzusetzen. In seinem Blog auf robertlemke.com schreibt Robert über die Hintergründe des TYPO3-Projekts, hin und wieder etwas über Espressomaschinen und eigentlich nie etwas über pangalaktische Donnergurgler.
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -