Archiv für die Kategorie ‘Typo3’

02. Dezember 2011

Typo3-Weihnachtskalender-Extension auf Extbase/Fluid-Basis

Typo3-Weihnachstkalener-Extension auf Extbase/Fluid-Basis

Typo3-Weihnachstkalener-Extension auf Extbase/Fluid-Basis

Unsere neue Typo3-Extension “cgadventcalendar” implementiert einen einfachen Weihnachtskalender mit 24 Kläppchen.

Der Clou: Klickt man mehrmals auf ein Kläppchen zukünftigen Datums, wird eine von fünf Audiodateien abgespielt. Beim ersten Klick wird jeweils per Zufall eine Datei aus den ersten drei Audiofiles ausgewählt. Beim zweiten und dritten Klick gibt es dann eine dramaturgische Steigerung.

Die Umsetzung der Typo3-Weihnachtskalender-Extension erfolgte auf Extbase/Fluid-Basis. Für die Umsetzung der Audio-Funktionalität setzten wir auf “Soundmanager 2“.

Die einzelnen Kläppchen lassen sich im Backend komfortabel per IRRE (Inline Relational Record Editing) mit zwei Zustandsgrafiken für die Kläppchen sowie beliebigen Typo3-Content-Elementen bestücken.

10. September 2011

Neue Website auf Typo3-Basis: Alte Villa Ling

Die Website der Alten Villa Ling in neuem Webdesign-Glanz und auf Typo3-Basis

Die Website der Alten Villa Ling in neuem Webdesign-Glanz und auf Typo3-Basis

Mit dem Relaunch der Website der Alten Villa Ling wurde nicht nur das alte Webdesign gegen ein neues und modernes Webdesign ausgetauscht, auch wurde die vormals statische Website durch ein modernes Content Management System auf Basis von Typo3 ersetzt.

Trotz des geringen zur Verfügung stehenden Budgets konnten wir kleinere Gimmicks umsetzen, wie beispielsweise die Möglichkeit, den Hauptinhaltsbereich per Klick hinter das Menü gleiten zu lassen, um die hochwertigen Fotografien und Hintergrundbilder besser betrachten zu können.

 

24. August 2011

Test-Driven Development unter Typo3: Extbase-Controller testen

Um Controller-Klassen unter dem Typo3-Extbase-Framework testen zu können, gilt es einige Unwegsamkeiten zu bewältigen:

  • Bestimmte zu testende Member-Variablen der Controller-Klasse wie beispielsweise die ‘view’-Variable sind als “geschützt” deklariert und sind zunächst weder über Setter/Getter noch per Dependency-Injection erreichbar
  • Von Haus unterstützt PHPUnit weder das “Stubben” noch “Mocken” von Methoden, die als privat, geschützt oder statisch definiert sind

Glücklicherweise erweitert die PHPUnit-Extension für Typo3 das PHPUnit-Framework um die nötigen Methoden, um “Accessible Mocks” zu erzeugen. Die entsprechende Methode getAccessibleMock() ermöglicht so den Zugriff auf geschützte Methoden und Eigenschaften des Mock-Objekts.

Ein Setup für eine Extbase-Controller-Testklasse könnte wie folgt aufgebaut sein:

/**
* @var Tx_Cgfaq_Controller_FaqController
*/
protected $fixture;

public function setUp() {
  $mockFaqRepository = $this->getMock(
    'Tx_Cgfaq_Domain_Repository_FaqRepository', array(), array(), '', FALSE
 );
  $this->fixture = $this->getAccessibleMock(
    'Tx_Cgfaq_Controller_FaqController', array('dummy'), array(), '', FALSE
  );

  $this->fixture->injectFaqRepository($mockFaqRepository);
  $this->fixture->_set('view', $this->getMock('Tx_Fluid_View_TemplateView', array(), array(), '', FALSE));
}

