Slide 1

Slide 1 text

Micro Framework and JavaScript Applications brought to you via the MicroPHP Manifesto Jeff Carouth

Slide 2

Slide 2 text

http://mojolive.com/profile/jcarouth

Slide 3

Slide 3 text

http://mojolive.com/profile/jcarouth @jcarouth

Slide 4

Slide 4 text

http://mojolive.com/profile/jcarouth

Slide 5

Slide 5 text

http://mojolive.com/profile/jcarouth Occasional Blogger

Slide 6

Slide 6 text

http://mojolive.com/profile/jcarouth

Slide 7

Slide 7 text

1 __DIR__ . "/../templates", 6 )); 7 8 $app->get('/', function() use($app) { 9 $app->render('index'); 10 }); 11 12 $app->run(); Micro Enough? I thought so. I’ll take your questions now. Thank you for coming.

Slide 8

Slide 8 text

Agenda The MicroPHP Manifesto

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Learning a comprehensive framework is hard.

Slide 11

Slide 11 text

PHP is complicated enough

Slide 12

Slide 12 text

Have you tried Xdebug yet? Hello…Dev Support…

Slide 13

Slide 13 text

To grok where a Micro Framework fits in today’s PHP ecosystem, it is imperative to examine PHP’s roots.

Slide 14

Slide 14 text

hypertext preprocessing language which is easily extensible modules and extensions leading to community contributed 1998

Slide 15

Slide 15 text

Exposing MicroPHP microphp.org……good start packagist.org……better choice

Slide 16

Slide 16 text

Exposing MicroPHP IMHO microphp.org……good start packagist.org……better choice

Slide 17

Slide 17 text

http://getcomposer.org “Composer is a tool for dependency management in PHP. It allows you to declare the dependent libraries your project needs and it will install them in your project for you.” – The FM

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

Slim: micro framework

Slide 21

Slide 21 text

simple yet powerful CREDIT: http://www.flickr.com/photos/malabooboo/4930536883/

Slide 22

Slide 22 text

REST CREDIT: http://www.flickr.com/photos/tmartin/111423043/

Slide 23

Slide 23 text

11 //GET route - retrieve data at resource 12 $app->get('/resource/:id', function ($id) { 13 echo 'This is a GET route'; 14 }); 15 16 //POST route - create new resource 17 $app->post('/resource', function () { 18 echo 'This is a POST route'; 19 }); 20 21 //PUT route - update resource 22 $app->put('/resource/:id', function ($id) { 23 echo 'This is a PUT route'; 24 }); 25 26 //DELETE route - delete resource 27 $app->delete('/resource/:id', function ($id) { 28 echo 'This is a DELETE route'; 29 }); RESTful Verbs

Slide 24

Slide 24 text

Tasty API Implementation CREDIT: http://www.flickr.com/photos/agustinrafaelreyes/6895890406/

Slide 25

Slide 25 text

PomTrac Eventually will be a pomodoro tracker. But we’ll start by just implementing tasks and the activity inventory.

Slide 26

Slide 26 text

Resource: tasks http://pomtrac.localhost/tasks

Slide 27

Slide 27 text

Implemention Guide ‣ GET /tasks ‣ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 28

Slide 28 text

Implemention Guide ‣ GET /tasks ‣ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 29

Slide 29 text

39 $app->get('/tasks', function() use ($app) { 40 $collection = $app->dataStore->tasks; 41 $tasks = iterator_to_array($collection->find()); 42 $app->render( 43 'tasks', 44 array( 45 'tasks' => $tasks, 46 ) 47 ); 48 });

Slide 30

Slide 30 text

39 $app->get('/tasks', function() use ($app) { 40 $collection = $app->dataStore->tasks; 41 $tasks = iterator_to_array($collection->find()); 42 $app->render( 43 'tasks', 44 array( 45 'tasks' => $tasks, 46 ) 47 ); 48 });

Slide 31

Slide 31 text

39 $app->get('/tasks', function() use ($app) { 40 $collection = $app->dataStore->tasks; 41 $tasks = iterator_to_array($collection->find()); 42 $app->render( 43 'tasks', 44 array( 45 'tasks' => $tasks, 46 ) 47 ); 48 });

Slide 32

Slide 32 text

GET http://pomtrac.localhost/tasks Accept-Language: en-us Accept: application/json Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate

Slide 33

Slide 33 text

GET http://pomtrac.localhost/tasks Accept-Language: en-us Accept: application/json Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip, deflate HTTP 200 No Error Server: Apache/2.2.21 (Unix) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Type: application/json Date: Tue, 26 Jun 2012 01:41:56 GMT Keep-Alive: timeout=5, max=100 Content-Length: 747 Connection: Keep-Alive

Slide 34

Slide 34 text

[ { "summary" : "Document all the codes.", "createdDate" : "2012-06-24T15:38:54-05:00", "id" : "4fe77ade8ead0ebfd2000000", "estimate" : null, "completed" : false }, { "summary" : "Do something.", "createdDate" : "2012-06-24T17:12:42-05:00", "id" : "4fe790da8ead0ebcd2000000", "estimate" : null, "completed" : false }, { "summary" : "Conference call @ 10AM w/ Josh", "createdDate" : "2012-06-24T17:55:59-05:00", "id" : "4fe79aff8ead0e400a00000a", "estimate" : null, "completed" : false } ]

Slide 35

Slide 35 text

Implemention Guide ✓ GET /tasks ‣ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 36

Slide 36 text

Implemention Guide ✓ GET /tasks ‣ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 37

Slide 37 text

68 $app->post('/tasks', function() use ($app) { 69 $request = $app->request(); 70 $response = $app->response(); 71 72 $data = $request->getBody(); 80 81 if(true === $app->dataStore->tasks->insert($data)) { 82 $response->status(201); 83 84 $resourceLocation = Utils\buildUrl( 85 $request, 86 "tasks/".(string)$data["_id"] 87 ); 88 89 $response['Location'] = $resourceLocation; 90 } else { 91 $response->status(500); 92 } 93 });

Slide 38

Slide 38 text

68 $app->post('/tasks', function() use ($app) { 69 $request = $app->request(); 70 $response = $app->response(); 71 72 $data = $request->getBody(); 80 81 if(true === $app->dataStore->tasks->insert($data)) { 82 $response->status(201); 83 84 $resourceLocation = Utils\buildUrl( 85 $request, 86 "tasks/".(string)$data["_id"] 87 ); 88 89 $response['Location'] = $resourceLocation; 90 } else { 91 $response->status(500); 92 } 93 });

Slide 39

Slide 39 text

POST http://pomtrac.localhost/tasks Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate { “summary”: “Write tests or GrumpyProgrammer will cut me.” }

Slide 40

Slide 40 text

POST http://pomtrac.localhost/tasks Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate { “summary”: “Write tests or GrumpyProgrammer will cut me.” } HTTP 201 Created Location: http://pomtrac.localhost/tasks/4fe91a7defca290156000000 X-Powered-By: PHP/5.3.8 Server: Apache/2.2.21 (Unix) PHP/5.3.8 Content-Type: application/json Date: Tue, 26 Jun 2012 02:12:13 GMT Keep-Alive: timeout=5, max=100 Content-Length: 0 Connection: Keep-Alive

Slide 41

Slide 41 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 42

Slide 42 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ‣ PUT /tasks/ ‣ GET /tasks/ ‣ DELETE /tasks/

Slide 43

Slide 43 text

50 $app->get('/tasks/:id', function($id) use ($app) { 51 $collection = $app->dataStore->tasks; 52 $task = $collection->findOne( 53 array('_id' => new MongoId($id)) 54 ); 55 56 if (null === $task) { 57 $app->response()->status(404); 58 } else { 59 $app->render( 60 'task', 61 array( 62 'task' => $task, 63 ) 64 ); 65 } 66 });

Slide 44

Slide 44 text

50 $app->get('/tasks/:id', function($id) use ($app) { 51 $collection = $app->dataStore->tasks; 52 $task = $collection->findOne( 53 array('_id' => new MongoId($id)) 54 ); 55 56 if (null === $task) { 57 $app->response()->status(404); 58 } else { 59 $app->render( 60 'task', 61 array( 62 'task' => $task, 63 ) 64 ); 65 } 66 });

Slide 45

Slide 45 text

50 $app->get('/tasks/:id', function($id) use ($app) { 51 $collection = $app->dataStore->tasks; 52 $task = $collection->findOne( 53 array('_id' => new MongoId($id)) 54 ); 55 56 if (null === $task) { 57 $app->response()->status(404); 58 } else { 59 $app->render( 60 'task', 61 array( 62 'task' => $task, 63 ) 64 ); 65 } 66 });

Slide 46

Slide 46 text

50 $app->get('/tasks/:id', function($id) use ($app) { 51 $collection = $app->dataStore->tasks; 52 $task = $collection->findOne( 53 array('_id' => new MongoId($id)) 54 ); 55 56 if (null === $task) { 57 $app->response()->status(404); 58 } else { 59 $app->render( 60 'task', 61 array( 62 'task' => $task, 63 ) 64 ); 65 } 66 });

Slide 47

Slide 47 text

GET http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

HTTP 200 No Error Server: Apache/2.2.21 (Unix) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Type: application/json Date: Tue, 26 Jun 2012 02:25:17 GMT Keep-Alive: timeout=5, max=100 Content-Length: 181 Connection: Keep-Alive { "id" : "4fe91a7defca290156000000", "summary" : "Write tests or GrumpyProgrammer will cut you.", "createdDate" : "2012-06-25T21:10:09-05:00", "estimate" : null, "completed" : false }

Slide 50

Slide 50 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ‣ PUT /tasks/ ✓ GET /tasks/ ‣ DELETE /tasks/

Slide 51

Slide 51 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ‣ PUT /tasks/ ✓ GET /tasks/ ‣ DELETE /tasks/

Slide 52

Slide 52 text

95 $app->put('/tasks/:id', function($id) use ($app) { 96 $data = $app->request()->getBody(); 106 $updateResult = $app->dataStore->tasks->update( 107 array("_id" => new MongoId($id)), 108 array( 109 '$set' => array( 110 'summary' => $data['summary'], 111 'estimate' => $data['estimate'], 112 'completed' => $data['completed'], 113 ) 114 ) 115 ); 116 117 if (true === $updateResult) { 118 $app->response()->status(200); 119 } else { 120 $app->response()->status(500); 121 $this->render( 122 'failure', 123 array('failure' => 'Could not update the task.') 124 ); 125 } 126 });

Slide 53

Slide 53 text

95 $app->put('/tasks/:id', function($id) use ($app) { 96 $data = $app->request()->getBody(); 106 $updateResult = $app->dataStore->tasks->update( 107 array("_id" => new MongoId($id)), 108 array( 109 '$set' => array( 110 'summary' => $data['summary'], 111 'estimate' => $data['estimate'], 112 'completed' => $data['completed'], 113 ) 114 ) 115 ); 116 117 if (true === $updateResult) { 118 $app->response()->status(200); 119 } else { 120 $app->response()->status(500); 121 $this->render( 122 'failure', 123 array('failure' => 'Could not update the task.') 124 ); 125 } 126 });

Slide 54

Slide 54 text

95 $app->put('/tasks/:id', function($id) use ($app) { 96 $data = $app->request()->getBody(); 106 $updateResult = $app->dataStore->tasks->update( 107 array("_id" => new MongoId($id)), 108 array( 109 '$set' => array( 110 'summary' => $data['summary'], 111 'estimate' => $data['estimate'], 112 'completed' => $data['completed'], 113 ) 114 ) 115 ); 116 117 if (true === $updateResult) { 118 $app->response()->status(200); 119 } else { 120 $app->response()->status(500); 121 $this->render( 122 'failure', 123 array('failure' => 'Could not update the task.') 124 ); 125 } 126 });

Slide 55

Slide 55 text

PUT http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate { “estimate”: “300” }

Slide 56

Slide 56 text

PUT http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate { “estimate”: “300” } HTTP 200 No Error Server: Apache/2.2.21 (Unix) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Type: application/json Date: Tue, 26 Jun 2012 02:34:30 GMT Keep-Alive: timeout=5, max=100 Content-Length: 0 Connection: Keep-Alive

Slide 57

Slide 57 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ✓ PUT /tasks/ ✓ GET /tasks/ ‣ DELETE /tasks/

Slide 58

Slide 58 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ✓ PUT /tasks/ ✓ GET /tasks/ ‣ DELETE /tasks/

Slide 59

Slide 59 text

128 $app->delete('/tasks/:id', function($id) use ($app) { 129 $deleteResult = $app->dataStore->tasks->remove( 130 array("_id" => new MongoId($id)) 131 ); 132 133 if (true === $deleteResult) { 134 $app->response()->status(204); 135 } else { 136 $app->response()->status(500); 137 } 138 });

Slide 60

Slide 60 text

128 $app->delete('/tasks/:id', function($id) use ($app) { 129 $deleteResult = $app->dataStore->tasks->remove( 130 array("_id" => new MongoId($id)) 131 ); 132 133 if (true === $deleteResult) { 134 $app->response()->status(204); 135 } else { 136 $app->response()->status(500); 137 } 138 });

Slide 61

Slide 61 text

DELETE http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate

Slide 62

Slide 62 text

HTTP 204 No Content Server: Apache/2.2.21 (Unix) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Type: text/html Date: Tue, 26 Jun 2012 02:41:35 GMT Keep-Alive: timeout=5, max=100 Content-Length: 0 Connection: Keep-Alive DELETE http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate

Slide 63

Slide 63 text

GET http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate

Slide 64

Slide 64 text

GET http://pomtrac.localhost/tasks/4fe91a7defca290156000000 Accept-Language: en-us Accept: application/json Content-Type: application/json Accept-Encoding: gzip, deflate HTTP 404 Not Found Server: Apache/2.2.21 (Unix) PHP/5.3.8 X-Powered-By: PHP/5.3.8 Content-Type: application/json Date: Tue, 26 Jun 2012 02:42:59 GMT Keep-Alive: timeout=5, max=100 Content-Length: 0 Connection: Keep-Alive

Slide 65

Slide 65 text

Implemention Guide ✓ GET /tasks ✓ POST /tasks ✓ PUT /tasks/ ✓ GET /tasks/ ✓ DELETE /tasks/

Slide 66

Slide 66 text

Final Stats ‣ Full index.php is 142 LOC ‣ Tasks API is 102 LOC ‣ App consists of 6 files (excluding vendor/)

Slide 67

Slide 67 text

LoneStarPHP+JavaScript DISCLAIMER: name change not cleared with organizers

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

*scoff* JavaScript doesn’t need STRUCTURE Well, not mine anyway.

Slide 70

Slide 70 text

529 var i = 0; 530 var departmentListLength = VisitReg.RegisterUI.AcademicAppointments.departmentList.length; 531 var deptList = VisitReg.RegisterUI.AcademicAppointments.departmentList; 532 533 for (i = 0; i < departmentListLength; i++) { 534 option = $("", {value: deptList[i].departmentId}); 535 option.html(deptList[i].departmentName); 536 537 appointmentSelector.append(option); 538 } 539 540 appointmentSelector.bind("change", function() { 541 var visitDate = VisitReg.RegisterUI.AcademicAppointments.date; 542 var appointmentDataWrapper = $(this).next(); 543 appointmentDataWrapper.empty(); 544 545 var selectedDeptId = $(this).val(); 546 547 if (selectedDeptId === '') { 548 return; 549 } 550 551 //find department in department list data 552 var departmentList = VisitReg.RegisterUI.AcademicAppointments.departmentList; 553 var selectedDepartmentData; 554 for (var i = 0; i < departmentList.length; i++) { 555 if (parseInt(departmentList[i].departmentId, 10) === parseInt(selectedDeptId, 10)) { 556 selectedDepartmentData = departmentList[i]; 557 break; 558 } 559 } 560 561 //TODO: handle error of missing departmentData 562 563 if (selectedDepartmentData.participating === "1") { 564 $.getJSON( 565 VisitReg.settings.baseUrl + "/api/availableacademicappts/date/" + visitDate.replace(/\//g, "-") + "/department/" + selectedDeptId, 566 function(data) { 567 var i = 0; 568 var availApptsLength = data.length; 569 570 if (availApptsLength === 0) { 571 //display department has no available appointments 572 var message = $('

', { 'class': "message" }); 573 message.html( 'We\'re sorry, but this department does not have any scheduled appointments on the date you wish to visit.'); 574 575 appointmentDataWrapper.append(message); 576 577 return; 578 } 579 580 var appointmentButtons = $('
    ',

    Slide 71

    Slide 71 text

    Lightweight JavaScript “MVC”

    Slide 72

    Slide 72 text

    Model View Controller

    Slide 73

    Slide 73 text

    View Controller Model Backbone.Model Backbone.Collection Templates Underscore.js Backbone.View Backbone.Router

    Slide 74

    Slide 74 text

    View Controller Model Backbone.Model Backbone.Collection Templates Underscore.js Backbone.View Backbone.Router Backbone.Events

    Slide 75

    Slide 75 text

    View Controller Model Backbone.Model Backbone.Collection Templates Underscore.js Backbone.View Backbone.Router Backbone.Events Backbone.Sync

    Slide 76

    Slide 76 text

    Implemention Guide ‣ Retrieve data from API ‣ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 77

    Slide 77 text

    Implemention Guide ‣ Retrieve data from API ‣ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 78

    Slide 78 text

    Backbone.Model 1 App.Task = Backbone.Model.extend({});

    Slide 79

    Slide 79 text

    Backbone.Model 1 App.Task = Backbone.Model.extend({ 2 urlRoot: "tasks" 3 });

    Slide 80

    Slide 80 text

    Backbone.Model 1 App.Task = Backbone.Model.extend({ 2 urlRoot: "tasks", 3 defaults: function() { 4 return { 5 summary: "", 6 createdDate: moment(), 7 completed: false, 8 estimate: null 9 }; 10 } 11 });

    Slide 81

    Slide 81 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({});

    Slide 82

    Slide 82 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({ 2 model: App.Task 3 });

    Slide 83

    Slide 83 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({ 2 model: App.Task, 3 4 url: "/tasks" 5 });

    Slide 84

    Slide 84 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({ 2 model: App.Task, 3 4 url: "/tasks", 5 6 comparator: function(task) { 7 return moment(task.get("createdDate")); 8 } 9 });

    Slide 85

    Slide 85 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({ 2 model: App.Task, 3 4 url: "/tasks", 5 6 comparator: function(task) { 7 return moment(task.get("createdDate")); 8 } 9 }); 1 var tasks = new App.Tasks(); 2 tasks.fetch();

    Slide 86

    Slide 86 text

    Backbone.Collection 1 App.Tasks = Backbone.Collection.extend({ 2 model: App.Task, 3 4 url: "/tasks", 5 6 comparator: function(task) { 7 return moment(task.get("createdDate")); 8 } 9 }); 1 var tasks = new App.Tasks(); 2 tasks.fetch(); GET http://pomtrac.localhost/tasks

    Slide 87

    Slide 87 text

    Implemention Guide ✓ Retrieve data from API ‣ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 88

    Slide 88 text

    Implemention Guide ✓ Retrieve data from API ‣ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 89

    Slide 89 text

    1 App.TaskView = Backbone.View.extend({}); Backbone.View

    Slide 90

    Slide 90 text

    1 App.TaskView = Backbone.View.extend({ 2 tagname: 'div', 3 4 className: 'inventory-row' 5 }); Backbone.View

    Slide 91

    Slide 91 text

    1 App.TaskView = Backbone.View.extend({ 2 tagname: 'div', 3 4 className: 'inventory-row', 5 6 template: _.template($("#pomtrac-task-tmpl").html()) 7 }); Backbone.View

    Slide 92

    Slide 92 text

    1 App.TaskView = Backbone.View.extend({ 2 tagname: 'div', 3 4 className: 'inventory-row', 5 6 template: _.template($("#pomtrac-task-tmpl").html()) 7 }); Backbone.View <input class="summary textinput" type="text" value="<%= summary %>"> <input class="estimate textinput" type="text" value="<%= estimate %>"> <div class="strike">[del]</div>

    Slide 93

    Slide 93 text

    1 App.TaskView = Backbone.View.extend({ 2 tagname: 'div', 3 4 className: 'inventory-row', 5 6 template: _.template($("#pomtrac-task-tmpl").html()), 7 8 initialize: function() { 9 this.render(); 10 } 11 }); Backbone.View

    Slide 94

    Slide 94 text

    1 App.TaskView = Backbone.View.extend({ 2 tagname: 'div', 3 4 className: 'inventory-row', 5 6 template: _.template($("#pomtrac-task-tmpl").html()), 7 8 initialize: function() { 9 this.render(); 10 }, 11 12 render: function() { 13 this.$el.html(this.template(this.model.toJSON())); 14 this.summaryInput = this.$('.summary'); 15 this.estimateInput = this.$('.estimate'); 16 return this; 17 } 18 }); Backbone.View

    Slide 95

    Slide 95 text

    1 App.ActivityInventoryView = Backbone.View.extend({ 2 initialize: function() { 3 this.collection = new App.Tasks(); 4 this.collection.url = "/tasks"; 5 this.collection.fetch({ 6 success: _.bind(function(resp, status, xhr) { 7 this.render(); 8 }, this) 9 }); 10 } 11 }); Backbone.View

    Slide 96

    Slide 96 text

    1 App.ActivityInventoryView = Backbone.View.extend({ 2 initialize: function() { 3 this.collection = new App.Tasks(); 4 this.collection.url = "/tasks"; 5 this.collection.fetch({ 6 success: _.bind(function(resp, status, xhr) { 7 this.render(); 8 }, this) 9 }); 10 }, 11 12 render: function() { 13 this.collection.each(this.renderTask, this); 14 } 15 }); Backbone.View

    Slide 97

    Slide 97 text

    1 App.ActivityInventoryView = Backbone.View.extend({ 2 initialize: function() { 3 this.collection = new App.Tasks(); 4 this.collection.url = "/tasks"; 5 this.collection.fetch({ 6 success: _.bind(function(resp, status, xhr) { 7 this.render(); 8 }, this) 9 }); 10 }, 11 12 render: function() { 13 this.collection.each(this.renderTask, this); 14 }, 15 16 renderTask: function(model) { 17 var taskView = new App.TaskView({model: model}); 18 this.$el.append(taskView.el); 19 } 20 }); Backbone.View

    Slide 98

    Slide 98 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 99

    Slide 99 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ‣ Configure the application ‣ Handle events

    Slide 100

    Slide 100 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ‣ Configure the application ‣ Handle events change, click, hover, dblclick, etc.

    Slide 101

    Slide 101 text

    1 App.TaskView = Backbone.View.extend({ 19 events: { 20 'change .textinput': 'update', 21 } 22 }); Backbone.View

    Slide 102

    Slide 102 text

    1 App.TaskView = Backbone.View.extend({ 19 events: { 20 'change .textinput': 'update', 21 }, 22 23 update: function() { 24 this.model.save({ 25 'summary': this.summaryInput.val(), 26 'estimate': this.estimateInput.val() 27 }); 28 } 29 }); Backbone.View

    Slide 103

    Slide 103 text

    1 App.TaskView = Backbone.View.extend({ 19 events: { 20 'change .textinput': 'update', 21 'click .strike': 'strike' 22 }, 23 24 update: function() { 25 this.model.save({ 26 'summary': this.summaryInput.val(), 27 'estimate': this.estimateInput.val() 28 }); 29 }, 30 31 strike: function() { 32 this.remove(); 33 this.model.destroy(); 34 } 35 }); Backbone.View

    Slide 104

    Slide 104 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ‣ Configure the application ✓ Handle events

    Slide 105

    Slide 105 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ‣ Configure the application ✓ Handle events

    Slide 106

    Slide 106 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 1 $(function() { 2 App.init(); 3 });

    Slide 107

    Slide 107 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 1 window.App = {}; 1 $(function() { 2 App.init(); 3 });

    Slide 108

    Slide 108 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 3 App.init = function() { 15 }; 1 $(function() { 2 App.init(); 3 });

    Slide 109

    Slide 109 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); Accept: application/json 1 $(function() { 2 App.init(); 3 });

    Slide 110

    Slide 110 text

    1 $(function() { 2 App.init(); 3 }); 1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 10 Backbone.emulateHTTP = true; Passes a header X-HTTP-Method-Override which works with Slim to allow PUT and DELETE requests as a POST request.

    Slide 111

    Slide 111 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 1 $(function() { 2 App.init(); 3 });

    Slide 112

    Slide 112 text

    1 window.App = {}; 2 3 App.init = function() { 4 var ActivityInventory = null; 5 6 $.ajaxSetup({ 7 'dataType': 'json' 8 }); 9 10 Backbone.emulateHTTP = true; 11 12 ActivityInventory = new App.ActivityInventoryView({ 13 el: $('#activityinventory') 14 }); 15 }; 1 $(function() { 2 App.init(); 3 });

    Slide 113

    Slide 113 text

    Implemention Guide ✓ Retrieve data from API ✓ Render HTML elements ✓ Configure the application ✓ Handle events

    Slide 114

    Slide 114 text

    Wrap Up

    Slide 115

    Slide 115 text

    Wrap Up MicroPHP is about exposing small-footprint libraries that solve common problems.

    Slide 116

    Slide 116 text

    Wrap Up MicroPHP is about exposing small-footprint libraries that solve common problems. Composer and Packagist help the PHP community by exposing micro frameworks and other libraries in an easy-to-consume manner.

    Slide 117

    Slide 117 text

    Wrap Up MicroPHP is about exposing small-footprint libraries that solve common problems. Composer and Packagist help the PHP community by exposing micro frameworks and other libraries in an easy-to-consume manner. Slim makes creating a RESTful API simple.

    Slide 118

    Slide 118 text

    Wrap Up MicroPHP is about exposing small-footprint libraries that solve common problems. Composer and Packagist help the PHP community by exposing micro frameworks and other libraries in an easy-to-consume manner. Slim makes creating a RESTful API simple. Backbone.js provides just the structure a PHP dev like me needs to build on top of such APIs.

    Slide 119

    Slide 119 text

    Code Available http://github.com/jcarouth/pomtrac The lsp12 branch will not change.

    Slide 120

    Slide 120 text

    Thank You! Questions? do you have or Comments?

    Slide 121

    Slide 121 text

    https://joind.in/6351 Speakers NEED Feedback @jcarouth | [email protected]