IceHawk - A PHP7 micro framework respecting CQRS

IceHawk - A PHP7 micro framework respecting CQRS

An introduction to the OSS micro framework "IceHawk" with a brief history of its emergence and approach, some facts about the project and its scope of application, an overview of features and code of the main component and a short look at additional components.

Talk presented at PHP Usergroup Munich

8ad631306f5ab343446a967b98e64c0e?s=128

Holger Woltersdorf

July 26, 2017
Tweet

Transcript

  1. JULY, 26TH 2017 • PHPUG • MUNICH HOLGER WOLTERSDORF

  2. HOLGER WOLTERSDORF CIO • FATHER • HUSBAND • PHP DEV

    WITH ♥ github.com/hollodotme github.com/icehawk @hollodotme @F9T3ch
  3. None
  4. SEPTEMBER 22nd ARNE BLANKERTS thePHPcc SEBASTIAN HEUER kartenmacherei JAN BURKL

    ZEND MARCO PIVETTA Ocramius STEPHAN HOCHDÖRFER bitExpert ALEXANDER MIERTSCH prooph software CHRISTIAN LÜCK reactPHP
  5. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF CONTENTS 5 HISTORY FACTS FEATURES & CODE COMPONENTS DISCUSSION
  6. HISTORY

  7. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 7 ๏ THE MVC PATTERN VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES UPDATES
  8. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 8 ๏ THE MVC PATTERN …THE PROBLEM! VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES UPDATES !
  9. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 9 ๏ THE MVC PATTERN …THE PROBLEM! VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES HTTP
  10. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 10 ๏ THE MVC PATTERN …THE SOLUTION? VIEW 1 VIEW 2 CONTROLLER MODEL USER INPUT MODIFIES HTTP RESPONDS
  11. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 11 "THE MVC PATTERN SOLVES A PROBLEM THAT DOESN’T EXIST IN THE WEB."
  12. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 12 "THE MVC PATTERN SOLVES A PROBLEM THAT DOESN’T EXIST IN THE WEB."
  13. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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
  14. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 14 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
  15. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 15 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
  16. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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
  17. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 17 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!
  18. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 18 ๏ 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
  19. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF PROJECTOR CHANGE PAGE 2 HISTORY 19 ๏ 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
  20. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 20 […] 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
  21. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF HISTORY 21 ๏ 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)
  22. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF 22 «We need a name!» «Yeah, something cool and fast!» HISTORY
  23. ICEHAWK

  24. FACTS

  25. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FACTS 25 ๏ COMPONENTS STABLE v2.1.1 STABLE v1.1.1 STABLE v1.0.0 STABLE v1.0.1 ICEHAWK SESSION FORMS PUBSUB COVERAGE 100% COVERAGE 100% COVERAGE 100% COVERAGE 100%
  26. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FACTS 26 ๏ MAIN COMPONENT: icehawk/icehawk 1.533 Logical lines of code (LLOC) 0 composer dependencies 0 third-party php extension dependencies v2.1.1 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
  27. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FACTS 27 ๏ 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
  28. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FACTS 28 NAMING CONVENTION interface BypassesRequest {} class RequestBypass {} trait DefaultRequestBypassing {}
  29. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FACTS 29 POST PUT PATCH DELETE GET HEAD OPTIONS WRITE REQUEST HANDLER READ REQUEST HANDLER AUTO-RESPONSE BASIC ROUTING BEHAVIOUR
  30. FEATURES & CODE (SELECTION)

  31. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 31 INSTALLATION
  32. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 32
  33. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 33 class IceHawk { public function __construct( $config, $delegate ) public function init() {} public function handleRequest() {} }
  34. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 34 <?php declare(strict_types = 1); namespace MyVendor\MyProject; use IceHawk\IceHawk\IceHawk; require(__DIR__ . '/../vendor/autoload.php'); $config = new IceHawkConfig(); $delegate = new IceHawkDelegate(); $application = new IceHawk( $config, $delegate ); $application->init(); $application->handleRequest();
  35. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 35 DELEGATION
  36. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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. } }
  37. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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. } }
  38. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - DELEGATION 38 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. } }
  39. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 39 CONFIGURATION
  40. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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; }
  41. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 41 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; }
  42. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 42 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() ), ]; } }
  43. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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/(?<postId>[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );
  44. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    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/(?<postId>[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );
  45. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 45 # 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/(?<postId>[0-9]+)/?$", 'i'), new ShowBlogPostRequestHandler() );
  46. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - CONFIGURATION 46 final class MyHawkConfig extends IceHawkConfig { public function getReadRoutes() { $routes = require(__DIR__ . '../config/ReadRoutes.php'); # $routes = [ # "^/post/(?<postId>[0-9]+)/?" # => MyVendor\...\ShowPostRequestHandler::class, # ]; foreach ($routes as $pattern => $handlerClass) { yield new ReadRoute( new NamedRegExp($pattern), new $handlerClass() ), } } }
  47. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE 47 REQUEST BYPASSING
  48. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE - REQUEST BYPASSING 48 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; }
  49. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN 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() ), ]; } }
  50. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE - REQUEST BYPASSING 50 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() ), ]; } }
  51. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 51 REQUEST HANDLERS
  52. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - REQUEST HANDLERS 52 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); } }
  53. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - REQUEST HANDLERS 53 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'); } }
  54. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE 54 EVENTS & SUBSCRIBERS
  55. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 55 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; }
  56. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 56 final class MyHawkConfig extends IceHawkConfig { public function getEventSubscribers() : array { return [ new LogSubscriber(), ]; } }
  57. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FEATURES & CODE - EVENTS & SUBSCRIBERS 57 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' ); } }
  58. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE 58 FINAL RESPONDING
  59. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 59 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; }
  60. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 60 final class MyHawkConfig extends IceHawkConfig { public function getFinalReadResponder() : RespondsFinallyToReadRequest { return MyFinalReadResponder(); } }
  61. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF FEATURES & CODE - FINAL RESPONDING 61 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(); } } }
  62. COMPONENTS

  63. SESSION

  64. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF SESSION 64 ๏ ABSTRACT REGISTRY ๏ Needs inheritance ๏ Implement typed getters, setters, issets and unsets ๏ Allows registration of data mappers
  65. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF SESSION - EXAMPLE IMPLEMENTATON 65 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 ); } }
  66. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF SESSION - DATA MAPPER 66 final class MyDataMapper implements MapsSessionData { public function toSessionData( $value ) { return base64_encode( $value ); } public function fromSessionData( $sessionData ) { return base64_decode( $sessionData ); } }
  67. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF SESSION - REGISTER DATA MAPPERS 67 # 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 ] );
  68. FORMS

  69. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FORMS 69 ๏ 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
  70. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FORMS - READ SIDE INITIALISATION 70 $form = new Form( new FormId('profile') ); $form->renewToken(); if ( !$form->wasDataSet() ) { # Set up some default data (single) $form->set( 'username', 'johndoe' ); }
  71. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF FORMS - WRITE SIDE 71 $form = $session->getForm( new FormId('profile') ); $token = Token::fromString($input->get('token')); $form->guardTokenIsValid($token); $form->addFeedback( 'user', new Feedback( 'Invalid username', Feedback::ERROR ) );
  72. PUBSUB

  73. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF PUBSUB 73 ๏ 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
  74. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF PUBSUB - A MESSAGE 74 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 'new@example.com'; } }
  75. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF PUBSUB - A SUBSCRIBER 75 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() ); } }
  76. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF PUBSUB - THE SUBSCRIPTION 76 $messageBus = new MessageBus(); $messageBus->subscribe( new Channel('ListenToMe'), new YourSubscriber() );
  77. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT

    AM MAIN HOLGER WOLTERSDORF PUBSUB - PUBLISH 77 $messageBus->publish( new Channel('ListenToMe'), new YourMessage() );
  78. FULL DOCUMENTATION AT icehawk.github.io

  79. QUESTIONS?

  80. 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:
  81. ICEHAWK FRAMEWORK • JULY, 26TH 2017 • PHPUG • MUNICH

    HOLGER WOLTERSDORF LINKS / REFERENCES 81 ๏ 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