Slide 1

Slide 1 text

NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF

Slide 2

Slide 2 text

HOLGER WOLTERSDORF CIO • FATHER • HUSBAND • PHP DEV WITH ♥ github.com/hollodotme github.com/icehawk @hollodotme @F9T3ch

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF CONTENTS 4 HISTORY FACTS FEATURES & CODE COMPONENTS DISCUSSION

Slide 5

Slide 5 text

HISTORY

Slide 6

Slide 6 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 6 ๏ THE MVC PATTERN VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES UPDATES

Slide 7

Slide 7 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 7 ๏ THE MVC PATTERN …THE PROBLEM! VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES UPDATES !

Slide 8

Slide 8 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 8 ๏ THE MVC PATTERN …THE PROBLEM! VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES HTTP

Slide 9

Slide 9 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 9 ๏ THE MVC PATTERN …THE SOLUTION? VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES HTTP RESPONDS

Slide 10

Slide 10 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 10 "THE MVC PATTERN SOLVES A PROBLEM THAT DOESN’T EXIST IN THE WEB."

Slide 11

Slide 11 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 11 "THE MVC PATTERN SOLVES A PROBLEM THAT DOESN’T EXIST IN THE WEB."

Slide 12

Slide 12 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 12 CONTROLLER ๏ THE MVC PATTERN …CONTROLLER RESPONSIBILITIES ๏ VALIDATE USER INPUT ๏ FIND MODEL(S), REPO(S) 
 HELPER(S) OR SERVICE(S) ๏ ISSUE CHANGES ๏ EVALUATE CHANGE RESULT ๏ FIND MODEL(S), REPO(S)
 HELPER(S) OR SERVICE(S) ๏ QUERY AND FETCH DATA ๏ RENDER VIEW (2) ๏ RESPOND TO CLIENT

Slide 13

Slide 13 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 13 CONTROLLER ๏ THE MVC PATTERN …CONTROLLER RESPONSIBILITIES ๏ VALIDATE USER INPUT ๏ FIND MODEL(S), REPO(S) 
 HELPER(S) OR SERVICE(S) ๏ ISSUE CHANGES ๏ EVALUATE CHANGE RESULT ๏ FIND MODEL(S), REPO(S)
 HELPER(S) OR SERVICE(S) ๏ QUERY AND FETCH DATA ๏ RENDER VIEW (2) ๏ RESPOND TO CLIENT WRITE READ

Slide 14

Slide 14 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 14 WRITE CONTROLLER ๏ SEGREGATED RESPONSIBILITIES ๏ VALIDATE USER INPUT ๏ FIND MODEL(S), REPO(S) 
 HELPER(S) OR SERVICE(S) ๏ ISSUE CHANGES ๏ EVALUATE CHANGE RESULT ๏ FIND MODEL(S), REPO(S)
 HELPER(S) OR SERVICE(S) ๏ QUERY AND FETCH DATA ๏ RENDER VIEW (2) ๏ RESPOND TO CLIENT WRITE READ READ CONTROLLER

Slide 15

Slide 15 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 15 WRITE CONTROLLER ๏ RESPONSIBILITY SEGREGATION ๏ VALIDATE USER INPUT ๏ FIND MODEL(S), REPO(S) 
 HELPER(S) OR SERVICE(S) ๏ ISSUE CHANGES ๏ EVALUATE CHANGE RESULT ๏ FIND MODEL(S), REPO(S)
 HELPER(S) OR SERVICE(S) ๏ QUERY AND FETCH DATA ๏ RENDER VIEW (2) ๏ RESPOND TO CLIENT COMMAND QUERY READ CONTROLLER

Slide 16

