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

JavaScripting for the PHP Developer in 2012

JavaScripting for the PHP Developer in 2012

The modern day web developer is presented with possibilities the developers of 2005 would salivate over. In this session we'll look at some JavaScript tools that will simplify your web development life by reducing the complexity of your PHP backend, increasing the rich user interface presented in the browser, as well as redundancy in your frontend and backend code.

Jeff Carouth

October 24, 2012
Tweet

More Decks by Jeff Carouth

Other Decks in Programming

Transcript

  1. JavaScripting for the
    PHP Developer in 2012
    this is not the JavaScript from 1999
    Jeff Carouth ZendCon 2012

    View Slide

  2. Jeff Carouth
    tweets jcarouth
    blogs http://carouth.com
    checks [email protected]
    works

    View Slide

  3. View Slide

  4. JavaScript Basics

    View Slide

  5. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");

    View Slide

  6. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");
    []; // new Array();
    [1, 2, 3, 4];
    [1, "foo", {}];
    ["foo": "bar", "fizz": "buzz"]; //ERROR

    View Slide

  7. Arrays
    array();
    []; //PHP 5.4+
    array(1, 2, 3, 4);
    array(1, "foo", new stdClass());
    array("foo" => "bar", "fizz" => "buzz");
    []; // new Array();
    [1, 2, 3, 4];
    [1, "foo", {}];
    ["foo": "bar", "fizz": "buzz"]; //ERROR
    {"foo": "bar", "fizz": "buzz"}; //NOT an array

    View Slide

  8. Arrays
    typeof []; // 'object'
    typeof new Array(); // 'object'
    [3]; // arr.length = 1
    new Array(3); // arr.length = 3

    View Slide

  9. Objects
    but NOT
    Classes
    Prototypes

    View Slide

  10. class Car
    {
    private $make;
    private $model;
    private $year;
    public function __construct($make, $model, $year)
    {
    $this->make = $make;
    $this->model = $model;
    $this->year = $year;
    }
    // could use __toString()
    public function toString()
    {
    return $this->year." ".$this->make." ".$this->model;
    }
    }
    $myFirstCar = new Car('Acura', 'Integra', 1990);
    print $myFirstCar->toString();
    // Result: ‘1990 Acura Integra’

    View Slide

  11. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    var myFirstCar = new Car('Acura', 'Integra', 1990);
    var myNewCar = new Car('Dodge', 'Charger', 2009);
    myFirstCar.toString();
    // Result: ‘1990 Acura Integra’
    myNewCar.toString();
    // Result: ‘2009 Dodge Charger’

    View Slide

  12. Checking Type
    gettype($myFirstCar); // object
    $myFirstCar instanceof Car; // true
    get_class($myFirstCar); // Car
    typeof myFirstCar; // 'object'
    myFirstCar instanceof Car; // true
    myFirstCar.constuctor; // Car
    php
    JavaScript

    View Slide

  13. Prototypal Inheritance
    Warning: Here be dragons…at first.

    View Slide

  14. Object Methods Via the Prototype
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }

    View Slide

  15. Object Methods Via the Prototype
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Car.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }

    View Slide

  16. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    }
    var aCar = new Car('Saturn', 'Vue', 2007);
    var anotherCar = new Car('Ford', 'F150', '2003');
    aCar.toString(); // '2007 Saturn Vue'
    anotherCar.toString(); // '2003 Ford F150'
    aCar.toString = function() {
    return '2013 BMW 335is Convertible';
    };
    aCar.toString(); // '2013 BMW 335is Convertible'
    anotherCar.toString(); // '2003 Ford F150'

    View Slide

  17. function Car(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Car.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    var aCar = new Car('Saturn', 'Vue', 2007);
    var anotherCar = new Car('Ford', 'F150', '2003');
    aCar.toString(); // '2007 Saturn Vue'
    anotherCar.toString(); // '2003 Ford F150'
    Car.prototype.toString = function() {
    return '2013 BMW 335is Convertible';
    };
    aCar.toString(); // '2013 BMW 335is Convertible'
    anotherCar.toString(); // '2013 BMW 335is Convertible'

    View Slide

  18. class Dad extends Person
    {
    public function __construct($firstName)
    {
    $this->familyName = 'Carouth';
    parent::__construct($firstName);
    }
    }
    class Son extends Dad
    {
    }
    $son = new Son('Jeff');
    print $son->familyName; // 'Carouth'

    View Slide

  19. var Dad = function() {
    this.familyName = 'Carouth';
    };
    var Son = function(firstName) {
    this.firstName = firstName;
    };
    Son.prototype = new Dad();
    Son.prototype.constructor = Son;
    var jeff = new Son('Jeff');
    jeff.familyName; // 'Carouth'
    jeff instanceof Son; // true
    jeff instanceof Dad; // true

    View Slide

  20. Namespaces
    Easy in PHP 5.3+
    Easy enough in JavaScript

    View Slide

  21. namespace Foo;
    class Car
    {
    public function __construct($make, $model, $year)
    {
    // ...snip...
    }
    // ...snip...
    }
    //someotherfile.php
    $myCar = new Foo\Car('Toyota', 'Prius', '2011');

    View Slide

  22. var Foo = Foo || {};
    Foo.Car = function(make, model, year) {
    // ...snip..
    };
    var myCar = new Foo.Car('Toyota', 'Prius', '2011');

    View Slide

  23. The Module Pattern

    View Slide

  24. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());

    View Slide

  25. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());
    (function() {
    }());

    View Slide

  26. var Car = (function() {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }());
    var Car =
    var Constructor;
    return Constructor;

    View Slide

  27. var Car = (function($) {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    }
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " + this.model;
    }
    return Constructor;
    }(jQuery));
    Dependencies

    View Slide

  28. Extension
    myCar.beep(); //undefined
    Car = (function(Car) {
    Car.prototype.beep = function() {
    return 'Beep';
    };
    return Car;
    }(Car));
    myCar.beep(); // 'Beep'

    View Slide

  29. Information Hiding
    A.K.A. private properties

    View Slide

  30. var Car = (function() {
    var started = false;
    var Constructor;
    Constructor = function(make, model, year) { /* snip */ };
    Constructor.prototype = {
    constructor: Constructor,
    toString: function() { /* snip */ },
    start: function() {
    if (!started) {
    started = true;
    }
    },
    isRunning: function() {
    return started === true;
    }
    };
    return Constructor;
    })();

    View Slide

  31. var myCar = new Car('BMW', '335is Convertible', 2013);
    myCar.isRunning(); // false
    myCar.started; // undefined
    myCar.start();
    myCar.isRunning(); // true

    View Slide

  32. require.js
    file
    and
    module
    loader

    View Slide




  33. Example Application
    src="scripts/require-jquery.js">


    My Example Application



    View Slide

  34. require(["jquery", "Car"], function($, Car) {
    var myCar = new Car('BMW', '335is Convertible', 2013);
    $("#output").html(myCar.toString());
    });
    scripts/main.js

    View Slide

  35. scripts/Car.js
    define(function () {
    var Constructor;
    Constructor = function(make, model, year) {
    this.make = make;
    this.model = model;
    this.year = year;
    };
    Constructor.prototype.toString = function() {
    return this.year + " " + this.make + " " +
    this.model;
    }
    return Constructor;
    });

    View Slide

  36. View Slide

  37. “MV*” Frameworks
    Backbone.js, KnockoutJS, AngularJS

    View Slide

  38. structure with models, collections, and views
    simple binding and handling of events
    connection to RESTful JSON API

    View Slide

  39. View Presenter
    Model
    Backbone.Model Backbone.Collection
    Templates Underscore.js Backbone.View Backbone.Router
    Backbone.Events
    Backbone.Sync

    View Slide

  40. Backbone.Router
    Binds URLs and hashes to routes.

    View Slide

  41. Backbone.Router
    MyRouter = Backbone.Router.extend({
    routes: {
    "": "index",
    "cars": "cars",
    "cars/:id": "car"
    },
    index: function() { /* show homepage */ },
    cars: function() { /* list of cars */ },
    car: function(id) { /* show car */ }
    });

    View Slide

  42. Backbone.View
    View takes data and transform it into HTML via
    templates and a reference to a DOM element.
    The view also listens to events and triggers action based
    those events.

    View Slide

  43. Backbone.View
    var CarView = Backbone.View.extend({
    tagName: "li",
    className: "car",
    events: {
    'click .start': 'start'
    },
    render: function() {
    this.$el.html(
    this.name() + ' [start]'
    );
    return this;
    },
    start: function() {
    alert('car started');
    },
    name: function() {
    return this.model.toString();
    }
    });

    View Slide

  44. Backbone.Model
    The model syncs with a server. If the backend is
    RESTful the “out of the box” sync will just work.
    A model holds information about a single record
    from the backend.
    Model update triggers and event which will update
    the view for that specific model.

    View Slide

  45. Backbone.Model
    var Car = Backbone.Model.extend({
    urlRoot: '/cars',
    toString: function() {
    return this.get('year') + " " +
    this.get('make') + " " +
    this.get('model');
    }
    });
    var CarView = Backbone.View.extend({
    initialize: function() {
    this.model.on('change', this.render, this);
    }
    /* ...snip... */
    });

    View Slide

  46. Backbone.Collection
    An “array” of models.
    Can also sync to the server if given a url root.

    View Slide

  47. Backbone.Collection
    var Cars = Backbone.Collection.extend({
    url: '/cars',
    model: Car
    });
    var CarsView = Backbone.View.extend({
    initialize: function() {
    this.collection = new Cars();
    this.collection.fetch({
    success: _.bind(function(resp, status, xhr) {
    this.render();
    }, this)
    });
    },
    render: function() {
    this.collection.each(this.renderCar, this);
    },
    renderCar: function(model) {
    var carView = new CarView({model: model});
    this.$el.append(carView.el);
    }
    });

    View Slide

  48. Templates in Backbone
    There is no default. You can use Underscore.js
    templates since it is a dependency.
    You are able to use whatever JavaScript templating
    such as Handlebars.

    View Slide

  49. QUnit
    You do test your code, don’t you?

    View Slide




  50. Example Test Runner


    data-main="tests.js">





    View Slide

  51. (function() {
    QUnit.config.autostart = false;
    require.config({
    baseUrl: "../src"
    });
    var testModules = [
    "model/CarTests.js"
    ];
    require(testModules, QUnit.start);
    }());

    View Slide

  52. define(function(require) {
    var Car = require("./Car");
    QUnit.module("model/Car", {
    setup: function() {},
    teardown: function() {}
    });
    QUnit.test("Car should not be running when first created",
    function() {
    var mycar = new Car('BMW', '335is', 2013);
    ok(!mycar.isRunning());
    }
    );
    QUnit.test("Car should be running after it is started",
    function() {
    var mycar = new Car("BMW", "335is", 2013);
    mycar.start();
    ok(mycar.isRunning());
    }
    );
    });

    View Slide

  53. View Slide

  54. Grunt
    Task-based build tool for JavaScript projects.

    View Slide

  55. module.exports = function(grunt) {
    grunt.initConfig({
    lint: {
    src: ['src/model/**/*.js'],
    tests: ['tests/model/**/*.js']
    },
    qunit: {
    files: ['tests/tests.html']
    },
    uglify: {}
    });
    grunt.registerTask('default', 'lint qunit');
    };

    View Slide

  56. $ grunt
    Running "lint:src" (lint) task
    Lint free.
    Running "lint:tests" (lint) task
    Lint free.
    Running "qunit:files" (qunit) task
    Testing tests.htmlOK
    >> 2 assertions passed (15ms)
    Done, without errors.

    View Slide

  57. Thank You!
    https://joind.in/7022
    @jcarouth | [email protected]
    http://speakerdeck.com/jcarouth

    View Slide