Upgrade to Pro — share decks privately, control downloads, hide ads and more …

IceHawk Framework | @PHPUGFFM

IceHawk Framework | @PHPUGFFM

Introduction to the Open Source IceHawk framework at PHP USERGROUP Frankfurt am Main, January 19th 2017

Holger Woltersdorf

January 19, 2017
Tweet

More Decks by Holger Woltersdorf

Other Decks in Programming

Transcript

  1. January, 19th 2017 • PHPUGFFM • Frankfurt am Main Holger Woltersdorf

    View Slide

  2. CO-FOUNDER OF
    HOLGER WOLTERSDORF
    CIO • FATHER • HUSBAND • PHP DEV WITH ♥
    github.com/hollodotme
    github.com/icehawk
    @hollodotme
    @F9T3ch

    View Slide

  3. View Slide

  4. View Slide

  5. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    CONTENTS
    5
    HISTORY
    FACTS
    FEATURES
    &
    CODE
    COMPONENTS
    DISCUSSION

    View Slide

  6. HISTORY

    View Slide

  7. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    7
    (A not completely unknown PHP consulting company)

    View Slide

  8. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    8
    ๏ THE MVC PATTERN
    VIEW 1 VIEW 2
    CONTROLLER MODEL
    USER INPUT
    MODIFIES
    UPDATES

    View Slide

  9. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    9
    ๏ THE MVC PATTERN …THE PROBLEM!
    VIEW 1 VIEW 2
    CONTROLLER MODEL
    USER INPUT
    MODIFIES
    UPDATES
    !

    View Slide

  10. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    10
    ๏ THE MVC PATTERN …THE PROBLEM!
    VIEW 1 VIEW 2
    CONTROLLER MODEL
    USER INPUT
    MODIFIES
    HTTP

    View Slide

  11. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    11
    ๏ THE MVC PATTERN …THE SOLUTION?
    VIEW 1 VIEW 2
    CONTROLLER MODEL
    USER INPUT
    MODIFIES
    HTTP
    RESPONDS

    View Slide

  12. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    12
    "THE MVC PATTERN
    SOLVES A PROBLEM
    THAT DOESN’T EXIST
    IN THE WEB."

    View Slide

  13. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    13
    "THE MVC PATTERN
    SOLVES A PROBLEM
    THAT DOESN’T EXIST
    IN THE WEB."

    View Slide

  14. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN 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

    View Slide

  15. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    15
    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

    View Slide

  16. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    16
    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

    View Slide

  17. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN 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

    View Slide

  18. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    18
    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
    RESPONIBILITY SEGREGATION
    (CQRS)
    TA-DA!

    View Slide

  19. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    19
    COMMAND QUERY RESPONIBILITY SEGREGATION
    (CQRS)
    TA-DA!

    View Slide

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

    View Slide

  21. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    PROJECTOR
    CHANGE
    PAGE 2
    HISTORY
    21
    ๏ 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

    View Slide

  22. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    HISTORY
    22
    […] 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

    View Slide

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

    View Slide

  24. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    24
    «Wir brauchen einen Namen!»
    «Ja, irgendwas cooles schnelles!»
    HISTORY

    View Slide

  25. ICEHAWK

    View Slide

  26. FACTS

    View Slide

  27. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FACTS
    27
    ๏ COMPONENTS
    STABLE v2.1.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%

    View Slide

  28. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FACTS
    28
    ๏ MAIN COMPONENT: icehawk/icehawk
    1.533 Logical lines of code (LLOC)
    0 composer dependencies
    0 third-party php extension dependencies
    v2.1.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

    View Slide

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

    View Slide

  30. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FACTS
    30
    NAMING CONVENTION
    interface BypassesRequest {}
    class RequestBypass {}
    trait DefaultRequestBypassing {}

    View Slide

  31. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FACTS
    31
    POST
    PUT
    PATCH
    DELETE
    GET
    HEAD
    OPTIONS
    WRITE
    REQUEST
    HANDLER
    READ
    REQUEST
    HANDLER
    AUTO-RESPONSE
    BASIC ROUTING BEHAVIOUR

    View Slide

  32. FEATURES & CODE

    View Slide

  33. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    33
    INSTALLATION

    View Slide

  34. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    34

    View Slide

  35. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    35
    class IceHawk
    {
    public function __construct( $config, $delegate )
    public function init() {}
    public function handleRequest() {}
    }

    View Slide

  36. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    36
    /**
    * @author root
    */
    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();

    View Slide

  37. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    37
    DELEGATION

    View Slide

  38. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN 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.
    }
    }

    View Slide

  39. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - DELEGATION
    39
    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.
    }
    }

    View Slide

  40. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - DELEGATION
    40
    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.
    }
    }

    View Slide

  41. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    41
    CONFIGURATION

    View Slide

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

    View Slide

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

    View Slide

  44. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - CONFIGURATION
    44
    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()
    ),
    ];
    }
    }

    View Slide

  45. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN 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/(?[0-9]+)/?$", 'i'),
    new ShowBlogPostRequestHandler()
    );

    View Slide

  46. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - CONFIGURATION
    46
    # 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()
    );

    View Slide

  47. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - CONFIGURATION
    47
    # 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()
    );

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  53. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    53
    REQUEST HANDLERS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  60. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE
    60
    FINAL RESPONDING

    View Slide

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

    View Slide

  62. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - FINAL RESPONDING
    62
    final class MyHawkConfig extends IceHawkConfig
    {
    public function getFinalReadResponder()
    : RespondsFinallyToReadRequest
    {
    return MyFinalReadResponder();
    }
    }

    View Slide

  63. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FEATURES & CODE - FINAL RESPONDING
    63
    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();
    }
    }
    }

    View Slide

  64. COMPONENTS

    View Slide

  65. SESSION

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  69. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    SESSION - REGISTER DATA MAPPERS
    69
    # 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
    ]
    );

    View Slide

  70. FORMS

    View Slide

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

    View Slide

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

    View Slide

  73. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    FORMS - WRITE SIDE
    73
    $form = $session->getForm( new FormId('profile') );
    $token = Token::fromString($input->get('token'));
    $form->guardTokenIsValid($token);
    $form->addFeedback(
    'user',
    new Feedback(
    'Invalid username',
    Feedback::ERROR
    )
    );

    View Slide

  74. PUBSUB

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  79. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    PUBSUB - PUBLISH
    79
    $messageBus->publish(
    new Channel('ListenToMe'),
    new YourMessage()
    );

    View Slide

  80. icehawk.github.io

    View Slide

  81. DISCUSSION

    View Slide

  82. 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:

    View Slide

  83. ICEHAWK FRAMEWORK • JANUARY, 19TH 2017 • PHPUGFFM • FRANKFURT AM MAIN HOLGER WOLTERSDORF
    LINKS / REFERENCES
    83
    ๏ 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

    View Slide