Slide 16 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 16 WRITE CONTROLLER ๏ RESPONSIBILITY SEGREGATION ๏ VALIDATE USER INPUT ๏ FIND MODEL(S), REPO(S) 
 HELPER(S) OR SERVICE(S) ๏ ISSUE CHANGES ๏ EVALUATE CHANGE RESULT ๏ FIND MODEL(S), REPO(S)
 HELPER(S) OR SERVICE(S) ๏ QUERY AND FETCH DATA ๏ RENDER VIEW (2) ๏ RESPOND TO CLIENT COMMAND QUERY READ CONTROLLER RESPONSIBILITY SEGREGATION (CQRS) TA-DA!

Slide 17

Slide 17 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 17 ๏ THE CQRS PATTERN (respecting HTTP) WRITE REQUESTHANDLER APP STATE USER INPUT MODIFIES QUERIES POST CLIENT / BROWSER REDIRECT TO PAGE 2 GET READ REQUESTHANDLER PAGE 1 PAGE 2 RESPONDS

Slide 18

Slide 18 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PROJECTOR CHANGE PAGE 2 HISTORY 18 ๏ OPTIMISATION FOR READ INTENSIVE APPLICATIONS WRITE REQUESTHANDLER APP STATE USER INPUT MODIFIES POST CLIENT / BROWSER REDIRECT TO PAGE 2 GET PAGE 1 PAGE 2 CHANGE MESSAGE (ASYNC) PROJECTOR PREPARES PUB SUB QUERIES

Slide 19

Slide 19 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 19 […] the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe". https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html

Slide 20

Slide 20 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF HISTORY 20 ๏ RULES SUMMARISED (FOR WEBSITES) ๏ A POST request MUST NOT not respond with UI content ๏ A POST request SHOULD change the application state ๏ A POST request SHOULD respond with a redirect ๏ A GET request SHOULD respond with UI content 
 representing the current application state ๏ A GET request MUST NOT change the application state (read-only)

Slide 21

Slide 21 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF 21 «We need a name!» «Yeah, something cool and fast!» HISTORY

Slide 22

Slide 22 text

ICEHAWK

Slide 23

Slide 23 text

FACTS

Slide 24

Slide 24 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FACTS 24 ๏ COMPONENTS STABLE v2.2.0 STABLE v1.1.1 STABLE v1.0.0 STABLE v1.0.1 ICEHAWK SESSION FORMS PUBSUB COVERAGE 100% COVERAGE 100% COVERAGE 100% COVERAGE 100%

Slide 25

Slide 25 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FACTS 25 ๏ MAIN COMPONENT: icehawk/icehawk 1.533 Logical lines of code (LLOC) 0 composer dependencies 0 third-party php extension dependencies v2.2.0 current stable v7.x.x php compatibility (only) STRICT typed MIT license FULLY documented at icehawk.github.io LOC Lines of code 1965 Logical lines of code 1533 Comment lines of code 433 Average volume 71.86 Average comment weight 21.28 Average intelligent content 21.28 Logical lines of code by class 29 Logical lines of code by method 5 Object oriented programming Classes 52 Interface 33 Methods 279 Methods by class 5.37 Lack of cohesion of methods 0.62 Average afferent coupling 0.66 Average efferent coupling 1.15 Average instability 0.61 Complexity Average Cyclomatic complexity by class 1.65 Average Relative system complexity 17.92 Average Difficulty 2.6

Slide 26

Slide 26 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FACTS 26 ๏ OBJECTIVES ๏ Producing comprehensible and readable code ๏ Avoiding inline comments where possible (includes PHPDoc) ๏ Applying the SOLID and CLEAN CODE principles ๏ Covering all code with tests ๏ Refactoring continuously ๏ Targeting the latest PHP version ๏ Doing open source ๏ APPLICABLE FOR ๏ WEBSITES ๏ (RESTful) APIs ๏ MICRO SERVICES ๏ EVENT SOURCING

Slide 27

Slide 27 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FACTS 27 NAMING CONVENTION interface BypassesRequest {} class RequestBypass {} trait DefaultRequestBypassing {}

Slide 28