Hierbei erzeugen wir zunächst die benötigten Mock-Objekte; eines für die Repository- und eines für die Controller-Klasse. Das Mock-Objekt für die Controller-Klasse erzeugen wir lediglich, um die geschützten Methoden und Eigenschaften per getAccessibleMock() durch öffentliche zu ersetzen. Damit PHPUnit nicht alle Methoden der Controller-Klasse durch Stubs ersetzt (was die Vorteile mit einem Schlage wieder wett machen würde), muss mit dem Aufruf der getAccessibleMock()-Methode zwingen eine Dummy-Methode übergeben werden (hier: array(‘dummy’)).

Die getAccessibleMock()-Methode erweitert die angegebene Klasse um drei Funktionen, mit denen der Zugriff auf die vormals geschützten Eigenschaften und Methoden möglich wird:

  1. _set($propertyName, $value)
  2. _setRef($propertyName, &$value)
  3. _get($propertyName)

Ist die setUp()-Methode geschrieben, sind die nachfolgenden Testfälle schnell getippt:

/**
* @test
*/
public function listActionFindsDemandedFaqs() {
  $mockQueryResult = $this->getMock('Tx_Extbase_Persistence_QueryResult', array(), array(), '', FALSE);

  $this->fixture->_get('faqRepository')->expects($this->once())
        ->method('fetchByFeUserAndGroup')
        ->will($this->returnValue($mockQueryResult));

  $this->fixture->_get('view')->expects($this->once())
        ->method('assign')
        ->with($this->equalTo('faqs'),
                $this->equalTo($mockQueryResult)
        );

  $this->fixture->listAction();
}
17. August 2011

Test-Driven Development unter Typo3: Extbase-Repositories testen

Mit der Einführung des “Testing Framework” in die Typo3-PHPUnit-Extension hat sich das Testen von Repositories ausgesprochen vereinfacht. Neben dem testweisen Schreiben von Datensätzen in die Datenbank bietet die Tx_Phpunit_Framework-Klasse eine Vielzahl weiterer nützlicher Funktionen wie beipspielsweise das testweise Anlegen von Front- und Backend-Usern oder das Ein- und Ausloggen von Nutzern.

Einen Überblick über die Möglichkeiten des Testing Frameworks findet sich in der Doku der Typo3-PHPunit-Extension.

Wie bei jeder PHPUnit-Testklasse schreiben wir zunächst die setUp()-Methode in der wir neben dem Fixture auch eine Instanz des Testing Frameworks instantiieren sowie die tearDown()-Methode. Da beim Testen der Repository-Klassen zwangsläufig externe Ressourcen einbezogen werden (Datenbank), ist die tearDown-Methode von besonderer Wichtigkeit, um nach jedem Test die externen Ressourcen wieder in den Ausgangszustand zurückzuversetzen:

/**
* @var Tx_Phpunit_Framework
*/
protected $testingFramework;

/**
* @var Tx_Cgfaq_Domain_Repository_FaqRepository
*/
protected $fixture;

public function setUp() {
  $this->testingFramework = new Tx_Phpunit_Framework('tx_cgfaq');
  $this->fixture = $this->objectManager->get('Tx_Cgfaq_Domain_Repository_FaqRepository');
}

public function tearDown() {
  $this->testingFramework->cleanUp();
  unset($this->testingFramework, $this->fixture);
}

In den einzelnen Tests generieren wir zunächst einige Dummy-Datenbankeinträge, führen die entsprechenden Repository-Methoden aus und prüfen schlussendlich das Rückgabeergebnis:

