Successfully reported this slideshow.
Your SlideShare is downloading. ×

Zend Framework MVC driven ExtJS

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Upcoming SlideShare
Doctrine Project
Doctrine Project
Loading in …3
×

Check these out next

1 of 198 Ad

Zend Framework MVC driven ExtJS

Download to read offline

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.

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.

Advertisement
Advertisement

More Related Content

Similar to Zend Framework MVC driven ExtJS (20)

Advertisement

Recently uploaded (20)

Zend Framework MVC driven ExtJS

  1. 1. Zend Framework MVC driven ExtJS Thorsten Suckow-Homberg, K&K GmbH Sourc{ - SenchaDev Conference May 5-7, 2011 Croatia, Split
  2. 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. 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. 4. This talk will show you... ● … how you should plan your directory layout in larger projects
  5. 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. 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. 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. 8. The Basics Directory Layout
  9. 9. The Basics – Directory Layout ● Top level should be a directory named after your project (obviously) ● ...containing three child directories:
  10. 10. The Basics – Directory Layout build-tools ● Real tools, like: ● yuicompressor ● phing ● ant
  11. 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. 12. The Basics – Directory Layout vendor ● All the third party libs you're using in your code ● ExtJS ● ZendFramework ● etc.
  13. 13. The Basics – Directory Layout vendor ● All the third party libs you're 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. 14. The Basics – Directory Layout src
  15. 15. The Basics – Directory Layout src ● Everything you're actually coding
  16. 16. The Basics – Directory Layout src ● Everything you're actually coding: ● overrides ● extensions ● backend code ● code that might refer to vendor code ● … in short: all application-specific code your team writes
  17. 17. The Basics – Directory Layout corelib
  18. 18. The Basics – Directory Layout corelib ● js – your client libraries (ExtJS, own implementations)
  19. 19. The Basics – Directory Layout corelib ● js – your client libraries (ExtJS, own implementations) ● php – your backend code (including tests)
  20. 20. The Basics – Directory Layout datastore ● data storage definition/structure goes here
  21. 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. 22. The Basics – Directory Layout www ● one step more towards a „callable“ application
  23. 23. The Basics – Directory Layout application
  24. 24. The Basics – Directory Layout application ● ZF specific „frontend“ code (controllers, templates)
  25. 25. The Basics – Directory Layout application ● ZF specific „frontend“ code (controllers, templates) ● and: – Meta-Information files for your application – caching directories – etc.
  26. 26. The Basics – Directory Layout htdocs
  27. 27. The Basics – Directory Layout htdocs ● Finally! The document root for your application ● the only „public“ folder
  28. 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. 29. The Basics – Directory Layout „This layout gets way too complex!“ Don't go berserk! There's a solution to all of it!
  30. 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. 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. 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. 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.MessageBus Alias /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,deny Allow from all </Directory> apache.conf
  34. 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.MessageBus Alias /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,deny Allow from all </Directory> apache.conf <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script> index.phtml
  35. 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.MessageBus Development: Alias /js/ext-ux-util-messagebus Virtual
  36. 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.MessageBus Development: 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. 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.MessageBus Development: 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. 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. 39. The Basics – Directory Layout Pros ● No symlinks –> not f***ing up the repository ● Code structured after purpose ● No need to run builds after you've 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 you're coworkers to set up things on different machines
  40. 40. Context based data What is a „context“?
  41. 41. Context based data Application Server
  42. 42. Context based data Application Server send/receive Desktop PC
  43. 43. Context based data Application Server send/receive send/receive Desktop PC Mobile
  44. 44. Context based data Application Server send/receive send/receive Desktop PC Mobile Context „default“
  45. 45. Context based data Application Server send/receive send/receive Desktop PC Mobile Context „default“ Context „mobile“
  46. 46. Context based data Why do we need it?
  47. 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. 48. Context based data What do we need?
  49. 49. Context based data class Zend_Controller_Action_Helper_ContextSwitch ContextSwitch.php
  50. 50. Context based data class 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. 51. Context based data How does it work?
  52. 52. Context based data - detection We can define a context based on (virtually) all data that's available during runtime!
  53. 53. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url
  54. 54. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url module
  55. 55. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url controller
  56. 56. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url action
  57. 57. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url parameter/value pair
  58. 58. Context based data - detection We can define a context based on (virtually) all data that's available during runtime! For example: http://myproject.com/user/reception/get.user/format/json url $_GET['format'] == 'json'
  59. 59. Context based data - detection We can define a context based on (virtually) all data that's 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. 60. Context based data - detection We can define a context based on (virtually) all data that's 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. 61. Context based data - detection We can define a context based on (virtually) all data that's 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. 62. Context based data So what can it do for me?
  63. 63. Context based data ● Detect devices/users (webbrowser, mobile, bots)
  64. 64. Context based data ● Detect devices/users (webbrowser, mobile, bots) ● One codebase for all devices: „Write once, run anywhere“
  65. 65. Context based data ● Detect devices/users (webbrowser, mobile, bots) ● One codebase for all devices: „Write once, run anywhere“
  66. 66. Context based data ● Detect devices/users (webbrowser, mobile, bots) ● One codebase for all devices: „Write once, run anywhere“
  67. 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. 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. 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 parent's 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. 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. 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. 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. 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. 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. 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. 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() controller's view { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; } } ReceptionController.php
  77. 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. 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. 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. 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. 81. Context based data - example Note ● This illustration explains how a request gets processed by Zend Framework [6] ● We'll use it to show how ContextSwitch changes the ResponseObject based on the application's context
  82. 82. Context based data - example Request Client invokes request
  83. 83. Context based data - example Request Router Zend Framework routes to User_ReceptionController::getUserAction()
  84. 84. Context based data - example Request Router pre Any plugins defined? Dispatch Signal a preDispatch to them!
  85. 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. 86. Context based data - example Request Router pre Dispatch the action – Dispatch getUserAction() gets processed! Dispatch
  87. 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. 88. Context based data - example Request Router pre Dispatch Action Dispatch Controller Any plugins defined? post Signal a postDispatch to them! Dispatch
  89. 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. 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. 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. 92. Context based data - example Request Router pre Dispatch Action Dispatch Controller post Dispatch actions left? send response Response Object
  93. 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. 94. Context based data AWESOME! This makes coding a real blast!
  95. 95. Skeptikal Hippo It makes sense when working with Ext 1.* and 2.*, but what about Ext.direct.*?
  96. 96. Ext.direct.* What is Ext.direct.*?
  97. 97. Ext.direct.* „Ext Direct is a platform and language agnostic technology to remote server-side methods to the client-side.“[4]
  98. 98. Ext.direct.* ● That new kid in class no one wants to play with
  99. 99. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs
  100. 100. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs ● Clumsy
  101. 101. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs ● Clumsy ● Implementation too complex
  102. 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. 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. 104. Ext.direct.* - advantages ● Let's you call remote procedures directly from client code class User_ReceptionController extends Zend_Controller_Action { public function getUserAction() { ... } } ReceptionController.php
  105. 105. Ext.direct.* - advantages ● Let's 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. 106. Ext.direct.* - advantages ● Let's 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. 107. Ext.direct.* - advantages ● Let's 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. 108. Ext.direct.* - advantages ● Let's 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. 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. 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. 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. 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. 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. 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. 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. 116. Ext.direct.* Batched request – what gives?
  117. 117. Ext.direct.* ● Can reduce serverload (1 request with n calls to specific actions instead of n calls)
  118. 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. 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. 120. Ext.direct.* w/ Zend Framework Unfortunately, not supported out of the box :(
  121. 121. Ext.direct.* w/ Zend Framework … so let's find a solution. Let's sum up our goals:
  122. 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. 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. 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. 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. 126. Ext.direct.* w/ Zend Framework What we need to do:
  127. 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. 128. Ext.direct.* w/ Zend Framework Change Ext.direct.RemotingProvider URLs on the fly
  129. 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. 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. 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. 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. 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. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  135. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  136. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  137. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  138. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware Firebug
  139. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  140. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  141. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  142. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  143. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware extDirectData {"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1} Firebug
  144. 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} Firebug if (isset($_POST['extDirectData'])) { ... } /groupware Firebug
  145. 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} Firebug if (isset($_POST['extDirectData'])) { ... } /groupware Firebug
  146. 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} Firebug if (isset($_POST['extDirectData'])) { http://sourcedevcon/groupware/account/get.email.accounts ... } /groupware Firebug
  147. 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} Firebug if (isset($_POST['extDirectData'])) { Http://sourcedevcon/groupware/account/get.email.accounts ... } /groupware Firebug
  148. 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} Firebug if (isset($_POST['extDirectData'])) { http://sourcedevcon/groupware/account/get.email.accounts ... } /groupware Firebug
  149. 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} Firebug if (isset($_POST['extDirectData'])) { http://sourcedevcon/groupware/account/get.email.accounts ... } /groupware Firebug
  150. 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} Firebug if (isset($_POST['extDirectData'])) { http://sourcedevcon/groupware/account/get.email.accounts ... } /groupware Firebug
  151. 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. 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. 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. 154. Ext.direct.* w/ Zend Framework URL = module action = controller method = action client.js
  155. 155. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 156. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 157. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 158. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 159. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 160. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 161. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 162. Ext.direct.* w/ Zend Framework URL = module action = controller method = action Ext.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. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  164. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js POST http://sourcedevcon/groupware
  165. 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.js eu.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. 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. 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. 168. Ext.direct.* w/ Zend Framework Will do! Let me send a batched request now!
  169. 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.js eu.sourcedevcon.provider.account.getEmailAccounts(); eu.sourcedevcon.provider.account.getFeedAccounts(); client.js
  170. 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.js eu.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. 171. Ext.direct.* w/ Zend Framework ...?
  172. 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. 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. 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. 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. 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. 177. Ext.direct.* w/ Zend Framework eu.sourcedevcon.provider.account.getEmailAccounts(); eu.sourcedevcon.provider.account.getFeedAccounts(); client.js Ext.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. 178. Ext.direct.* w/ Zend Framework eu.sourcedevcon.provider.account.getEmailAccounts(); eu.sourcedevcon.provider.account.getFeedAccounts(); client.js Ext.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. 179. Ext.direct.* w/ Zend Framework eu.sourcedevcon.provider.account.getEmailAccounts(); eu.sourcedevcon.provider.account.getFeedAccounts(); client.js Ext.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. 180. Ext.direct.* w/ Zend Framework ...and now for something completely different.
  181. 181. Ext.direct.* w/ Zend Framework Introducing Sourcedevcon_Controller_Plugin_ExtRequest[5]
  182. 182. Ext.direct.* w/ Zend Framework What is this Plugin? ● „Plugin“ for Zend Framework's 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. 183. Ext.direct.* w/ Zend Framework
  184. 184. Ext.direct.* w/ Zend Framework dispatchLoopStartup
  185. 185. Ext.direct.* w/ Zend Framework dispatchLoopStartup dispatchLoopShutdown
  186. 186. Ext.direct.* w/ Zend Framework pre Dispatch Action Dispatch Controller dispatchLoopStartup post dispatchLoopShutdown Dispatch Response Object
  187. 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. 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

×