Slide 28 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FACTS 28 POST PUT PATCH DELETE GET HEAD OPTIONS WRITE REQUEST HANDLER READ REQUEST HANDLER AUTO-RESPONSE BASIC ROUTING BEHAVIOUR

Slide 29

Slide 29 text

FEATURES & CODE (SELECTION)

Slide 30

Slide 30 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 30 INSTALLATION

Slide 31

Slide 31 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 31

Slide 32

Slide 32 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 32 class IceHawk { public function __construct( $config, $delegate ) public function init() {} public function handleRequest() {} }

Slide 33

Slide 33 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 33 init(); $application->handleRequest();

Slide 34

Slide 34 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 34 DELEGATION

Slide 35

Slide 35 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - DELEGATION 35 final class IceHawkDelegate implements SetsUpEnvironment { public function setUpGlobalVars() { # Change your global vars $_SERVER, $_GET, $_POST, etc. # here, before IceHawk will use them. } public function setUpErrorHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default error handling is used unless you set up # something else here. } public function setUpSessionHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default session handling is used unless you set up # something else here. } }

Slide 36

Slide 36 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - DELEGATION 36 final class IceHawkDelegate implements SetsUpEnvironment { public function setUpGlobalVars() { # Change your global vars $_SERVER, $_GET, $_POST, etc. # here, before IceHawk will use them. } public function setUpErrorHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default error handling is used unless you set up # something else here. } public function setUpSessionHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default session handling is used unless you set up # something else here. } }

Slide 37

Slide 37 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - DELEGATION 37 final class IceHawkDelegate implements SetsUpEnvironment { public function setUpGlobalVars() { # Change your global vars $_SERVER, $_GET, $_POST, etc. # here, before IceHawk will use them. } public function setUpErrorHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default error handling is used unless you set up # something else here. } public function setUpSessionHandling( ProvidesRequestInfo $requestInfo ) { # PHP's default session handling is used unless you set up # something else here. } }

Slide 38

Slide 38 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 38 CONFIGURATION

Slide 39

Slide 39 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 39 final class IceHawkConfig implements ConfiguresIceHawk { use Defaults\Traits\DefaultRequestInfoProviding; use Defaults\Traits\DefaultReadRouting; use Defaults\Traits\DefaultWriteRouting; use Defaults\Traits\DefaultRequestBypassing; use Defaults\Traits\DefaultEventSubscribing; use Defaults\Traits\DefaultCookieProviding; use Defaults\Traits\DefaultFinalReadResponding; use Defaults\Traits\DefaultFinalWriteResponding; }

Slide 40

Slide 40 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 40 final class IceHawkConfig implements ConfiguresIceHawk { use Defaults\Traits\DefaultRequestInfoProviding; use Defaults\Traits\DefaultReadRouting; use Defaults\Traits\DefaultWriteRouting; use Defaults\Traits\DefaultRequestBypassing; use Defaults\Traits\DefaultEventSubscribing; use Defaults\Traits\DefaultCookieProviding; use Defaults\Traits\DefaultFinalReadResponding; use Defaults\Traits\DefaultFinalWriteResponding; }

Slide 41

Slide 41 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 41 final class MyHawkConfig extends IceHawkConfig { public function getReadRoutes() { return [ new ReadRoute( new Literal( '/' ), new SayHelloRequestHandler() ), ]; } public function getWriteRoutes() { return [ new WriteRoute( new Literal( '/do-something' ), new DoSomethingRequestHandler() ), ]; } }

Slide 42

Slide 42 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 42 # Literal route new ReadRoute( new Literal( '/' ), new SayHelloRequestHandler() ); # RegExp route with parameters from matches new ReadRoute( new RegExp("#^/post/([0-9]+)/?$#i", ['postId'] ), new ShowBlogPostRequestHandler() ); # NamedRegExp route with named matches new ReadRoute( new NamedRegExp("^/post/(?[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );

Slide 43

Slide 43 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 43 # Literal route new ReadRoute( new Literal( '/' ), new SayHelloRequestHandler() ); # RegExp route with parameters from matches new ReadRoute( new RegExp("#^/post/([0-9]+)/?$#i", ['postId'] ), new ShowBlogPostRequestHandler() ); # NamedRegExp route with named matches new ReadRoute( new NamedRegExp("^/post/(?[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );

Slide 44

Slide 44 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 44 # Literal route new ReadRoute( new Literal( '/' ), new SayHelloRequestHandler() ); # RegExp route with parameters from matches new ReadRoute( new RegExp("#^/post/([0-9]+)/?$#i", ['postId'] ), new ShowBlogPostRequestHandler() ); # NamedRegExp route with named matches new ReadRoute( new NamedRegExp("^/post/(?[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );

Slide 45

Slide 45 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 45 final class MyHawkConfig extends IceHawkConfig { public function getReadRoutes() { $routes = require(__DIR__ . '../config/ReadRoutes.php'); # $routes = [ # "^/post/(?[0-9]+)/?" # => MyVendor\...\ShowPostRequestHandler::class, # ]; foreach ($routes as $pattern => $handlerClass) { yield new ReadRoute( new NamedRegExp($pattern), new $handlerClass() ), } } }

Slide 46

Slide 46 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 46 REQUEST BYPASSING

Slide 47

Slide 47 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - REQUEST BYPASSING 47 final class IceHawkConfig implements ConfiguresIceHawk { use Defaults\Traits\DefaultRequestInfoProviding; use Defaults\Traits\DefaultReadRouting; use Defaults\Traits\DefaultWriteRouting; use Defaults\Traits\DefaultRequestBypassing; use Defaults\Traits\DefaultEventSubscribing; use Defaults\Traits\DefaultCookieProviding; use Defaults\Traits\DefaultFinalReadResponding; use Defaults\Traits\DefaultFinalWriteResponding; }

Slide 48

Slide 48 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - REQUEST BYPASSING 48 final class MyHawkConfig extends IceHawkConfig { public function getRequestBypasses() { return [ new RequestBypass( new Literal('/came/via/get'), '/do/some/write/action', HttpMethod::POST ), ]; } public function getWriteRoutes() { return [ new WriteRoute( new Literal( '/do/some/write/action' ), new DoSomethingRequestHandler() ), ]; } }

Slide 49

Slide 49 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - REQUEST BYPASSING 49 final class MyHawkConfig extends IceHawkConfig { public function getRequestBypasses() { return [ new RequestBypass( new Literal('/came/via/get'), '/do/some/write/action', HttpMethod::POST ), ]; } public function getWriteRoutes() { return [ new WriteRoute( new Literal( '/do/some/write/action' ), new DoSomethingRequestHandler() ), ]; } }

Slide 50

Slide 50 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 50 REQUEST HANDLERS

Slide 51

Slide 51 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - REQUEST HANDLERS 51 final class SayHelloRequestHandler implements HandlesGetRequest { public function handle(ProvidesReadRequestData $request) { $info = $request->getInfo(); $input = $request->getInput(); $cookies = $request->getCookies(); (new Page())->respond('Hello!', HttpCode::OK); } }

Slide 52

Slide 52 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - REQUEST HANDLERS 52 final class DoSomethingRequestHandler implements HandlesPostRequest { public function handle(ProvidesWriteRequestData $request) { $info = $request->getInfo(); $input = $request->getInput(); $cookies = $request->getCookies(); $files = $input->getAllUploadedFiles(); (new Redirect())->respond('/done'); } }

Slide 53

Slide 53 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 53 EVENTS & SUBSCRIBERS

Slide 54

Slide 54 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 54 final class IceHawkConfig implements ConfiguresIceHawk { use Defaults\Traits\DefaultRequestInfoProviding; use Defaults\Traits\DefaultReadRouting; use Defaults\Traits\DefaultWriteRouting; use Defaults\Traits\DefaultRequestBypassing; use Defaults\Traits\DefaultEventSubscribing; use Defaults\Traits\DefaultCookieProviding; use Defaults\Traits\DefaultFinalReadResponding; use Defaults\Traits\DefaultFinalWriteResponding; }

Slide 55

Slide 55 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 55 final class MyHawkConfig extends IceHawkConfig { public function getEventSubscribers() : array { return [ new LogSubscriber(), ]; } }

Slide 56

Slide 56 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 56 final class LogSubscriber extends AbstractEventSubscriber { private $startTime; public function getAcceptedEvents() : array { return [ IceHawk\IceHawk\Events\HandlingReadRequestEvent::class, IceHawk\IceHawk\Events\ReadRequestWasHandledEvent::class, ]; } public function whenHandlingReadRequest(HandlingReadRequestEvent $event) { $this->startTime = microtime(true); } public function whenReadRequestWasHandled(ReadReqeustWasHandledEvent $event) { error_log( sprintf( "Your app took %f seconds to handle the request on URI: %s", (microtime(true) - $this->startTime), $event->getRequestInfo()->getUri() ), 3, 'file.log' ); } }

Slide 57

Slide 57 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE 57 FINAL RESPONDING

Slide 58

Slide 58 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 58 final class IceHawkConfig implements ConfiguresIceHawk { use Defaults\Traits\DefaultRequestInfoProviding; use Defaults\Traits\DefaultReadRouting; use Defaults\Traits\DefaultWriteRouting; use Defaults\Traits\DefaultRequestBypassing; use Defaults\Traits\DefaultEventSubscribing; use Defaults\Traits\DefaultCookieProviding; use Defaults\Traits\DefaultFinalReadResponding; use Defaults\Traits\DefaultFinalWriteResponding; }

Slide 59

Slide 59 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 59 final class MyHawkConfig extends IceHawkConfig { public function getFinalReadResponder() : RespondsFinallyToReadRequest { return MyFinalReadResponder(); } }

Slide 60

Slide 60 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 60 final class MyFinalReadResponder implements RespondsFinallyToReadRequest { public function handleUncaughtException( \Throwable $throwable, ProvidesReadReqeustData $request ) { try { throw $throwable; } catch (UnresolvedRequest $e) { (new NotFound())->respond(); } catch (\Throwable $e) { (new InternalServerError())->respond(); } } }

Slide 61

Slide 61 text

COMPONENTS

Slide 62

Slide 62 text

SESSION

Slide 63

Slide 63 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF SESSION 63 ๏ ABSTRACT REGISTRY ๏ Needs inheritance ๏ Implement typed getters, setters, issets and unsets ๏ Allows registration of data mappers

Slide 64

Slide 64 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF SESSION - EXAMPLE IMPLEMENTATON 64 final class Session extends AbstractSession { const KEY_SOME_STRING_VALUE = 'someStringValue'; public function getSomeStringValue() : string { return $this->get( self::KEY_SOME_STRING_VALUE ); } public function setSomeStringValue( string $value ) { $this->set( self::KEY_SOME_STRING_VALUE, $value ); } public function isSomeStringValueSet() : bool { return $this->isset( self::KEY_SOME_STRING_VALUE ); } public function unsetSomeStringValue() { $this->unset( self::KEY_SOME_STRING_VALUE ); } }

Slide 65

Slide 65 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF SESSION - DATA MAPPER 65 final class MyDataMapper implements MapsSessionData { public function toSessionData( $value ) { return base64_encode( $value ); } public function fromSessionData( $sessionData ) { return base64_decode( $sessionData ); } }

Slide 66

Slide 66 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF SESSION - REGISTER DATA MAPPERS 66 # Add the data mapper for all keys in the registry $session->addDataMapper( new MyDataMapper() ); # Add the data mapper for one specific key in the registry $session->addDataMapper( new MyDataMapper(), [Session::KEY_SOME_STRING_VALUE] ); # Add the data mapper for multiple keys in the registry $session->addDataMapper( new MyDataMapper(), [ Session::KEY_SOME_STRING_VALUE, Session::KEY_SOME_OTHER_VALUE ] );

Slide 67

Slide 67 text

FORMS

Slide 68

Slide 68 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FORMS 68 ๏ DTO TO BE STORED IN SESSION ๏ CSRF protection using tokens (with expiration) ๏ Data pre-setting ๏ Gets input validation feedback (with severity) on write side ๏ Provides input validation feedback on read side

Slide 69

Slide 69 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FORMS - READ SIDE INITIALISATION 69 $form = new Form( new FormId('profile') ); $form->renewToken(); if ( !$form->wasDataSet() ) { # Set up some default data (single) $form->set( 'username', 'johndoe' ); }

Slide 70

Slide 70 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF FORMS - WRITE SIDE 70 $form = $session->getForm( new FormId('profile') ); $token = Token::fromString($input->get('token')); $form->guardTokenIsValid($token); $form->addFeedback( 'user', new Feedback( 'Invalid username', Feedback::ERROR ) );

Slide 71

Slide 71 text

PUBSUB

Slide 72

Slide 72 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PUBSUB 72 ๏ BASIC PUBLISH SUBSCRIBE SYSTEM TO DECOUPLE BUSINESS LOGIC ๏ Defines interfaces for messages, channels and subscribers ๏ Provides a message bus for publishing and subscribing ๏ Provides abstract message subscriber with auto-method resolving

Slide 73

Slide 73 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PUBSUB - A MESSAGE 73 final class YourMessage implements CarriesInformation { public function getMessageId() : IdentifiesMessage { return new MessageId('message-xyz'); } public function getMessageName() : NamesMessage { return new MessageName('User email address changed'); } public function getContent() : string { return '[email protected]'; } }

Slide 74

Slide 74 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PUBSUB - A SUBSCRIBER 74 final class YourSubscriber extends AbstractMessageSubscriber { protected function whenSomethingHadHappened( YourMessage $yourMessage, Channel $channel ) { printf( 'Message named "%s" with ID "%s" ' . 'was published on channel "%" with content: "%s"', $yourMessage->getMessageName(), $yourMessage->getMessageId(), $channel, $yourMessage->getContent() ); } }

Slide 75

Slide 75 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PUBSUB - THE SUBSCRIPTION 75 $messageBus = new MessageBus(); $messageBus->subscribe( new Channel('ListenToMe'), new YourSubscriber() );

Slide 76

Slide 76 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF PUBSUB - PUBLISH 76 $messageBus->publish( new Channel('ListenToMe'), new YourMessage() );

Slide 77

Slide 77 text

FULL DOCUMENTATION AT icehawk.github.io

Slide 78

Slide 78 text

QUESTIONS?

Slide 79

Slide 79 text

THANK YOU! github.com/hollodotme @hollodotme / @F9T3ch fortuneglobe.com phpug-dresden.org @phpugdd HOLGER WOLTERSDORF https://hollo.me icehawk.github.io speakerdeck.com/hollodotme Slides available at:

Slide 80

Slide 80 text

ICEHAWK FRAMEWORK • NOVEMBER 21st 2017 • PHP USERGROUP MÜNSTER HOLGER WOLTERSDORF LINKS / REFERENCES 80 ๏ MVC-Pattern: http://martinfowler.com/eaaDev/uiArchs.html ๏ CQRS-Pattern: http://martinfowler.com/bliki/CQRS.html ๏ GET/HEAD methods: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html ๏ SOLID principles https://en.wikipedia.org/wiki/SOLID_(object-oriented_design) ๏ "Clean Code" by Robert C. Martin: http://amzn.to/2dthxQn ๏ "Traitful" Configs: https://hollo.me/php/traitful-configs.html ๏ IceHawk Gitter chat: https://gitter.im/icehawk/Lobby