/**
* @test
* @return void
*/
public function fetchByFeUserAndGroup_testing_SingleUserConstraint() {
  $pid = 0;
  $mockCustomerRelatedService = $this->getMock('Tx_Cgfaq_Service_CustomerRelatedService');
  $this->fixture->injectCustomerRelatedService($mockCustomerRelatedService);

// create some dummy records
$this->testingFramework->createRecord('tx_cgfaq_domain_model_faq', array(
'pid'         => $pid,
'type'        => Tx_Cgfaq_Controller_FaqController::SIMPLE_FAQ,
'question'    => 'OKAY',
'answer'    => 'OKAY',
'front_user'=> 99
));
$this->testingFramework->createRecord('tx_cgfaq_domain_model_faq', array(
'pid'         => $pid,
'type'        => Tx_Cgfaq_Controller_FaqController::SIMPLE_FAQ,
'question'    => 'AHA',
'answer'    => 'AHA',
'front_user'=> 99
));
$this->testingFramework->createRecord('tx_cgfaq_domain_model_faq', array(
'pid'         => $pid,
'type'        => Tx_Cgfaq_Controller_FaqController::SIMPLE_FAQ,
'question'    => 'ERROR',
'answer'    => 'ERROR',
'front_user'=> 88
));

$mockCustomerRelatedService->expects($this->any())
->method('isGroupMember')
->will($this->returnValue(FALSE));

$mockCustomerRelatedService->expects($this->any())
->method('getCalculatedFeUser')
->will($this->returnValue(99));

$this->assertEquals(2, (int)$this->fixture->fetchByFeUserAndGroup()->count());
}

Tipp: Beim Testen von Repository-Methoden, die den Inhalt der Datenbank verändern (z.B. per remove() oder update()),  müssen vor der Fomulierung der Annahmen ($this->assert…..) die durch die Repository-Methoden eingeleiteten Änderungen persistiert werden. Dazu genügen die folgenden beiden Zeilen:

$persistanceManager = t3lib_div::makeInstance('Tx_Extbase_Persistence_Manager');
$persistanceManager->persistAll();
25. Juli 2011

Test-Driven Development unter Typo3: Extbase-Models testen

In diesem und den folgenden Beiträgen möchten wir unsere Erfahrungen für die testgetriebene Entwicklung (TDD) unter Typo3 Extbase/Fluid beschreiben sowie einige “Best Practice” vermitteln.

Für das Testen von Models hat sich folgende Herangehensweise bewährt:

Zunächst erfolgt das Aufsetzen des Testobjekts (“fixture”):

/**
* @var Tx_Cgfaq_Domain_Model_Faq
*/
protected $fixture;

public function setUp() {
  $this->fixture = new Tx_Cgfaq_Domain_Model_Faq();
}

Solange keine externen Ressourcen für die Erstellung des Testobjekts benötigt werden, kann auf eine explizite tearDown()-Methode verzichtet werden.

Setter und Getter für einfache Objekteingenschaften testen wir wie folgt. Dabei greifen wir wann immer es sinnvoll ist auf “assertSame” statt auf “asserEquals” zurück. So können wir sicher sein, dass sowohl der Typ der Eigenschaft als auch deren Wert auf Gleichheit geprüft werden. Zusätzlich prüfen wir, dass jede Eigenschaft den von uns erwarteten Ausgangswert besitzt:

/**
* Test if getTitle() returns inital value for title
*
* @test
* @return void
*/
public function getTitleReturnsInitialValueForTitle() {
$this->assertSame('', $this->fixture->getTitle());
}

/**
* Test if a title can be set
*
* @test
* @return void
*/
public function aTitleCanBeSet() {
  $this->fixture->setTitle('Hello World');
  $this->assertSame('Hello World', $this->fixture->getTitle());
}

Objekteigenschaften, die als ObjectStorage dienen, testen wir wie folgt. Dabei testen wir neben den Setter- und Getter-Methoden auch die Möglichkeit, Objekte hinzuzufügen (add/attach) respektive zu löschen (remove/detach).

Im ersten Schritt stellen wir zunächst sicher, dass die Eigenschaft, die als Object Storage dient, korrekt initalisiert wird, sprich ein Objekt der Klasse “Tx_Extbase_Persistence_ObjectStorage” ist und der Objektspeicher leer ist:

