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

MVVM and Silex - It's the future

MVVM and Silex - It's the future

There's two things that every cool new start-up wants to provide. A rich application like website, and an API. I'll be talking about how to use Silex and an AngularJS to create one. With lots of demos to go wrong, this talk is aimed at PHP developers that work closely with the frontend, some some knowledge of JavaScript is assumed. We'll touch on the cool things happening in the frontend space like Bower, Grunt, MVVM Frameworks, and how that might change how you write PHP.

3a1c6ce62064c58e2420e9e27c125716?s=128

Billie Thompson

February 20, 2015
Tweet

More Decks by Billie Thompson

Other Decks in Technology

Transcript

  1. Code/Demo Server book-jacket-api book-info-website Book Jacket API Rating API Book

    Info Website Browser ratings-api {server}.herokuapp.com https://github.com/PurpleBooth/{server}
  2. MVVM and Silex Welcome to the world of tomorrow!

  3. Who’re you? Billie Thompson @BillieAThompson billie@purplebooth.co.uk PHP Contractor

  4. What’re we building? • Domain: Book Shop • Sub-domain: Bookshop

    Website • Bounded-Context: Book Information Service
  5. Book Information Service Book Jacket API Rating API Book Info

    Website Browser
  6. Book Information Service DB Queues Logic Responsive Extendible Clean Parallel

    Serve JS Frontend-y Book Jacket API Rating API Book Info Website Browser
  7. Book Information Service Silex PHP AngularJS JavaScript Express JavaScript Book

    Jacket API Rating API Book Info Website Browser
  8. Code/Demo Server book-jacket-api book-info-website Book Jacket API Rating API Book

    Info Website Browser ratings-api {server}.herokuapp.com https://github.com/PurpleBooth/{server}
  9. Cross Functional Teams Team Alpha Team One Team Primary Product?

    Ops Backend Test Frontend
  10. Why Microservices? • Small focused teams • Small services •

    Combining to become awesome
  11. Why JavaScript? • Mature Platform • Mature Frameworks • Mature

    Support Tools
  12. Goals • Working knowledge • JavaScript serverside • Client side

    JavaScript frameworks • Know how to integrate them with PHP • Become more of a Cross Stack developer
  13. Silex Solid & simple

  14. Recap • Micro Framework • Symfony Components • Lots of

    you have (probably?) used it
  15. Getting started with Silex • Composer • PHP on whatever

    • Single PHP File
  16. Book Information Service Book Jacket API Rating API Book Info

    Website Browser
  17. –Silex Demo “Please don’t break”

  18. // book-jacket-api/public/index.php require_once __DIR__.’/../vendor/autoload.php'; $app = new Silex\Application();

  19. // book-jacket-api/public/index.php $app->get('/hello/{name}', function($name) use($app) {
 return 'Hello '.$app->escape($name);
 });


  20. // book-jacket-api/public/index.php use PurpleBooth\Controller\BooksController; use Silex\Provider\ServiceControllerServiceProvider; … $app->register(new ServiceControllerServiceProvider());
 …

    
 $app['books.controller'] = $app->share(function() use ($app) {
 return new BooksController();
 });
 
 $app->get('/', "books.controller:indexAction");
 $app->get('/{isbn}', "books.controller:getAction");
  21. <?php
 // book-jacket-api/src/Controller/BooksController.php
 
 namespace PurpleBooth\Controller;
 
 use Symfony\Component\HttpFoundation\JsonResponse;
 


    class BooksController
 {
 
 …
 public function getAction($isbn)
 {
 if (!array_key_exists($isbn, $this->bookData)) {
 return new JsonResponse(null, 404);
 }
 
 return new JsonResponse($this->bookData[$isbn]);
 }
 }
  22. Silex for the business logic • Rapid API Development •

    Familiar libraries (Doctrine, etc) • Perfect for small services
  23. Alternatives? • Apigility • Building an API with Apigility -

    Rob Allen • ZF2 • Symfony • Build RESTful APIs easily with Symfony - Sarah Khalil
  24. MVVM Model, View and View Model

  25. MVVM Framework View View Model Model Remote API Browser Server

  26. None
  27. Getting Started • Create basic HTML file - include JS

    • Bower.io • Similar to composer • More focus on UI components
  28. –AngularJS Demo “It looked so easy when I saw someone

    else’s talk”
  29. //- book-info-website/views/index.jade doctype html
 html(lang="en" ng-app="booksApp")
 head
 title Book Info

    Website
 link(rel='stylesheet', href='/stylesheets/style.css')
 script(src='/assets/modules/angular/angular.js')
 script(src='/assets/modules/angular-resource/angular-resource.js')
 script(src='/assets/modules/angular-route/angular-route.js')
 script(src='/javascripts/angular/app.js')
 script(src='/javascripts/angular/services.js')
 script(src='/javascripts/angular/controllers.js')
 body
 div(ng-view)
  30. <!DOCTYPE html>
 <html lang="en" ng-app="booksApp">
 
 <head>
 <title>Book Info Website</title>


    <link rel="stylesheet" href="/stylesheets/style.css">
 <script src="/assets/modules/angular/angular.js"></script>
 <script src="/assets/modules/angular-resource/angular-resource.js"></script>
 <script src="/assets/modules/angular-route/angular-route.js"></script>
 <script src="/javascripts/angular/app.js"></script>
 <script src="/javascripts/angular/services.js"></script>
 <script src="/javascripts/angular/controllers.js"></script>
 </head>
 
 <body>
 <div ng-view></div>
 </body>
 
 </html>
  31. //- book-info-website/views/index.jade 
 script(src='/assets/modules/angular/angular.js')
 script(src='/assets/modules/angular-resource/angular-resource.js')
 script(src='/assets/modules/angular-route/angular-route.js')

  32. //- book-info-website/views/index.jade script(src='/javascripts/angular/app.js')
 script(src='/javascripts/angular/services.js')
 script(src='/javascripts/angular/controllers.js')

  33. //- book-info-website/views/index.jade html(lang="en" ng-app=“booksApp”) … // book-info-website/public/javascripts/angular/app.js 
 var booksApp

    = angular.module('booksApp', [
 'ngResource', 
 'ngRoute',
 'booksServices',
 'booksControllers'
 ]); 

  34. // book-info-website/public/javascripts/angular/app.js booksApp.config(['$routeProvider',
 function($routeProvider) {
 $routeProvider.
 when('/', {
 templateUrl: 'partials/list.html',


    controller: 'IndexController'
 }).
 when('/:isbn', {
 templateUrl: 'partials/details.html',
 controller: 'DetailController'
 }).
 otherwise({
 redirectTo: '/'
 });
 }]); … //- book-info-website/views/index.jade body
 div(ng-view)
  35. //- book-info-website/views/partials/list.jade
 div(ng-controller="IndexController")
 h1= title
 h2 Book list!
 ul
 li(ng-repeat="book

    in books")
 a(href="#/{{book.isbn}}") {{book.title}}
  36. // book-info-website/public/javascripts/angular/controllers.js var booksControllers = angular.module('booksControllers', []);
 
 booksControllers.controller( 'IndexController',

    ['$scope', 'Book', function ($scope, Book) {
 $scope.books = Book.query();
 }] ); …
  37. // book-info-website/public/javascripts/angular/services.js var booksService = angular.module('booksServices', []);
 
 booksService.factory('Book', ['$resource',

    '$timeout',
 function ($resource, $timeout) {
 var api = $resource('api/v2/:isbn', {'isbn': '@id'});
 …
 return api;
 }]);

  38. MVVM Framework View View Model Model Remote API Browser Server

  39. // book-info-website/public/javascripts/angular/controllers.js booksControllers.controller(
 'DetailController',
 ['$scope', '$routeParams', 'Book',
 function ($scope, $routeParams,

    Book) {
 Book.pushGet({isbn: $routeParams.isbn}, function (book) {
 $scope.book = book;
 });
 
 $scope.$on('$destroy', function () {
 Book.stopPushGet();
 });
 }
 ]
 );
  40. // book-info-website/public/javascripts/angular/services.js var promise;
 var pushing = false;
 
 api.pushGet

    = function (params, callback) {
 if (!pushing) {
 pushing = true;
 
 var refreshData = function () {
 api.get(params, function (book) {
 callback(book);
 
 promise = $timeout(
 function () {
 refreshData(params, callback);
 }, 4000);
 });
 };
 
 refreshData(params, callback);
 }
 };
  41. // book-info-website/public/javascripts/angular/services.js api.stopPushGet = function () {
 pushing = false;


    
 if (angular.isDefined(promise)) {
 $timeout.cancel(promise);
 promise = undefined;
 }
 };
  42. Alternatives? • React • Bring your PHP application to the

    next level with React.JS - Bastian Hofmann • Backbone • Ember
  43. Future of frontend development • Simpler than it looks •

    Has a lot of similarities with server side frameworks • More and more popular - you will encounter it • Data via APIs from client side
  44. Express Contender for the worlds most boring logo

  45. Book Information Service Book Jacket API Rating API Book Info

    Website Browser
  46. Blocking Book Jacket API Rating API Book Info Website Book

    Info Website
  47. Non-blocking Book Jacket API Rating API Book Info Website Book

    Info Website
  48. Who is going to use it most? • Less context

    switching • JavaScript developers can understand it
  49. Getting Started • Template generator npm install -g express-generator express

    /tmp/foo • Exactly like composer/bower • Except it’s NPM
  50. Friends of Express: Grunt • Achieved Phing’s dream • Loads

    of prewritten tasks • Pre-process CSS/JS/Images • Automatically restart Express on change
  51. // book-info-website/Gruntfile.js module.exports = function (grunt) {
 grunt.initConfig({
 pkg: grunt.file.readJSON('package.json'),


    watch: {
 express: {
 files: ['**/*.js'],
 tasks: ['express:dev'],
 options: {
 spawn: false
 }
 }
 },
 express: {
 dev: {
 options: {
 script: 'bin/www'
 }
 }
 }
 });
 
 grunt.loadNpmTasks('grunt-contrib-watch');
 grunt.loadNpmTasks('grunt-express-server');
 
 grunt.registerTask('server', ['express:dev', 'watch'])
 grunt.registerTask('default', ['server']);
 
 }
  52. // book-info-website/Gruntfile.js 
 grunt.loadNpmTasks('grunt-contrib-watch');
 grunt.loadNpmTasks('grunt-express-server');


  53. // book-info-website/Gruntfile.js 
 grunt.registerTask('server', ['express:dev', 'watch'])
 grunt.registerTask('default', ['server']);
 


  54. –Grunt & Express Demo “How likely is that it will

    break twice?”
  55. // book-info-website/app.js … 
 var routes = require('./routes/index');
 var bookApi1

    = require('./routes/book-api-v1');
 var bookApi2 = require('./routes/book-api-v2'); … app.use("/assets/modules", express.static(__dirname + '/bower_components'));
 
 app.use('/', routes);
 app.use('/api/v1', bookApi1);
 app.use('/api/v2', bookApi2); 

  56. // book-info-website/routes/index.js /* GET home page. */
 router.get('/', function(req, res,

    next) {
 res.render('index');
 }); … //- book-info-website/views/index.jade 
 doctype html
 html(lang="en" ng-app="booksApp")
 head
 title Book Info Website
 link(rel='stylesheet', href='/stylesheets/style.css')
 script(src='/assets/modules/angular/angular.js')
 script(src='/assets/modules/angular-resource/angular-resource.js')
 script(src='/assets/modules/angular-route/angular-route.js')
 script(src='/javascripts/angular/app.js')
 script(src='/javascripts/angular/services.js')
 script(src='/javascripts/angular/controllers.js')
 body
 div(ng-view)
  57. // book-info-website/routes/book-api-v1.js router.get('/', function (req, res, next) {
 booksApiClient.findAll(function (err,

    books) {
 res.json(books);
 });
 });
  58. // book-info-website/api-client/books.js var endpoint = "http://book-jacket-api.herokuapp.com/";
 
 this.getBook = function

    (isbn, callback) {
 makeHttpRequest(endpoint.concat(isbn), callback)
 };

  59. // book-info-website/api-client/client.js var http = require('http');
 
 module.exports = function

    (url, callback) {
 http.get(url, function (res) {
 var str = '';
 
 res.on('data', function (chunk) {
 str += chunk;
 });
 
 res.on('end', function () {
 var apiResponse = JSON.parse(str);
 
 callback(null, apiResponse);
 });
 }).on('error', function (e) {
 callback(e);
 });
 };
  60. Book Information Service Book Jacket API Rating API Book Info

    Website Browser
  61. –Async Demo “What’s the worst that can happen?”

  62. // book-info-website/routes/book-api-v2.js router.get('/:isbn', function (req, res, next) {
 async.parallel({
 'book':

    function (callback) {
 booksApiClient.getBook(req.params.isbn, function (err, bookDetail) {
 callback(err, bookDetail);
 });
 }, 
 'rating': function (callback) {
 ratingsApiClient.getRating(req.params.isbn, function (err, ratings) {
 callback(err, ratings);
 });
 } 
 }, function (err, results) {
 _.extend(results.book, {'rating': results.rating});
 res.json(results.book);
 });
 });

  63. Alternatives? • PHP + Using Guzzle Futures • PHP +

    Queues • Adding 1.21 Gigawatts to Applications with RabbitMQ - James Titcumb • Go/Other language with parallelisation
  64. Express • Non-blocking • Front-end Developer Friendly • Lightweight

  65. In conclusion • Cross functional teams require knowledge of other

    disciplines • MVVM frameworks are going to get more popular • MVVM frameworks require APIs • Use middleware to hide none public services
  66. Any Questions? @BillieAThompson billie@purplebooth.co.uk https://joind.in/talk/view/13383