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

Bring your PHP application to the next level with React.JS

Bring your PHP application to the next level with React.JS

React.JS is a very powerful library for building user interfaces and the new, cool kid in the JavaScript world. But it is also very interesting for creating a fast, maintainable and interactive PHP application. In this talk I'll show what React is all about and how you can combine it’s power with your PHP application, even if you have to render out HTML on the server side. The result will be a flexible, component based architecture that enables developers to take page elements, like a single "follow" button, and place it everywhere on the site without having to duplicate any PHP, JS, HTML, CSS or AJAX endpoints in the process.

Bastian Hofmann

February 19, 2015
Tweet

More Decks by Bastian Hofmann

Other Decks in Programming

Transcript

  1. Bring your PHP
    application to the next
    level with React.JS
    @BastianHofmann

    View Slide

  2. Let's talk about...

    View Slide

  3. Application
    architecture

    View Slide

  4. Code and
    component
    re-use

    View Slide

  5. Rapid
    Development

    View Slide

  6. Handling large
    code-bases

    View Slide

  7. With PHP and
    React.js

    View Slide

  8. webserver
    HTML
    browser
    JS
    controller

    View Slide

  9. webserver
    HTML
    browser
    JS
    Ajax
    controller

    View Slide

  10. webserver
    HTML
    browser
    JS
    Ajax
    controller

    View Slide

  11. de duplication
    ode duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplication
    code duplicatio
    code duplicat
    code duplic
    code dup
    code du
    code
    cod
    co
    co

    View Slide

  12. So?

    View Slide

  13. A few words
    about me

    View Slide

  14. View Slide

  15. View Slide

  16. View Slide

  17. Questions? Ask

    View Slide

  18. http://speakerdeck.com/u/bastianhofmann

    View Slide

  19. Application
    architecture

    View Slide

  20. many roads

    View Slide

  21. View Slide

  22. status quo

    View Slide

  23. webserver
    loadbalancer
    pgsql memcached mongodb
    services

    View Slide

  24. webserver

    View Slide

  25. View Slide

  26. MVC

    View Slide

  27. PHP templates

    View Slide

  28. Duplication and
    only some Code re-
    use

    View Slide

  29. We can do
    better

    View Slide

  30. Small components
    over big controllers

    View Slide

  31. View Slide

  32. View Slide

  33. View Slide

  34. View Slide

  35. View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. Self contained

    View Slide

  40. Can be used
    everywhere

    View Slide

  41. Can be addressed and
    rendered separately

    View Slide

  42. JS is part of the
    component

    View Slide

  43. CSS can be part of
    the component

    View Slide

  44. Share code
    between server
    and client

    View Slide

  45. It needs to be fast

    View Slide

  46. http://facebook.github.io/react/

    View Slide

  47. JavaScript UI Library

    View Slide

  48. Virtual DOM

    View Slide

  49. Many small, self
    contained,
    reusable
    components

    View Slide

  50. var HelloMessage = React.createClass(

    {

    render: function () {

    return Hello {this.props.name};

    }

    }

    );


    React.render(, mountNode);

    View Slide

  51. var Timer = React.createClass({

    getInitialState: function () {

    return {secs: 0};

    },

    tick: function () {

    this.setState({secs: this.state.secs + 1});

    },

    componentDidMount: function () {

    this.interval = setInterval(this.tick, 1000);

    },

    componentWillUnmount: function () {

    clearInterval(this.interval);

    },

    render: function () {

    return (
    Seconds Elapsed: {this.state.secs}
    );

    }

    });


    React.render(, mountNode);

    View Slide

  52. var TodoList = React.createClass(

    {

    render: function () {

    var createItem = function (itemText) {

    return {itemText};

    };

    return (

    {this.props.items.map(createItem)}

    );

    }

    }

    );

    View Slide

  53. var TodoApp = React.createClass({

    getInitialState: function () {

    return {items: […]};

    },

    render: function () {

    return (


    TODO



    );

    }

    });

    View Slide

  54. Getting the data in
    there

    View Slide

  55. PHP
    Backend
    JSON React
    Frontend

    View Slide

  56. PHP
    Backend
    JSON React
    Frontend

    View Slide

  57. PHP
    Backend
    JSON React
    Frontend

    View Slide

  58. PHP
    Backend
    JSON React
    Frontend

    View Slide

  59. Problematic

    View Slide

  60. Remember

    View Slide

  61. Self-contained

    View Slide

  62. Reusable

    View Slide

  63. PHP
    Backend
    JSON React
    Frontend

    View Slide

  64. PHP
    Backend
    JSON React
    Frontend

    View Slide

  65. PHP
    Backend
    JSON React
    Frontend

    View Slide

  66. Overfetching

    View Slide

  67. Underfetching

    View Slide

  68. Solutions

    View Slide

  69. Flux Datastores

    View Slide

  70. PHP
    Backend
    React
    Frontend
    Datastores

    View Slide

  71. GraphQL
    https://gist.github.com/wincent/598fa75e22bdfa44cf47

    View Slide

  72. Requirements

    View Slide

  73. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Institution
    Menu
    React
    Frontend

    View Slide

  74. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    PHP Backend
    Request
    Response
    Institution

    View Slide

  75. LeftColumn Image
    Menu
    React
    Frontend

    View Slide

  76. LeftColumn Image
    Menu
    Request
    Response
    PHP Backend

    View Slide

  77. Remember:
    self contained

    View Slide

  78. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Account
    Account
    Account
    Account
    Account
    Publication1
    Publication2
    Publication3
    Institution

    View Slide

  79. Do not fetch data
    directly

    View Slide

  80. Sssssssllllooooowww

    View Slide

  81. Require stuff

    View Slide

  82. http://www.infoq.com/presentations/Evolution-of-Code-
    Design-at-Facebook/

    View Slide

  83. View Slide

  84. Widget Widget Widget Widget
    Preparer
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations

    View Slide

  85. Widget Widget Widget Widget
    Preparer
    Fetch Requirements
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations

    View Slide

  86. Widget Widget Widget Widget
    Preparer
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations
    Batch
    requirements
    and pass
    them to
    resolvers

    View Slide

  87. Widget Widget Widget Widget
    Preparer
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations
    Call Services as
    effective as possible
    (Multi-GET,...)

    View Slide

  88. Widget Widget Widget Widget
    Preparer
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations
    Attach fetched
    data to
    Requirements and
    pass them back to
    the preparer

    View Slide

  89. Widget Widget Widget Widget
    Preparer
    Resolver Resolver
    Services
    Connector Interfaces
    Connector Implementations
    Distribute fetched
    data to the widgets
    that required it

    View Slide

  90. public function collect() {

    return [

    new EntityRequirement(

    'account',

    Account::class,

    ['id' => $this->request->get('id')]

    ),

    ];

    }

    View Slide

  91. Request Cache

    View Slide

  92. Multi-GET

    View Slide

  93. Futures

    View Slide

  94. Data
    dependencies
    within a widget

    View Slide

  95. => Callbacks

    View Slide

  96. public function collect() {

    return new RequirementCollection([

    new EntityRequirement(

    'account',

    Account::class,

    ['id' => $this->request->get('id')]

    ),

    ], function() {

    return new RequirementCollection([

    new ServiceRequirement(

    'scienceDisciplines',

    AccountService::class,

    'getScienceDisciplines',

    ['account' => $this->account]

    )

    ]);

    });

    }

    View Slide

  97. PHP 5.5 Generators
    http://php.net/manual/de/language.generators.overview.php

    View Slide

  98. public function collect() {

    yield [

    new EntityRequirement(

    'account',

    Account::class,

    ['id' => $this->request->get('id')]

    ),

    ];


    yield [

    new ServiceRequirement(

    'scienceDisciplines',

    AccountService::class,

    'getScienceDisciplines',

    ['account' => $this->account]

    )

    ];

    }

    View Slide

  99. PHP 5.4 Traits
    http://us1.php.net/trait

    View Slide

  100. yield [

    serviceRequirement(
    'job',

    JobService::getCall()->getById(248)

    )

    ];

    View Slide

  101. trait ServiceRequirementFactory {


    /** @return $this */

    public static function getCall() {

    return new ServiceRequirementFactoryProxy(
    static::class
    );

    }

    }

    View Slide

  102. class ServiceRequirementFactoryProxy {


    private $className;


    public function __construct($className) {

    $this->className = $className;

    }


    public function __call($name, $arguments) {

    return [

    'serviceClass' => $this->className,

    'methodName' => $name,

    'arguments' => $arguments

    ];

    }


    }

    View Slide

  103. Data
    dependencies
    between Widgets

    View Slide

  104. Assembling the tree

    View Slide

  105. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    PHP Backend
    Request
    Response
    Institution

    View Slide

  106. Widget
    Requirement

    View Slide

  107. Prefills

    View Slide

  108. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  109. class PublicationKeywordSearch {


    public $publications;

    public $publicationListItems = [];


    public function collect() {

    yield [

    serviceRequirement(

    'publications',

    PublicationService::getCall()->getByKeywords(

    ['virology', 'cancer'], 10, 0

    )

    )

    ];

    foreach ($this->publications as $publication) {

    yield new WidgetRequirement(

    'publicationListItems',

    PublicationItem::CLASS,

    [
    'publicationId' => $publication->getId()
    ]

    );

    }

    }

    }

    View Slide

  110. class PublicationItem {


    public $publicationId;

    public $publication;


    public function collect() {

    yield new RequestDataRequirement('publicationId');

    yield [

    new EntityRequirement(

    'publication',

    Publication::class,

    ['id' => $this->publicationId]

    )

    ];

    }

    }

    View Slide

  111. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  112. Institution
    Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu

    View Slide

  113. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  114. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  115. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  116. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution
    DONE

    View Slide

  117. Getting the data to
    React.js

    View Slide

  118. public function getData() {

    return [

    'key' => 'value',

    'other' => 'data',

    'number' => 42,

    'subComponent' => $this->subComponent,

    'someArray' => [1, 2, 3],

    'subComponentList' => [
    $this->items[0], $this->items[1]
    ]

    ];

    }

    View Slide

  119. {

    "component": "ParentComponent.jsx",

    "id": "ParentComponent-1234",

    "data": {

    "key": "value",

    "other": "data",

    "number": 42,

    "subComponent": {

    "component": "SubComponent.jsx",

    "id": "SubComponent",

    "data": { "boolValue": true }

    },

    "someArray": [1,2,3],

    "subComponentList": [

    {

    "component": "ListItem",

    "id": "ListItem-444",

    "data": { "title": "444s title“ }

    },

    {

    "component": "ListItem",

    "id": "ListItem-555",

    "data": { "title": "555s title“ }

    }

    ]

    }

    }

    View Slide

  120. var React = require('react');

    var SubComponent = require('SubComponent');

    var ListItem = require('ListItem');


    module.exports = React.createClass(

    {

    displayName: 'ParentComponent',

    render: function () {

    var items = [];


    for (var key in this.props.subComponentList) {

    if (this.props.subComponentList.hasOwnProperty(key)) {

    items.push(




    );

    }

    }


    return (


    {this.props.other} Hello PHP {this.props.number}


    {items}


    );

    }

    }

    );

    View Slide

  121. var React = require('react');


    module.exports = React.createClass(

    {

    displayName: 'ListItem',

    render: function () {

    return (


    {this.props.title}


    );

    }

    }

    );

    View Slide

  122. Server side
    rendering

    View Slide

  123. SEO

    View Slide

  124. Better user
    experience

    View Slide

  125. Several
    approaches

    View Slide

  126. http://pecl.php.net/package/v8js
    V8js

    View Slide

  127. Request
    HTML
    Preparer
    libV8
    React
    PHP process
    Data array
    Rendered HTML string

    View Slide

  128. NodeJS proxy

    View Slide

  129. Request
    HTML
    Preparer
    nodeJS Proxy
    React
    PHP process
    Data JSON
    Rendered
    HTML string

    View Slide

  130. NodeJS service

    View Slide

  131. Request
    HTML
    Preparer
    nodeJS service
    React
    PHP process
    Data JSON
    Rendered HTML string

    View Slide

  132. Bundling

    View Slide

  133. http://webpack.github.io/

    View Slide

  134. View Slide

  135. Whoa

    View Slide

  136. This looks awfully
    complicated to
    debug

    View Slide

  137. View Slide

  138. View Slide

  139. View Slide

  140. View Slide

  141. View Slide

  142. Benefits

    View Slide

  143. Enables developers
    to only focus on
    their components

    View Slide

  144. Rapid prototyping

    View Slide

  145. Easier Refactoring

    View Slide

  146. Easy re-using of
    components

    View Slide

  147. Error Handling

    View Slide

  148. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  149. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    EXCEPTION
    Institution

    View Slide

  150. Profile Publications Publication
    Publication
    Publication
    LeftColumn Image
    Menu
    Institution

    View Slide

  151. Experiments (A/B Testing)

    View Slide

  152. Feature toggles

    View Slide

  153. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu
    Institution

    View Slide

  154. Profile Publications Publication
    Publication
    Publication
    AboutMeNew
    LeftColumn Image
    Menu
    Institution

    View Slide

  155. Caching of
    Components

    View Slide

  156. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu

    Institution

    View Slide

  157. Load components
    asynchronously

    View Slide

  158. Profile Publications Publication
    Publication
    Publication
    AboutMe
    LeftColumn Image
    Menu

    loadWidget('/aboutMe', function(w) {<br/>w.render({ replace : '#placeholder' });<br/>})
    Institution

    View Slide

  159. Conclusion?

    View Slide

  160. Think about your
    architecture

    View Slide

  161. Refactor and make
    it better
    continuously

    View Slide

  162. Frontend and
    backend are part
    of the same
    application

    View Slide

  163. Don't rewrite your
    whole codebase in
    one go

    View Slide

  164. https://joind.in/13375

    View Slide

  165. http://twitter.com/BastianHofmann
    http://lanyrd.com/people/BastianHofmann
    http://speakerdeck.com/u/bastianhofmann
    [email protected]

    View Slide