/**
* Test if getCategories() returns inital value for object storage
*
* @test
* @return void
**/
public function getCategoriesReturnsInitialValueForCategories() {
  $this->assertSame('Tx_Extbase_Persistence_ObjectStorage', get_class($this->fixture->getCategories()));
  $this->assertEquals(0, count($this->fixture->getCategories()));
}

Als Nächstes prüfen wir die Setter-Methode. Wichtig ist in diesem Zusammenhang die Verwendung von Mock-Objekten. Nur so lässt sich das TDD-Paradigma “loosely coupled objects”, der locker verbundenen Objekte, umsetzen:

/**
* Test if a category can be set
*
* @test
* @return void
**/
public function aCategoryCanBeSet() {
  $mockObjStorage = $this->getMock('Tx_Extbase_Persistence_ObjectStorage', array('contains'));
  $mockObjStorage->expects($this->any())->method('contains')->with('foo')->will($this->returnValue(TRUE));
  $this->fixture->setCategories($mockObjStorage);

  $this->assertTrue($this->fixture->getCategories()->contains('foo'));
}

Zu guter Letzt folgen die Tests für die addCategory()- und removeCategory()-Methoden:

/**
* Test if a category can be added
*
* @test
* @return void
**/
public function aCategoryCanBeAdded() {
  $category = new Tx_Cgfaq_Domain_Model_Categories();
  $this->fixture->addCategory($category);

  $this->assertTrue($this->fixture->getCategories()->contains($category);

/**
* Test if a category can be removed
*
* @test
* @return void
**/
public function aCategoryCanBeRemoved() {
  $category = new Tx_Cgfaq_Domain_Model_Categories();
  $this->fixture->addCategory($category);
  $this->assertEquals(1, count($this->fixture->getCategories()));
  $this->fixture->removeCategory($category);

  $this->assertFalse($this->fixture->getCategories()->contains($category));
}
23. Juli 2011

Typo3 Advanced FAQs (cgfaq): FAQ-Extension für Typo3 auf Extbase/Fluid-Basis

Dank Autovervollständigung und Stoppwortfilterung sind FAQs schnell gefunden

Dank Autovervollständigung und Stoppwortfilterung sind FAQs schnell gefunden

Mit unserer neuen Typo3-Extension Advanced FAQs (cgfaq) lassen sich FAQs komfortabel über das Typo3-Frontend verwalten und nutzen.

FAQ-SUCHE: Zentraler Bestandteil der auf Extbase/Fluid basierenden Typo3-Extension ist unser FAQ-Suchmodul. Die integrierte Autovervollständigung des eingegebenen Suchausdrucks sowie die Vorfilterung per Stoppwortliste ermöglichen eine schnelle und zielgerichtete Suche in der FAQ-Datenbank. Die Listenansicht der gefundenen FAQs unterstützt zusätzlich eine seitenweise Ausgabe der Treffer mit variabler Trefferanzahl pro Seite inklusive Pagebrowser sowie eine spaltenweise Sortierfunktion.

 

"Einfache" FAQs bestehen aus einer Frage und der dazugehörigen Antwort

"Einfache" FAQs bestehen aus einer Frage und der dazugehörigen Antwort

FAQ ANLEGEN: Unsere Typo3-Extension unterscheidet zwischen einfachen FAQs und FAQ-Fragebäumen. Das Modul zum Anlegen einfacher FAQs bietet Anwendern die Möglichkeit, jeweils eine FAQ-Frage sowie die dazugehörige Antwort einzugeben. Der integrierte Rich-Text-Editor bietet zusätzlich vielfältige Formatierungsmöglichkeiten und -freiheiten.

[Anmerkung: Wir haben in diesem Zusammenhang mit verschiedenen RTEs experimentiert, um Anwendern bei der Eingabe der FAQs maximalen Komfort und Funktionsumfang bieten zu können - unter anderem auch mit Aloha. Letztlich entschlossen wir uns für die Integration des CKEditor, der für unser Anwedungsszenario die besten Voraussetzungen und Features bot.] (weiterlesen…)