moderne webentwicklung
TRANSCRIPT
ONLINE KARRIERETAG MÜNCHEN 2016
AGENDA MODERNE WEBENTWICKLUNG
▸ TEIL 1: TESTGETRIEBENE ENTWICKLUNG ▸ CODEBEISPIEL
▸ TEIL 2: SYMFONY ENVIRONMENT ▸ VERSAND EINER NEWSLETTER KAMPAGNE
BEISPIELCODE: DATA CLASS
WAS MACHT DIESER CODE?1<?php23classdata4{5private$data;67publicfunction__construct($data)8{9$this->data=$data;10}1112publicfunctionget()13{14$fp=array();15foreach($this->dataas$o){16if($o->bList==1){//WhatisbList?17$fp[]=$o;18}19}2021return$fp;22}23}24
WAS PASSIERT, WENN …▸ … kein Array von Objekten
übergeben wird?
▸ … die Objekte nicht public $bList; enthalten?
▸ … du diese Klasse erweitern sollst?
?
EXKURS: TESTGETRIEBENE ENTWICKLUNG
RED » GREEN » REFACTOR - ZYKLUS
TEST FEHLGESCHLAGEN
TEST SCHREIBEN
TEST ERFOLGREICH
CODE HINZUFÜGEN
ABLAUF STÄNDIG WIEDERHOLEN
CODE VERBESSERN
REFACTOR
ERSTER TEST
PRODUCT LIST TEST1<?php23namespaceTests\Demo;45useDemo\ProductList;67classProductListTestextends\PHPUnit_Framework_TestCase8{9publicfunctiontestProductList()10{11 $productList=newProductList();12}13}14
FAILURES!Tests:1,Assertions:0,Errors:1.
MINIMALE IMPLEMENTIERUNG
IMPLEMENTIERUNG PRODUCT LIST1<?php23namespaceDemo;45classProductList6{78}9
OK(1test,0assertions)
EXKURS: WAS IST EIN INTERFACE
INTERFACE: LISTBARES PRODUKT1<?php23namespaceDemo;45interfaceProductListInterface6{7/**8*Checksiftheproductislisted.9*10*@returnbool11*/12publicfunctionisListed();13}14
Mit Hilfe des Interface schließen wir einen „Vertrag“, dass die Methode „isListed“ vorhanden ist.
ERWEITERUNG DES TESTFALLS
ERWEITERUNG PRODUCT LIST TEST8classProductListTestextends\PHPUnit_Framework_TestCase9{10publicfunctiontestProductList()11{12$listedProduct=$this->prophesize(ProductListInterface::class);13$listedProduct->isListed()->willReturn(true);14$notListedProduct=$this->prophesize(ProductListInterface::class);15$notListedProduct->isListed()->willReturn(false);1617$productList=newProductList(18[19$listedProduct->reveal(),20$notListedProduct->reveal(),21]22);2324$this->assertCount(1,$productList->getListedProducts());25$this->assertContains($listedProduct->reveal(),26$productList->getListedProducts());27}28}29
GELISTETNICHT
GELISTET
BEIDEÜBERGEBEN
NUR 1 PRODUKT ERWARTET
FEHLERMELDUNG
ERGEBNIS PRODUCT LIST TESTTherewas1error:
1)Tests\Demo\ProductListTest::testProductListError:CalltoundefinedmethodDemo\ProductList::getListedProducts()
FAILURES!Tests:1,Assertions:0,Errors:1.
FINALE IMPLEMENTIERUNG DER PRODUCT LIST KLASSE
IMPLEMENTIERUNG PRODUCT LIST5classProductList6{7private$products=[];89publicfunction__construct(array$productList)10{11foreach($productListas$product){12$this->addProduct($product);13}14}1516publicfunctionaddProduct(ProductListInterface$product)17{18array_push($this->products,$product);19}2021publicfunctiongetListedProducts()22{23returnarray_filter(24$this->products,25function(ProductListInterface$product){26return$product->isListed();27}28);29}30}31
NUR ARRAYERLAUBT
INTERFACE IMPLEMENTIERT
NUR GELISTETEPRODUKTE
3classdata4{5private$data;67publicfunction__construct($data)8{9$this->data=$data;10}1112publicfunctionget()13{14$fp=array();15foreach($this->dataas$o){16if($o->bList==1){17$fp[]=$o;18}19}2021return$fp;22}23}24
5classProductList6{7private$products=[];89publicfunction__construct(array$productList)10{11foreach($productListas$product){12$this->addProduct($product);13}14}1516publicfunctionaddProduct(ProductListInterface$product)17{18array_push($this->products,$product);19}2021publicfunctiongetListedProducts()22{23returnarray_filter(24$this->products,25function(ProductListInterface$product){26return$product->isListed();27}28);29}30}31
GEGENÜBERSTELLUNG
VERGLEICH: VORHER «–» NACHHER
FAZIT: ▸ Einfacherer und sprechender Code▸ Code weniger fehleranfällig▸ Tests stetig wiederholbar
WAS IST DIE SYMFONY WELT?
SYMFONY
▸ Komponenten
▸ 36 einzelne Bibliotheken in PHP
▸ Open Source und in vielen Projekten oder Frameworks verwendet
▸ Full-Stack-Frameworkbasierend auf den Komponenten bildet Symfony ein vollständiges Framework
ÜBERSICHT DES ABLAUFS
BEISPIEL: VERSAND EINER NEWSLETTER E-MAIL
NEWSLETTER
MAILERinstanziiert
Array an Empfängern
jede Instanz sendet eineE-Mail an einen Empfänger
BEISPIEL EINER MÖGLICHEN IMPLEMENTIERUNG
KLASSE: MAILER1<?php23classMailer4{5private$fromEmail;6private$fromName;7private$header;89publicfunction__construct($fromEmail,$fromName,$header)10{11$this->fromEmail=$fromEmail;12$this->fromName=$fromName;13$this->header="From:$fromName<$fromEmail>\n".$header;14}1516publicfunctionsend($to,$subject,$message)17{18mail($to,$subject,$message,$this->header);19}20}21
NICHT TESTBAR!
BEISPIEL EINER MÖGLICHEN IMPLEMENTIERUNG
KLASSE: NEWSLETTER1<?php23classNewsletter4{5private$mailer;67publicfunction__construct()8{9$this->mailer=newMailer('[email protected]','DemoNews','Reply-To:[email protected]');10}1112publicfunctionsend($recipients,$subject,$message){13foreach($recipientsas$to){14$this->mailer->send($to,$subject,$message);15}16}17}18
▸ Nicht testbar, erweiterbar und wiederverwendbar▸ Kein Fehlerhandling & kaum Chancen Fehler zu findenFAZIT:
DIREKTEABHÄNGIGKEIT
ENTWICKLUNG IM SYMFONY ENVIRONMENT
„THE SYMFONY WAY“
▸ Dependency Injection löst die Abhängigkeiten auf
▸ Kleine testgetriebene Klassen
▸ Config stellt einfache Konfiguration bereit
▸ Debug hilft beim Testen
▸ Framework integriert die Bibliothek SwiftMailer und stellt umfangreiche Konfiguration zur Verfügung
KONFIGURATION DES SERVICE CONTAINERS MIT HILFE VON YAML
DEPENDENCY INJECTION KONFIGURATIONparameters:mailer.transport:sendmail
services:mailer:sendmailclass:Mailerarguments:['%mailer.transport%']newsletter_manager:class:NewsletterManagercalls:-[setMailer‚['@mailer']]
BEISPIEL: UNIT-TEST FÜR NEWSLETTER-MANAGER
NEWSLETTER MANAGER TEST1<?php23namespaceTests\Demo;45useDemo\MailerInterface;6useDemo\Message;7useDemo\NewsletterManager;89classNewsletterManagerTestextends\PHPUnit_Framework_TestCase10{11publicfunctiontestNewsletterManager()12{13$message=newMessage('TestBetreff','Test-InhaltNewsletter');14$mailer=$this->prophesize(MailerInterface::class);15$mailer->send('[email protected]',$message)->shouldBeCalled();1617$newsletterManager=newNewsletterManager();18$newsletterManager->setMailer($mailer->reveal());19$newsletterManager->sendMail(['[email protected]'],$message);20}21}22
STUB
IMPLEMENTIERUNG DES NEWSLETTER-MANAGERS
NEWSLETTER-MANAGER1<?php23namespaceDemo;45classNewsletterManager6{7private$mailer;89publicfunctionsetMailer(MailerInterface$mailer)10{11$this->mailer=$mailer;12}1314publicfunctionsendMail(array$recipients,Message$message)15{16foreach($recipientsas$recipient){17$this->mailer->send($recipient,$message);18}19}20}21
SYMFONY ENVIRONMENT: DEPENDENCY INJECTION
VERWENDUNG DES NEWSLETTER-MANAGERS
▸ Im Controller oder Command kann nun der NewsletterManager mit Hilfe der Dependency Injection verwendet werden:
▸ Symfony liest die Konfiguration aus und erstellt den NewsletterManager mit allen Abhängigkeiten
$newsletterManager=$this->get('newsletter_manager');$newsletterManager->send($recipients,$message);
SYMFONY ENVIRONMENT: ERWEITERUNG
ZUSÄTZLICHE ANFORDERUNGEN
▸ Im Test- & Entwicklungssystem sollen keine E-Mails versendet werden
▸ Einfache Konfiguration des Absenders
▸ Möglichkeit, über Gmail E-Mails zu versenden
▸ Bringt Symfony bereits alles mit
SWIFTMAILER BIBLIOTHEK
KONFIGURATION E-MAIL-VERSAND
▸ Versand deaktivierenswiftmailer:disable_delivery:true
swiftmailer:delivery_address:[email protected]
swiftmailer:transport:'gmail'username:'[email protected]'password'myGmailPassword'
▸ Versand an Test-Empfänger
▸ Versand über Gmail
MODERNE WEBENTWICKLUNG
DANKE FÜR DIE AUFMERKSAMKEIT
▸ Sebastian Blum [email protected]
▸ Präsentation auf unserer Webseite# https://www.sblum.de/treffen
▸ Café an unserem Stand