2011-02-13

TDD utflykt i PHP land, del 6

Det tillfälle som kanske är mest spännande när man TDD:ar fram en MVP-lösning (Model-View-Presenter) är när det är dags att koppla in en riktig vy för första gången. Arbetsgången är att skapa ett GUI-element (t. ex. en dialog eller UserControl) och implementera det gränssnitt som vyn ska ha. Därefter kopplar man ihop modellen, vyn och presentatören. Om man har gjort ett bra jobb under TDD-fasen så fungerar det nästan felfritt på en gång.

I vårt fall är vyn ett Smarty-objekt med tillhörande mallfil. Gränssnittet består till största del av ett antal variabler. Vi behöver också den PHP-sida som användaren navigerar till när denna vill lägga till en punkt. Det är sidan som ansvarar för att koppla ihop de ingående delarna.

Vi börjar med koden för att visa sidan, sedan tar vi hand om återpostning av sidan.

<?php $require('common.inc.php') // Innehåller bra-att-ha-saker (t. ex. koppling till databasen) $tpl->name = 'childwp'; // $tpl är ett Smarty-objekt deklarerat i common.inc.php $presenter = new ChildWp_Presenter(); $presenter->setTypes(array(new ChildWp_Type(1, 'Parking'), new ChildWp_Type(2, 'Reference point'))); $presenter->prepare($tpl); $tpl->display(); ?>

Som synes är punktens typ hårdkodat i php-filen. Det är inte en optimal lösning, men än så länge förekommer typerna bara på ett ställe så därför gör det inget. Eftersom det är mallens jobb att beskriva sidan, är så här lite kod väntat. Dags att lägga till lite mer logik. Vi har tidigare gjort en init()-metod som kontrollerar att cachen finns och att användaren får lägga till punkter till den.

<?php $require('common.inc.php') $tpl->name = 'childwp'; $presenter = new ChildWp_Presenter(); $cacheManager = new Cache_Manager(); $presenter->init($tpl, $cacheManager); $presenter->setTypes(array(new ChildWp_Type(1, 'Parking'), new ChildWp_Type(2, 'Reference point'))); $presenter->prepare($tpl); $tpl->display(); ?>

Klassen Cache_Manager innehåller några SQL-satser, men deras exakta utformning är ointressant.

När sidan postas tillbaka så ska inmatningsfälten valideras och, om de är godkända, punkten skapas. Men om något fält inte är godkänt så ska sidan visas igen inklusive ett felmeddelande.

Tyvärr visar det sig vara problem vid återpostningen. Istället för att få upp sidan igen, så får vi ett felmeddelande som säger att cachen inte finns. Vi har tappat bort cache-ID:t. Detta löses genom att lägga till ett osynligt inmatningsfält som innehåller ID när sidan postas tillbaka. Lite större vana vid webbformulär och jag hade tänkt på det från början.

Självklart blir detta ett testfall.

function testSetCacheId() { $this->request->set(ChildWp_Presenter::req_cache_id, '234'); $presenter = $this->createPresenter(); $presenter->prepare($this); $this->assertEqual('234', $this->values[ChildWp_Presenter::tpl_cache_id]); }

Metoden prepare() tar hand om att visa de felmeddelande som finns efter validering. Det betyder att om valideringen är godkänd så ska punkten skapas och därefter ska man omdirigera tillbaka till sidan man kom från (redigera cache i det här fallet). Och om användaren trycker på avbryt så ska man också tillbaka till sidan man kom från. Hela sidan blir följande.

<?php $require('common.inc.php') $tpl->name = 'childwp'; $isSubmit = isset($_POST['submitform']); $redirect = isset($_POST['back']); $request = new Http_Request(); $presenter = new ChildWp_Presenter($request); $cacheManager = new Cache_Manager(); $presenter->init($tpl, $cacheManager); $presenter->setTypes(array(new ChildWp_Type(1, 'Parking'), new ChildWp_Type(2, 'Reference point'))); if ($isSubmit && $presenter->validate()) { $handler = new ChildWp_Handler(); $presenter->addWaypoint($handler); $redirect = true; } if ($redirect) $tpl->redirect('editcache.php?cacheid=' . $request->get(ChildWp_Presenter::req_cache_id)); $presenter->prepare($tpl); $tpl->display(); ?>

Jag skapar ett explicit Request-objekt bara för att komma åt cache-ID vid omdirigeringen. Klassen ChildWp_Handler innehåller också till största delen (ointressant) databashantering.

Det är inte speciellt mycket kod, men ändå så pass mycket att det känns som att det ligger en basklass och lurar där. Min erfarenhet säger mig dock att det är lättare att extrahera basklasser när man har två liknande fall att utgå från. Annars blir det mest spekulationer med varierande resultat. Därför låter jag det vara som det är tills vidare.

Härnäst ska vi ta hand om redigera punkt. Tanken är att samma sida ska hantera det också. Men det får bli nästa gång.

Inga kommentarer: