Zend Framework MVC driven ExtJS

  • 15,327 views
Uploaded on

This talk will give attendees details on how to set up their directory layout in larger PHP/ExtJS applications, along with hints to build processing and deployment. In the second part the talk will …

This talk will give attendees details on how to set up their directory layout in larger PHP/ExtJS applications, along with hints to build processing and deployment. In the second part the talk will cover context based applications, how to detect context and how to utilize it with ExtJS. The third and last part will show how developers can use Ext.direct.* with an already existing Zend Framework backend, including merged requests and how to set up sandboxes for processing merged requests.

More in: Education , Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
15,327
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
544
Comments
0
Likes
12

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Zend Framework MVC driven ExtJS Thorsten Suckow-Homberg, K&K GmbH Sourc{ - SenchaDev Conference May 5-7, 2011 Croatia, Split
  • 2. Who am I?● Thorsten Suckow-Homberg● Born 1976, Aachen, Germany● Webdeveloper since 1999● Senior Software Developer for K&K GmbH, Aachen● Focus on planning, architecture and deployment of web based software
  • 3. Who am I?… oh, and UI programming, of course:Author of:● conjoon – http://www.conjoon.org● Ext.ux.Livegrid – http://www.ext-livegrid.com● various other open source ExtJS extensions/ components● Numerous bug reports, rants and proposals over at the sencha forums :) (MindPatterns)
  • 4. This talk will show you...● … how you should plan your directory layout in larger projects
  • 5. This talk will show you...● … how you should plan your directory layout in larger projects● … what is application context - and how to use it to your advantage
  • 6. This talk will show you...● … how you should plan your directory layout in larger projects● … what is application context - and how to use it to your advantage● … how to use Ext.Direct with existing ZF backend code
  • 7. This talk will show you...● … how you should plan your directory layout in larger projects● … what is application context - and how to use it to your advantage● … how to use Ext.Direct with existing ZF backend code● In short: ...why Zend Framework could become the framework of your choice when combining Ext and PHP
  • 8. The BasicsDirectory Layout
  • 9. The Basics – Directory Layout ● Top level should be a directory named after your project (obviously) ● ...containing three child directories:
  • 10. The Basics – Directory Layout build-tools ● Real tools, like: ● yuicompressor ● phing ● ant
  • 11. The Basics – Directory Layout build-tools ● Real tools, like: ● yuicompressor ● phing ● ant ● (XML-)build scripts ● code sanity ● tests ● deployment ● etc... in short: Continuous Integration[1]!
  • 12. The Basics – Directory Layout vendor ● All the third party libs youre using in your code ● ExtJS ● ZendFramework ● etc.
  • 13. The Basics – Directory Layout vendor ● All the third party libs youre using in your code ● ExtJS ● ZendFramework ● etc. Note: ● files from separate repository vendor branch will be merged into this directory ● Best case: developers will not touch the vendor directory ● Read [2] for more infos on how to use vendor branches
  • 14. The Basics – Directory Layout src
  • 15. The Basics – Directory Layout src ● Everything youre actually coding
  • 16. The Basics – Directory Layout src ● Everything youre actually coding: ● overrides ● extensions ● backend code ● code that might refer to vendor code ● … in short: all application-specific code your team writes
  • 17. The Basics – Directory Layout corelib
  • 18. The Basics – Directory Layout corelib ● js – your client libraries (ExtJS, own implementations)
  • 19. The Basics – Directory Layout corelib ● js – your client libraries (ExtJS, own implementations) ● php – your backend code (including tests)
  • 20. The Basics – Directory Layout datastore ● data storage definition/structure goes here
  • 21. The Basics – Directory Layout datastore ● data storage definition/structure goes here Note: ● build scripts can refer to the structure file when deploying an application
  • 22. The Basics – Directory Layout www ● one step more towards a „callable“ application
  • 23. The Basics – Directory Layout application
  • 24. The Basics – Directory Layout application ● ZF specific „frontend“ code (controllers, templates)
  • 25. The Basics – Directory Layout application ● ZF specific „frontend“ code (controllers, templates) ● and: – Meta-Information files for your application – caching directories – etc.
  • 26. The Basics – Directory Layout htdocs
  • 27. The Basics – Directory Layout htdocs ● Finally! The document root for your application ● the only „public“ folder
  • 28. The Basics – Directory Layout htdocs ● Finally! The document root for your application ● the only „public“ folder Note: ● Build-process focuses on this folder
  • 29. The Basics – Directory Layout „This layout gets way too complex!“ Dont go berserk! Theres a solution to all of it!
  • 30. The Basics – Directory Layout „Do I need to run a build process every time a line of code changed?“ „How do I get the resources from vendor into my src folder where – obviously - running code will resist?“
  • 31. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php
  • 32. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php<?php if ($isDeployment) { ?> <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script><?php } else { ?> <script type="text/javascript" src="/vendor/ext-ux-util-messagebus/src/messagebus.js"></script><?php } ?> index.phtml
  • 33. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php<?php if ($isDeployment) { ?> <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script><?php } else { ?> <script type="text/javascript" src="/vendor/ext-ux-util-messagebus/src/messagebus.js"></script><?php } ?> index.phtml# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebus "/htdocs/your_project/vendor/ext-ux-util-messagebus/src"<Directory "/htdocs/your_project/vendor/ext-ux-util-messagebus/src">Order allow,denyAllow from all</Directory> apache.conf
  • 34. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php<?php if ($isDeployment) { ?> <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script><?php } else { ?> <script type="text/javascript" src="/vendor/ext-ux-util-messagebus/src/messagebus.js"></script><?php } ?> index.phtml# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebus "/htdocs/your_project/vendor/ext-ux-util-messagebus/src"<Directory "/htdocs/your_project/vendor/ext-ux-util-messagebus/src">Order allow,denyAllow from all</Directory> apache.conf<script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script> index.phtml
  • 35. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php # Alias for Ext.ux.util.MessageBusDevelopment: Alias /js/ext-ux-util-messagebus Virtual
  • 36. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php # Alias for Ext.ux.util.MessageBusDevelopment: Alias /js/ext-ux-util-messagebus Virtual Build: ... <target name="build_js"> <delete dir="./build/js/ext-ux-util-messagebus" /> <copy todir="./build/js/ext-ux-util-messagebus" includeemptydirs="true"> <fileset dir="./vendor/ext-ux-util-messagebus"> <exclude name="**/.svn" /> </fileset> </copy> </target> ... Build process
  • 37. The Basics – Directory Layout working copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus /var/www/your_project/src/www/htdocs/index.php # Alias for Ext.ux.util.MessageBusDevelopment: Alias /js/ext-ux-util-messagebus Virtual Build: ... <target name="build_js"> <delete dir="./build/js/ext-ux-util-messagebus" /> <copy todir="./build/js/ext-ux-util-messagebus" includeemptydirs="true"> <fileset dir="./vendor/ext-ux-util-messagebus"> <exclude name="**/.svn" /> </fileset> </copy> </target> ... Build process <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script> index.phtml
  • 38. The Basics – Directory Layout Cons● will need some webserver configuration to get things working● build-files depend on initial layout, changes mean adjustment at several locations at once● needs documentation for your dev team● users need to know how to set up their dev environment when they check out „including sources“
  • 39. The Basics – Directory Layout Pros ● No symlinks –> not f***ing up the repository ● Code structured after purpose ● No need to run builds after youve changed one line of code (except for tests, of course) ● Clean approach towards build- and development-code ● Makes build-definitions easy due to strictly defined layout Advice:● Use svn.ignore and template files! - it will help you and youre coworkers to set up things on different machines
  • 40. Context based data What is a „context“?
  • 41. Context based data Application Server
  • 42. Context based data Application Server send/receive Desktop PC
  • 43. Context based data Application Server send/receive send/receive Desktop PC Mobile
  • 44. Context based data Application Server send/receive send/receive Desktop PC Mobile Context „default“
  • 45. Context based data Application Server send/receive send/receive Desktop PC Mobile Context „default“ Context „mobile“
  • 46. Context based data Why do we need it?
  • 47. Context based data● Different devices need different views● Content delivery optimizations● One domain serves all (www.senchadevcon.eu vs. m.senchadevcon.eu)● Specific data format (send/receive) might not be available on devices used by our users
  • 48. Context based data What do we need?
  • 49. Context based dataclass Zend_Controller_Action_Helper_ContextSwitch ContextSwitch.php
  • 50. Context based dataclass Zend_Controller_Action_Helper_ContextSwitch ContextSwitch.php ● Action helper that will detect context based requests ● Capable of sending specially formatted responses based on detected context and configuration ● Available as a default action helper provided by Zend Framework ● For more informations on how to use action helper, see [3]
  • 51. Context based data How does it work?
  • 52. Context based data - detection We can define a context based on (virtually) all data thats available during runtime!
  • 53. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url
  • 54. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url module
  • 55. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url controller
  • 56. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url action
  • 57. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url parameter/value pair
  • 58. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url $_GET[format] == json
  • 59. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url $_GET[format] == json● Application is now in „json“ context – i.e., return all responses json formatted, since the client told us so!
  • 60. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url $_GET[format] == json● Application is now in „json“ context – i.e., return all responses json formatted, since the client told us so!● In fact, this is a default option coming with the ContextSwitch action helper
  • 61. Context based data - detection We can define a context based on (virtually) all data thats available during runtime! Another example: ... $userAgent = strtolower($_SERVER[HTTP_USER_AGENT]); // request coming from ipad? if (strpos($userAgent, ipad) !== false) { $this->currentContext = ipad; // request coming from android? } else if (strpos($userAgent), android) !== false) { $this->currentContext = android; } ... User Agent ● Context set by detection, not manually enforced by parameters
  • 62. Context based dataSo what can it do for me?
  • 63. Context based data● Detect devices/users (webbrowser, mobile, bots)
  • 64. Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run anywhere“
  • 65. Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run anywhere“
  • 66. Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run anywhere“
  • 67. Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices:„Write once, run anywhere“ ● View variables will either be assigned to templates (plain html mixed with PHP for example) or transformed to json (xml etc.) – automatically – no need to implement special logic as long as your client can handle the response ● Requesting different formats is often just a thing of switching a parameter at client site ● Makes even delivering views from the backend very easy! ● Test a context by switching a parameter ● Only views? No, different business logic depending on the context, too!
  • 68. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 69. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) implement parents init() method ->initContext(); } to add action contexts... /** * This method will return user data to the client as requested. */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 70. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. ...which happens here: */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 71. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. getUserAction() will now... */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 72. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data response json-formatted if … return the to the client as requested. */ the get-Parameter „format“ was set to „json“ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 73. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } We have just added an action context to this action } ReceptionController.php
  • 74. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. */ public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } We have just added an action context to this action } ReceptionController.php
  • 75. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. */ Call business logic... public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 76. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { public function init() { // define the actions that should consider different contexts $this->_helper->contextSwitch() ->addActionContext(get.user, json) ->initContext(); } /** * This method will return user data to the client as requested. */ And finally: Assign values to the public function getUserAction() controllers view { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php
  • 77. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } } ReceptionController.php Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); } }); client.js
  • 78. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } Module } ReceptionController.php Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); } }); client.js
  • 79. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } Controller } ReceptionController.php Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); } }); client.js
  • 80. Context based data - example class User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } Action } ReceptionController.php Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); } }); client.js
  • 81. Context based data - exampleNote● This illustration explains how a request gets processed by Zend Framework [6]● Well use it to show how ContextSwitch changes the ResponseObject based on the applications context
  • 82. Context based data - example RequestClient invokes request
  • 83. Context based data - example Request Router Zend Framework routes toUser_ReceptionController::getUserAction()
  • 84. Context based data - example Request Router pre Any plugins defined? Dispatch Signal a preDispatch to them!
  • 85. Context based data - example Request Router pre Any plugins defined? Dispatch Signal a preDispatch to them! public function preDispatch() { } Zend_Controller_Action_Helper_Abstract
  • 86. Context based data - example Request Router pre Dispatch the action – Dispatch getUserAction() gets processed! Dispatch
  • 87. Context based data - example Request Router pre Dispatch Dispatch Action Controller public function getUserAction() { ... $this->view->userName = Peter Griffin; $this->view->userEmail = peter@birdistheword.com; } ReceptionController.php
  • 88. Context based data - example Request Router pre Dispatch Action Dispatch Controller Any plugins defined? post Signal a postDispatch to them! Dispatch
  • 89. Context based data - example Request Router pre Dispatch Action Dispatch Controller Any plugins defined? post Signal a postDispatch to them! Dispatch public function postDispatch() { $context = $this->getCurrentContext(); ... //$this->postJsonContext(); } ContextSwitch.php
  • 90. Context based data - example Request Router pre Dispatch Action Dispatch Controller post Dispatch $response->setHeader(Content-Type, application/json); ContextSwitch.php actions left? Response Object
  • 91. Context based data - example Request Router pre Dispatch Action Dispatch Controller post Dispatch $response->setHeader(Content-Type, application/json); ContextSwitch.php actions left? $response->setBody(Zend_Json::encode($view->getVars())); ContextSwitch.php Response Object
  • 92. Context based data - example Request Router pre Dispatch Action Dispatch Controller post Dispatch actions left? send response Response Object
  • 93. Context based data - example Request Router pre Dispatch Action Dispatch Controller post Dispatch actions left?{userName : „Peter Griffin“, userEmail : „peter@birdistheword.com“} console send response Response Object
  • 94. Context based data AWESOME! This makes coding a real blast!
  • 95. Skeptikal HippoIt makes sense when working with Ext 1.* and 2.*, but what about Ext.direct.*?
  • 96. Ext.direct.*What is Ext.direct.*?
  • 97. Ext.direct.* „Ext Direct is a platform and language agnostictechnology to remote server-side methods to the client-side.“[4]
  • 98. Ext.direct.*● That new kid in class no one wants to play with
  • 99. Ext.direct.*● That new kid in class no one wants to play with ● Bugs
  • 100. Ext.direct.*● That new kid in class no one wants to play with ● Bugs ● Clumsy
  • 101. Ext.direct.*● That new kid in class no one wants to play with ● Bugs ● Clumsy ● Implementation too complex
  • 102. Ext.direct.*● That new kid in class no one wants to play with ● Bugs ● Clumsy ● Implementation too complex ● The bad thing: – Sencha started to focus remote functionality in their library on Ext.direct.* with 3.*
  • 103. Ext.direct.*● That new kid in class no one wants to play with ● Bugs ● Clumsy ● Implementation too complex ● The bad thing: – Sencha started to focus remote functionality in their library on Ext.direct.* with 3.* ● The good thing: – Sencha eliminated almost all implementation issues
  • 104. Ext.direct.* - advantages● Lets you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php
  • 105. Ext.direct.* - advantages● Lets you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php user.reception.getUser(); client.js
  • 106. Ext.direct.* - advantages● Lets you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php module user.reception.getUser(); client.js
  • 107. Ext.direct.* - advantages● Lets you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php controller user.reception.getUser(); client.js
  • 108. Ext.direct.* - advantages● Lets you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php action user.reception.getUser(); client.js
  • 109. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php
  • 110. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); client.js
  • 111. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); client.js
  • 112. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); groupware.account.getFeedAccounts(); client.js Firebug
  • 113. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); groupware.account.getFeedAccounts(); client.js POST http://sourcedevcon/groupware/account/get.email.accounts POST http://sourcedevcon/groupware/account/get.feed.accounts Firebug
  • 114. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); groupware.account.getFeedAccounts(); client.js POST http://sourcedevcon/groupware/account/get.email.accounts POST http://sourcedevcon/groupware/account/get.feed.accounts Firebug POST http://sourcedevcon/groupware Firebug
  • 115. Ext.direct.* - advantages● Can stack remote procedure calls and send them as one „batched request“ class Groupware_AccountController extends Zend_Controller_Action { public function getEmailAccountsAction(){ ... } public function getFeedAccountsAction(){ ... } } GroupwareController.php groupware.account.getEmailAccounts(); groupware.account.getFeedAccounts(); client.js POST http://sourcedevcon/groupware/account/get.email.accounts POST http://sourcedevcon/groupware/account/get.feed.accounts Firebug POST http://sourcedevcon/groupware extDirectData [{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}, {"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}] Firebug
  • 116. Ext.direct.*Batched request – what gives?
  • 117. Ext.direct.*● Can reduce serverload (1 request with n calls to specific actions instead of n calls)
  • 118. Ext.direct.*● Can reduce serverload (1 request with n calls to specific actions instead of n calls)● Reduces possibility of losing connections (http allows for n concurrent connections to one domain at a time)
  • 119. Ext.direct.*● Can reduce serverload (1 request with n calls to specific actions instead of n calls)● Reduces possibility of losing connections (http allows for n concurrent connections to one domain at a time) This alone are tremendously important reasons for you to go ahead and make friendship with that new kid in class!
  • 120. Ext.direct.* w/ Zend FrameworkUnfortunately, not supported out of the box :(
  • 121. Ext.direct.* w/ Zend Framework … so lets find a solution. Lets sum up our goals:
  • 122. Ext.direct.* w/ Zend Framework ● Switch client code to Ext.direct.* without having to change backend source code ● Add another tier of complexity and automatically create backend methods/client code. Tests, changing naming conventions etc. have to be added by hand then. ● Keep our backend testable, reusable and make sure it runs with any other client library/ implementation
  • 123. Ext.direct.* w/ Zend Framework ● Switch client code to Ext.direct.* without having to change backend source code ● Add another tier of complexity and automatically create backend methods/client code. Tests, changing naming conventions etc. have to be added by hand then. ● Keep our backend testable, reusable and make sure it runs with any other client library/ implementation
  • 124. Ext.direct.* w/ Zend Framework ● Switch client code to Ext.direct.* without having to change backend source code ● Add another tier of complexity and automatically create backend methods/client code. Tests, changing naming conventions etc. have to be added by hand then. ● Keep our backend testable, reusable and make sure it runs with any other client library/ implementation
  • 125. Ext.direct.* w/ Zend Framework ● Switch client code to Ext.direct.* without having to change backend source code ● Add another tier of complexity and automatically create backend methods/client code. Tests, changing naming conventions etc. have to be added by hand then. ● Keep our backend testable, reusable and make sure it runs with any other client library/ implementation
  • 126. Ext.direct.* w/ Zend Framework What we need to do:
  • 127. Ext.direct.* w/ Zend Framework – Show requests sent by Ext.direct.* their way through Zend Framework to their module/controller/action – Teach Zend Framework how to distinguish between old fashioned and merged requests – Show Zend Framework how to disassemble 1 request into n requests – Give Zend Framework a sandbox where it can work/play/you name it with a disamssembled request – Collect sandboxed requests and merge them back into one response
  • 128. Ext.direct.* w/ Zend Framework Change Ext.direct.RemotingProvider URLs on the fly
  • 129. Ext.direct.* w/ Zend Framework Remember? The Ext.direct.RemotingProvider exposes access to server side methods on the client. By mapping those remote methods to the client, there is almost no need anymore to spray URLs around the source like crazy. It establishes a connection between the client and the backend by providing a programmer friendly interface.
  • 130. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 131. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, URL format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 132. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, URL format : json, type : zend, actions : { account : [{ „action“ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 133. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, URL format : json, type : zend, actions : { account : [{ „action“ name : getFeedAccounts }, { name : getEmailAccounts method }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 134. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 135. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); namespace client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 136. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] action }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 137. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider method }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 138. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware Firebug
  • 139. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 140. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 141. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 142. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 143. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 144. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { ...} /groupware Firebug
  • 145. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { ...} /groupware Firebug
  • 146. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { http://sourcedevcon/groupware/account/get.email.accounts ...} /groupware Firebug
  • 147. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); URL = module client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { Http://sourcedevcon/groupware/account/get.email.accounts ...} /groupware Firebug
  • 148. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); URL = module client.js action = controller POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { http://sourcedevcon/groupware/account/get.email.accounts ...} /groupware Firebug
  • 149. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); URL = module client.js action = controller POST http://sourcedevcon/groupware extDirectData method = action {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { http://sourcedevcon/groupware/account/get.email.accounts ...} /groupware Firebug
  • 150. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, URL format : json, type : zend, actions : { account : [{ „action“ name : getFeedAccounts }, { name : getEmailAccounts method }] }, namespace : eu.sourcedevcon.provider }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); URL = module client.js action = controller POST http://sourcedevcon/groupware extDirectData method = action {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebugif (isset($_POST[extDirectData])) { http://sourcedevcon/groupware/account/get.email.accounts ...} /groupware Firebug
  • 151. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 152. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js
  • 153. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.js Ext.define(eu.sourcedevcon.direct.ZendProvider, { alias : direct.zendprovider, extend : Ext.direct.RemotingProvider }); ZendProvider.js
  • 154. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = action client.js
  • 155. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 156. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 157. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 158. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 159. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 160. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 161. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { ContextSwitch url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 162. Ext.direct.* w/ Zend FrameworkURL = module action = controller method = actionExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 163. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 164. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware
  • 165. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware POST http://sourcedevcon/groupware/account/get.email.accounts/format/json extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  • 166. Ext.direct.* w/ Zend Framework POST http://sourcedevcon/groupware/account/get.email.accounts/format/json extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug Note: ● Teach your actions the „extDirectData“-POST parameter
  • 167. Ext.direct.* w/ Zend Framework POST http://sourcedevcon/groupware/account/get.email.accounts/format/json extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug Note: ● Teach your actions the „extDirectData“-POST parameter ● Your responses must return the „tid“ as received by the request
  • 168. Ext.direct.* w/ Zend Framework Will do! Let me send a batched request now!
  • 169. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts(); client.js
  • 170. Ext.direct.* w/ Zend Framework Ext.direct.Manager.addProvider({ id : eu.sourcedevcon.provider, enableUrlEncode : extDirectData, url : ./groupware, format : json, type : zend, actions : { account : [{ name : getFeedAccounts }, { name : getEmailAccounts }] }, namespace : eu.sourcedevcon.provider }); client.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts(); client.js POST http://sourcedevcon/groupware extDirectData [{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}, {"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}] Firebug
  • 171. Ext.direct.* w/ Zend Framework ...?
  • 172. Ext.direct.* w/ Zend Framework queueTransaction: function(transaction){ var me = this, enableBuffer = me.enableBuffer; if (transaction.form) { me.sendFormRequest(transaction); return; } me.callBuffer.push(transaction); if (enableBuffer) { if (!me.callTask) { me.callTask = Ext.create(Ext.util.DelayedTask, me.combineAndSend, me); } me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10); } else { me.combineAndSend(); } } RemotingProvider.js
  • 173. Ext.direct.* w/ Zend Framework queueTransaction: function(transaction){ add transaction to callBuffer Array var me = this, enableBuffer = me.enableBuffer; if (transaction.form) { me.sendFormRequest(transaction); return; } me.callBuffer.push(transaction); if (enableBuffer) { if (!me.callTask) { me.callTask = Ext.create(Ext.util.DelayedTask, me.combineAndSend, me); } me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10); } else { me.combineAndSend(); } } RemotingProvider.js
  • 174. Ext.direct.* w/ Zend Framework queueTransaction: function(transaction){ add transaction to callBuffer Array var me = this, enableBuffer = me.enableBuffer; if batching is enabled, create a task if (transaction.form) { me.sendFormRequest(transaction); return; } me.callBuffer.push(transaction); if (enableBuffer) { if (!me.callTask) { me.callTask = Ext.create(Ext.util.DelayedTask, me.combineAndSend, me); } me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10); } else { me.combineAndSend(); } } RemotingProvider.js
  • 175. Ext.direct.* w/ Zend Framework queueTransaction: function(transaction){ add transaction to callBuffer Array var me = this, enableBuffer = me.enableBuffer; if batching is enabled, create a task wait for 10ms for another if (transaction.form) { transaction to be added me.sendFormRequest(transaction); return; } me.callBuffer.push(transaction); if (enableBuffer) { if (!me.callTask) { me.callTask = Ext.create(Ext.util.DelayedTask, me.combineAndSend, me); } me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10); } else { me.combineAndSend(); } } RemotingProvider.js
  • 176. Ext.direct.* w/ Zend Framework queueTransaction: function(transaction){ add transaction to callBuffer Array var me = this, enableBuffer = me.enableBuffer; if batching is enabled, create a task wait for 10ms for another if (transaction.form) { transaction to be added me.sendFormRequest(transaction); no more transactions coming in? Call return; combineAndSend } me.callBuffer.push(transaction); if (enableBuffer) { if (!me.callTask) { me.callTask = Ext.create(Ext.util.DelayedTask, me.combineAndSend, me); } me.callTask.delay(Ext.isNumber(enableBuffer) ? enableBuffer : 10); } else { me.combineAndSend(); } } RemotingProvider.js
  • 177. Ext.direct.* w/ Zend Frameworkeu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts(); client.jsExt.Ajax.on(beforerequest, function(conn, options) { var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 178. Ext.direct.* w/ Zend Frameworkeu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts(); client.jsExt.Ajax.on(beforerequest, function(conn, options) { false var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; action = action.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var module = options.url; var url = module + (module.lastIndexOf(/) == module.length-1 ? : /) + controller + / + action; if (options.transaction.provider.format) { url += /format/ + options.transaction.provider.format; } options.url = url; options.disableCaching = true; }}); client.js
  • 179. Ext.direct.* w/ Zend Frameworkeu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts(); client.jsExt.Ajax.on(beforerequest, function(conn, options) { false var trans = options.transaction; if (trans && trans.provider && trans.provider.type == zend) { var controller = options.transaction.action; controller = controller.replace(/([a-z])([A-Z])/g, "$1.$2").toLowerCase(); var action = options.transaction.method; ... client.js POST http://sourcedevcon/groupware extDirectData [{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}, {"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}] Firebug
  • 180. Ext.direct.* w/ Zend Framework ...and now for something completely different.
  • 181. Ext.direct.* w/ Zend FrameworkIntroducingSourcedevcon_Controller_Plugin_ExtRequest[5]
  • 182. Ext.direct.* w/ Zend FrameworkWhat is this Plugin?● „Plugin“ for Zend Frameworks Front Controller● Actually not a real plugin, but rather a mediator for preDispatch/postDispatch Events● Capable of detecting batched requests● Capable of disassembling a batched request into individual requests● Capable of creating a sandbox for each request, and processing it
  • 183. Ext.direct.* w/ Zend Framework
  • 184. Ext.direct.* w/ Zend Framework dispatchLoopStartup
  • 185. Ext.direct.* w/ Zend Framework dispatchLoopStartup dispatchLoopShutdown
  • 186. Ext.direct.* w/ Zend Framework pre Dispatch Action Dispatch Controller dispatchLoopStartup post dispatchLoopShutdown Dispatch Response Object
  • 187. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.php
  • 188. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, The POST parameter that holds a batched request additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.php
  • 189. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, Additional headers for the additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), response object action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.php
  • 190. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => Additional parameters we add json), action => multi.request, to each sandboxed request controller => ext, module => default )); $extDirect->registerPlugins(); index.php
  • 191. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, The default module/controller/action module => default before disassembling )); $extDirect->registerPlugins(); index.php
  • 192. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); Register the plugins at the Front Controller index.php
  • 193. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.phppublic function dispatchLoopStartup(){ $this->_parent->notifyDispatchLoopStartup();} PreDispatcher.php
  • 194. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.phppublic function dispatchLoopStartup() public function dispatchLoopShutdown(){ { $this->_parent->notifyDispatchLoopStartup(); $this->_parent->notifyDispatchLoopShutdown();} } PreDispatcher.php PostDispatcher.php
  • 195. Ext.direct.* w/ Zend Framework $extDirect = new Sourcedevcon_Controller_Plugin_ExtRequest(array( extParameter => extDirectData, additionalHeaders => array(Content-Type => application/json), additionalParams => array(format => json), action => multi.request, controller => ext, module => default )); $extDirect->registerPlugins(); index.phppublic function dispatchLoopStartup() public function dispatchLoopShutdown(){ { $this->_parent->notifyDispatchLoopStartup(); $this->_parent->notifyDispatchLoopShutdown();} } PreDispatcher.php PostDispatcher.php preDispatch dispatch postDispatch Request_Http Response_Http
  • 196. Thank you Thank you!... questions?
  • 197. Resources[1] http://en.wikipedia.org/wiki/Continuous_integration[2] http://svnbook.red-bean.com/en/1.5/svn.advanced.vendorbr.html[3] http://zendframework.com/manual/en/zend.controller.actionhelpers.html[4] http://www.sencha.com/products/extjs/extdirect[5] http://thorsten.suckow-homberg.de/sourcedevcon[6] http://framework.zend.com/manual/en/zend.controller.basics.html