implements hello_dolly

51
implements Hello_Dolly Image Credit: Ky on Flickr • https://flic.kr/p/8x4bVQ Jonathan Brinley • • #wcorl • Slides: @jbrinley flightless.us/wcorl2016

Upload: jonathan-brinley

Post on 15-Apr-2017

60 views

Category:

Software


0 download

TRANSCRIPT

implementsHello_DollyImageCredit:KyonFlickr•https://flic.kr/p/8x4bVQ

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

JonathanBrinley

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

"Hello,Dolly!"

ImageCredit:ClassicFilmonFlickr•https://flic.kr/p/KD7WWE

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

"Hello,Dolly!"

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

hello.php/***@packageHello_Dolly*@version1.6*//*PluginName:HelloDollyPluginURI:http://wordpress.org/plugins/hello-dolly/Description:Thisisnotjustaplugin,itsymbolizesthehopeandenthusiasmofanentiregenerationsummedupintwowordssungmostfamouslybyLouisArmstrong:Hello,Dolly.Whenactivatedyouwillrandomlyseealyricfrom<cite>Hello,Dolly</cite>intheupperrightofyouradminscreenoneverypage.Author:MattMullenwegVersion:1.6AuthorURI:http://ma.tt/*/

functionhello_dolly_get_lyric(){ /**ThesearethelyricstoHelloDolly*/ $lyrics="Hello,DollyWell,hello,DollyIt'ssonicetohaveyoubackwhereyoubelongYou'relookin'swell,DollyIcantell,DollyYou'restillglowin',you'restillcrowin'You'restillgoin'strongWefeeltheroomswayin'Whiletheband'splayin'

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Refactor!

github.com/flightless/implements-hello-dollyImageCredit:ClassicFilmonFlickr•https://flic.kr/p/LxazKW

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

implements-hello-dolly.php/*PluginName:implementsHello_DollyDescription:Westartwitheveryone’sfavoriteWordPressplugin,“Hello,Dolly”.Withadramaticwaveofourhands,wespeakthemagicalword:“Refactor!”Let’sseehowfarwecango.Author:JonathanBrinleyVersion:2.0Contributors:MattMullenweg*/

namespaceHello_Dolly;

//Startthepluginadd_action('plugins_loaded',function(){ require_once__DIR__.'/vendor/autoload.php'; Hello_Dolly_Plugin::init(); do_action('hello_dolly/init');},1,0);

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Composer

AutoloadingLibraries

getcomposer.org

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Composercomposerinit

{"name":"flightless/implements-hello-dolly","description":"Westartwitheveryone’sfavoriteWordPressplugin,“Hello,Dolly”.Withadramaticwaveofourhands,wespeakthemagicalword:“Refactor!”Let’sseehowfarwecango.""type":"wordpress-plugin","license":"GPL-2.0","authors":[{"name":"JonathanBrinley","email":"[email protected]"}]}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

composer.json{"name":"flightless/implements-hello-dolly","description":"Westartwitheveryone’sfavoriteWordPressplugin,“Hello,Dolly”.Withadramaticwaveofourhands,wespeakthemagicalword:“Refactor!”Let’sseehowfarwecango.""type":"wordpress-plugin","license":"GPL-2.0","authors":[{"name":"JonathanBrinley","email":"[email protected]"}],"autoload":{"psr-4":{"Hello_Dolly\\":"src/"}}}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Codeceptioncomposerrequire--devlucatume/wp-browser

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Codeception

composerinstall--no-dev

{"name":"flightless/implements-hello-dolly",/*...*/"autoload":{"psr-4":{"Hello_Dolly\\":"src/"}},"require-dev":{"lucatume/wp-browser":"^1.16"}}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

WPLoadervendor/bin/wpceptbootstrap

https://github.com/lucatume/wp-browser

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

tests/integration/Hello_Dolly/Hello_Dolly_Plugin_Test.phpnamespaceHello_Dolly;useCodeception\TestCase\WPTestCase;

classHello_Dolly_Plugin_TestextendsWPTestCase{ publicfunctiontest_get_instance(){ $instance=Hello_Dolly_Plugin::instance(); $this->assertInstanceOf('Hello_Dolly\\Hello_Dolly_Plugin',$instance); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

implements-hello-dolly.phpnamespaceHello_Dolly;

//Startthepluginadd_action('plugins_loaded',function(){ require_once__DIR__.'/vendor/autoload.php'; Hello_Dolly_Plugin::init(); do_action('hello_dolly/init');},1,0);

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

src/Hello_Dolly_Plugin.phpnamespaceHello_Dolly;

/***InitializestheHello,Dollyplugin*/classHello_Dolly_Plugin{ /**@varstatic*/ privatestatic$instance;

/** *Initializetheplugin */ publicstaticfunctioninit(){ self::instance(); }

/** *Gettheglobalinstanceoftheclass *@returnstatic */ publicstaticfunctioninstance(){ if(empty(static::$instance)){ static::$instance=newstatic(); } returnstatic::$instance;

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

FirstFivePrinciplesSingleresponsibilityprincipleOpen/closedprincipleLiskovsubstitutionprincipleInterfacesegregationprincipleDependencyinversionprinciple

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

SingleresponsibilityprincipleTurnastringoflyricsintoanarrayGetarandomlinefromthelyricsarrayTexturizealineoflyricsWraplyricsinaparagraphtagBuildlanguage-appropriateCSSrulesPrintthelyricstothebrowserPrintthestylerulestothebrowserHookintoWordPress

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_CollectionResponsibility

Fetchasinglelinefromanarrayoflyrics

Whywoulditchange?

Ifthealgorithmtofetchalinechanged

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

tests/integration/Hello_Dolly/Lyrics/Lyric_Collection_Test.phpnamespaceHello_Dolly\Lyrics;useCodeception\TestCase\WPTestCase;

classLyric_Collection_TestextendsWPTestCase{ publicfunctiontest_get_lyric(){ $lyrics=[]; for($i=0;$i<10;$i++){ $lyrics[]=rand_str(mt_rand(0,32)).''.rand_str(mt_rand(0,32)).''.rand_str(mt_rand(0,32)); }

$collection=newLyric_Collection($lyrics); for($i=0;$i<20;$i++){ $this->assertContains($collection->get_lyric(),$lyrics); } }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_CollectionnamespaceHello_Dolly\Lyrics;

classLyric_CollectionimplementsLyric_Collection_Interface{ /**@varstring[]*/ protected$lyrics;

/**@varint*/ protected$count=0;

/** *Lyric_Collectionconstructor. * *@paramarray$lyricsAnarrayofsingle-linestrings */ publicfunction__construct(array$lyrics){ $this->lyrics=array_values($lyrics); $this->count=count($this->lyrics); }

publicfunctionget_lyric(){ return$this->get_random_lyric(); }

/** *Getarandomitemfromthelistoflyrics

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_Collection_InterfacenamespaceHello_Dolly\Lyrics;

/***InterfaceLyric_Collection_Interface**Implementorswillreturnasinglelineoflyrics*/interfaceLyric_Collection_Interface{ /** *@returnstringAsinglelineoflyrics */ publicfunctionget_lyric();}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_Collection_FactoryResponsibility

TransformastringoflyricsintoaLyric_CollectionWhywoulditchange?

Ifthereturnvalueshouldbeadifferentclass

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

tests/integration/Hello_Dolly/Lyrics/Lyric_Collection_Factory_Test.php

namespaceHello_Dolly\Lyrics;useCodeception\TestCase\WPTestCase;

classLyric_Collection_Factory_TestextendsWPTestCase{ publicfunctiontest_create_collection(){ $lyrics=[]; for($i=0;$i<10;$i++){ $lyrics[]=rand_str(mt_rand(0,32)).''.rand_str(mt_rand(0,32)).''.rand_str(mt_rand(0,32)); } $string=implode("\n",$lyrics); $factory=newLyric_Collection_Factory(); $collection=$factory->create_collection($string);

$this->assertInstanceOf('Hello_Dolly\\Lyrics\\Lyric_Collection',$collection); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_Collection_FactorynamespaceHello_Dolly\Lyrics;

/***ClassLyric_Collection_Factory**CreatesaLyric_Collectioninstancefrom*astringoflyrics.*/classLyric_Collection_FactoryimplementsLyric_Collection_Factory_Interface{ /** *@paramstring$lyrics *@returnLyric_Collection */ publicfunctioncreate_collection($lyrics){ $lyrics=explode("\n",$lyrics); returnnewLyric_Collection($lyrics); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Lyrics\Lyric_Collection_Factory_InterfacenamespaceHello_Dolly\Lyrics;

/***InterfaceLyric_Collection_Factory_Interface**CreatesaLyric_Collection_Interfacefroma*multi-linestringoflyrics.*/interfaceLyric_Collection_Factory_Interface{ /** *@paramstring$lyricsAmulti-linestringoflyrics *@returnLyric_Collection_Interface */ publicfunctioncreate_collection($lyrics);}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

FormattingResponsibility

Applywptexturize()toastringWrapastringinaparagraphtagwithanID

Whywoulditchange?

Theformattingalgorithmchanges

TheHTMLelementchanges

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Decorator

format(string)String_Formatterformat(string)

String_Formatter

format(string)String_Formatter_Interfaceformat(string)

String_Formatter_Interface

html_id__construct(formatter,html_id)decorate(string)

Paragraph_Taghtml_id__construct(formatter,html_id)decorate(string)

Paragraph_Tagdecorate(string)

WP_Texturize_Formatterdecorate(string)

WP_Texturize_Formatter

formatter__construct(formatter)format(string)decorate(string)

String_Formatter_Decoratorformatter__construct(formatter)format(string)decorate(string)

String_Formatter_Decorator

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\String_Formatter_InterfacenamespaceHello_Dolly\Formatting;

/***InterfaceString_Formatter_Interface**Implementorswillformatandreturnastring.*/interfaceString_Formatter_Interface{ /** *@paramstring$stringThestringtobeformatted *@returnstringTheformattedstring */ publicfunctionformat($string);}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\String_FormatternamespaceHello_Dolly\Formatting;useCodeception\TestCase\WPTestCase;

classString_Formatter_TestextendsWPTestCase{ publicfunctiontest_passthrough(){ $string=rand_str(); $passthrough=newString_Formatter();

$this->assertEquals($string,$passthrough->format($string)); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\String_FormatternamespaceHello_Dolly\Formatting;

/***ClassString_Formatter**Apassthroughformatterthatreturnsthegivenstring*/classString_FormatterimplementsString_Formatter_Interface{ publicfunctionformat($string){ return$string; }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\String_Formatter_DecoratornamespaceHello_Dolly\Formatting;

/***ClassString_Formatter_Decorator**Baseclassforstringdecorators.*/abstractclassString_Formatter_DecoratorimplementsString_Formatter_Interface{ /**@varString_Formatter_Interface*/ protected$formatter; publicfunction__construct(String_Formatter_Interface$formatter){ $this->formatter=$formatter; }

publicfunctionformat($string){ $string=$this->formatter->format($string); return$this->decorate($string); }

abstractprotectedfunctiondecorate($string);}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\WP_Texturize_FormatternamespaceHello_Dolly\Formatting;useCodeception\TestCase\WPTestCase;

classWP_Texturize_Formatter_TestextendsWPTestCase{ publicfunctiontest_texturization(){ $string="You'relookin'swell,Dolly"; $texturized_string=wptexturize($string); $this->assertNotEquals($string,$texturized_string);

$formatter=newWP_Texturize_Formatter(newString_Formatter()); $this->assertEquals($texturized_string,$formatter->format($string)); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\WP_Texturize_FormatternamespaceHello_Dolly\Formatting;

/***ClassWP_Texturize_Formatter**Formatsastringwithwptexturize()*@seewptexturize()*/classWP_Texturize_FormatterextendsString_Formatter_Decorator{ protectedfunctiondecorate($string){ returnwptexturize($string); }}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\Paragraph_TagnamespaceHello_Dolly\Formatting;useCodeception\TestCase\WPTestCase;

classParagraph_Tag_TestextendsWPTestCase{ publicfunctiontest_paragraph_tag(){ $string=rand_str(); $id=rand_str();

$formatter=newParagraph_Tag(newString_Formatter(),$id);

$expected=sprintf('<pid="%s">%s</p>',$id,$string); $this->assertEquals($expected,$formatter->format($string)); }

publicfunctiontest_escaped_id(){ $string=rand_str(); $id=rand_str(8).''.rand_str(8); $escaped_id=sanitize_html_class($id); $this->assertNotEquals($id,$escaped_id);

$formatter=newParagraph_Tag(newString_Formatter(),$id);

$expected=sprintf('<pid="%s">%s</p>',$escaped_id,$string); $this->assertEquals($expected,$formatter->format($string)); }

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Formatting\Paragraph_TagnamespaceHello_Dolly\Formatting;

/***ClassParagraph_Tag**WrapsastringinaparagraphtagwithanID*/classParagraph_TagextendsString_Formatter_Decorator{ /**@varstring*/ protected$html_id;

/** *Paragraph_Tagconstructor. * *@paramString_Formatter_Interface$formatter *@param$html_id */ publicfunction__construct(String_Formatter_Interface$formatter,$html_id){ parent::__construct($formatter); $this->html_id=$html_id; }

protectedfunctiondecorate($string){ returnsprintf('<pid="%s">%s</p>',sanitize_html_class($this->html_id),$string); }

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

<pid="dolly">You’relookin’swell,Dolly</p>

$formatter=newParagraph_Tag(newWP_Texturize_Formatter(newString_Formatter()),'dolly');return$formatter->format("You'relookin'swell,Dolly");

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Styles\Style_Rules_InterfacenamespaceHello_Dolly\Styles;

/***InterfaceStyle_Rules_Interface**GeneratesalistofCSSproperties*/interfaceStyle_Rules_Interface{

/** *@returnstring */ publicfunctionget_styles();}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Styles\Directional_Style_RulesnamespaceHello_Dolly\Styles;

/***ClassDirectional_Style_Rules**Generatesstylesforthegiventextdirection*/classDirectional_Style_RulesimplementsStyle_Rules_Interface{ protected$side;

/** *Directional_Style_Rulesconstructor. * *@paramstring$sideThesidetextfloatsto.'left'or'right' */ publicfunction__construct($side){ if(empty($side)){ thrownew\InvalidArgumentException(__('$this->sidemustbesettoanon-emptyvalue')); } $this->side=$side; }

publicfunctionget_styles(){ return" float:{$this->side};

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Styles\Style_Printer_InterfacenamespaceHello_Dolly\Styles;

/***InterfaceStyle_Printer_Interface**PrintsCSSstyles*/interfaceStyle_Printer_Interface{ /** *@paramStyle_Rules_Interface$styles *@returnvoid */ publicfunctionprint_styles(Style_Rules_Interface$styles);}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Styles\Style_PrinternamespaceHello_Dolly\Styles;

/***ClassStyle_Printer**PrintsthegivenstylerulesfortheelementwiththegivenID*/classStyle_PrinterimplementsStyle_Printer_Interface{ protected$html_id;

/** *Style_Printerconstructor. * *@paramstring$html_idTheIDofthetargetedDOMelement */ publicfunction__construct($html_id){ $this->html_id=$html_id; }

/** *@paramStyle_Rules_Interface$styles *@returnvoid */ publicfunctionprint_styles(Style_Rules_Interface$styles){ $rules=$styles->get_styles();

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

src/Hello_Dolly_Plugin.phpprivatefunctionhooks(){ add_action('admin_head',[$this,'print_admin_css']); add_action('admin_notices',[$this,'print_admin_notice']);}

publicfunctionprint_admin_css(){ $style_rules=$this->get_style_rules(); $printer=$this->get_style_printer(); $printer->print_styles($style_rules);}

publicfunctionprint_admin_notice(){ $lyrics=$this->get_lyric_collection(); $printer=$this->get_lyric_printer(); $printer->render($lyrics->get_lyric());}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

src/Hello_Dolly_Plugin.php/***@returnStyle_Rules_Interface*/privatefunctionget_style_rules(){ if(is_rtl()){ $style_rules=$this->container['style_rules.rtl']; }else{ $style_rules=$this->container['style_rules.ltr']; } returnapply_filters('hello_dolly/style_rules',$style_rules);}

/***@returnStyle_Printer_Interface*/privatefunctionget_style_printer(){ $printer=$this->container['style_printer']; returnapply_filters('hello_dolly/style_printer',$printer);}

/***@returnLyric_Collection_Interface*/privatefunctionget_lyric_collection(){ $collection=$this->container['lyrics.collection'];

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

src/Hello_Dolly_Plugin.php/***Initializetheplugin**@returnvoid*/publicstaticfunctioninit(Container$container){ $instance=self::instance(); $instance->container=$container; $instance->hooks();}

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

DependencyInjectionContainerAura.DiPHP-DIPimpleSymphony\DependencyInjectionZend\Di

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

Pimplecomposerrequirepimple/pimple

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

implements-hello-dolly.phpnamespaceHello_Dolly;usePimple\Container;

//Startthepluginadd_action('plugins_loaded',function(){ require_once__DIR__.'/vendor/autoload.php'; $container=newContainer(); $container->register(newService_Provider()); Hello_Dolly_Plugin::init($container); do_action('hello_dolly/init',Hello_Dolly_Plugin::instance(),$container);},1,0);

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

src/Service_Provider.phpnamespaceHello_Dolly;

useHello_Dolly\Formatting\Paragraph_Tag;useHello_Dolly\Formatting\String_Formatter;useHello_Dolly\Formatting\WP_Texturize_Formatter;useHello_Dolly\Lyrics\Lyric_Collection_Factory;useHello_Dolly\Printing\Formatted_Printer;useHello_Dolly\Styles\Directional_Style_Rules;useHello_Dolly\Styles\Style_Printer;usePimple\Container;usePimple\ServiceProviderInterface;

classService_ProviderimplementsServiceProviderInterface{ publicfunctionregister(Container$container){ $container['html_id']='dolly';

$container['lyrics']="Hello,DollyWell,hello,DollyIt'ssonicetohaveyoubackwhereyoubelongYou'relookin'swell,DollyIcantell,DollyYou'restillglowin',you'restillcrowin'You'restillgoin'strong

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

implements-hello-dolly.phpnamespaceHello_Dolly;usePimple\Container;

//Startthepluginadd_action('plugins_loaded',function(){ require_once__DIR__.'/vendor/autoload.php'; $container=newContainer(); $container->register(newService_Provider()); Hello_Dolly_Plugin::init($container); do_action('hello_dolly/init',Hello_Dolly_Plugin::instance(),$container);},1,0);

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

ResourcesimplementsHello_Dollygithub.com/flightless/implements-hello-dolly

ThePrinciplesofOOD/RobertC.Martinbutunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

InversionofControlContainersandtheDependencyInjectionpattern/MartinFowlermartinfowler.com/articles/injection.html

WPBrowser/LucaTumedeigithub.com/lucatume/wp-browsertheaveragedev.com/tag/wp-browser/

ImageCredit:NewYorkSundayNews

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016

JonathanBrinley@jbrinley•[email protected]

JonathanBrinley• •#wcorl•Slides:@jbrinley flightless.us/wcorl2016