SlideShare a Scribd company logo
1 of 198
Download to read offline
Zend Framework MVC driven ExtJS



 Thorsten Suckow-Homberg, K&K GmbH

         Sourc{ - SenchaDev Conference
                  May 5-7, 2011
                   Croatia, Split
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
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)
This talk will show you...

●   … how you should plan your directory layout in
    larger projects
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
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
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
The Basics




Directory Layout
The Basics – Directory Layout
               ●   Top level should be a
                   directory named after your
                   project (obviously)
               ●   ...containing three child
                   directories:
The Basics – Directory Layout
                   build-tools
               ●   Real tools, like:
                   ●   yuicompressor
                   ●   phing
                   ●   ant
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]!
The Basics – Directory Layout
                   vendor
               ●   All the third party libs
                   you're using in your code
                   ●   ExtJS
                   ●   ZendFramework
                   ●   etc.
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
The Basics – Directory Layout

                src
The Basics – Directory Layout

                   src
               ●   Everything you're actually
                   coding
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
The Basics – Directory Layout
                corelib
The Basics – Directory Layout
                corelib
                ●   js – your client libraries
                    (ExtJS, own
                    implementations)
The Basics – Directory Layout
                corelib
                ●   js – your client libraries
                    (ExtJS, own
                    implementations)
                ●   php – your backend
                    code (including tests)
The Basics – Directory Layout
                datastore
                ●   data storage
                    definition/structure goes
                    here
The Basics – Directory Layout
                                 datastore
                                  ●   data storage
                                      definition/structure goes
                                      here




 Note:
 ●   build scripts can refer to the structure file when deploying
     an application
The Basics – Directory Layout
                www
                ●   one step more towards
                    a „callable“ application
The Basics – Directory Layout
                application
The Basics – Directory Layout
                application
                ●   ZF specific „frontend“
                    code (controllers,
                    templates)
The Basics – Directory Layout
                application
                ●   ZF specific „frontend“
                    code (controllers,
                    templates)
                ●   and:
                     –   Meta-Information
                         files for your
                         application
                     –   caching directories
                     –   etc.
The Basics – Directory Layout
                htdocs
The Basics – Directory Layout
                htdocs
                ●   Finally! The document
                    root for your application
                ●   the only „public“ folder
The Basics – Directory Layout
                                htdocs
                                 ●   Finally! The document
                                     root for your application
                                 ●   the only „public“ folder




 Note:
 ●   Build-process focuses on this folder
The Basics – Directory Layout
                „This layout gets way too
                complex!“


                Don't go berserk!


                There's a solution to all of
                it!
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?“
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
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
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
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
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
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
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
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“
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
Context based data




  What is a „context“?
Context based data


             Application Server
Context based data


                    Application Server




     send/receive




    Desktop PC
Context based data


                    Application Server




     send/receive             send/receive




    Desktop PC                               Mobile
Context based data


                       Application Server




     send/receive                send/receive




     Desktop PC                                 Mobile



   Context „default“
Context based data


                       Application Server




     send/receive                send/receive




     Desktop PC                                 Mobile



   Context „default“                  Context „mobile“
Context based data




  Why do we need it?
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
Context based data




   What do we need?
Context based data

class Zend_Controller_Action_Helper_ContextSwitch
                                       ContextSwitch.php
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]
Context based data




   How does it work?
Context based data - detection
 We can define a context based on (virtually) all data
 that's available during runtime!
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
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
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
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
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
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'
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!
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
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
Context based data




So what can it do for me?
Context based data
●   Detect devices/users (webbrowser, mobile, bots)
Context based data
●   Detect devices/users (webbrowser, mobile, bots)
●   One codebase for all devices: „Write once, run
    anywhere“
Context based data
●   Detect devices/users (webbrowser, mobile, bots)
●   One codebase for all devices: „Write once, run
    anywhere“
Context based data
●   Detect devices/users (webbrowser, mobile, bots)
●   One codebase for all devices: „Write once, run
    anywhere“
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!
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Context based data - example
                    Request




Client invokes request
Context based data - example
                     Request        Router




      Zend Framework routes to
User_ReceptionController::getUserAction()
Context based data - example
      Request   Router      pre         Any plugins defined?
                         Dispatch   Signal a preDispatch to them!
Context based data - example
      Request   Router      pre                  Any plugins defined?
                         Dispatch            Signal a preDispatch to them!




                                    public function preDispatch()
                                    {
                                    }
                                    Zend_Controller_Action_Helper_Abstract
Context based data - example
      Request   Router      pre         Dispatch the action –
                         Dispatch   getUserAction() gets processed!




                         Dispatch
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
Context based data - example
      Request   Router      pre
                         Dispatch




                                     Action
                         Dispatch
                                    Controller


                                              Any plugins defined?
                           post           Signal a postDispatch to them!
                         Dispatch
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
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
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
Context based data - example
      Request   Router      pre
                         Dispatch




                                      Action
                         Dispatch
                                     Controller




                            post
                          Dispatch




                          actions
                           left?




                           send
                         response    Response
                                      Object
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
Context based data


          AWESOME!

 This makes coding a real blast!
Skeptikal Hippo




It makes sense when working with Ext 1.*
   and 2.*, but what about Ext.direct.*?
Ext.direct.*




What is Ext.direct.*?
Ext.direct.*




 „Ext Direct is a platform and language agnostic
technology to remote server-side methods to the
                   client-side.“[4]
Ext.direct.*
●   That new kid in class no one wants to play with
Ext.direct.*
●   That new kid in class no one wants to play with
    ●   Bugs
Ext.direct.*
●   That new kid in class no one wants to play with
    ●   Bugs
    ●   Clumsy
Ext.direct.*
●   That new kid in class no one wants to play with
    ●   Bugs
    ●   Clumsy
    ●   Implementation too complex
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.*
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
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
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
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
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
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
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
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
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
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
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
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
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
Ext.direct.*




Batched request – what gives?
Ext.direct.*
●   Can reduce serverload (1 request with n calls to
    specific actions instead of n calls)
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)
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!
Ext.direct.* w/ Zend Framework




Unfortunately, not supported out of the box :(
Ext.direct.* w/ Zend Framework




       … so let's find a solution.
       Let's sum up our goals:
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
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
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
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
Ext.direct.* w/ Zend Framework




        What we need to do:
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
Ext.direct.* w/ Zend Framework




    Change Ext.direct.RemotingProvider
             URLs on the fly
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.
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.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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.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.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
Ext.direct.* w/ Zend Framework
URL = module   action = controller   method = action




                                           client.js
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
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
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
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
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
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
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
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
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
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
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
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
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
Ext.direct.* w/ Zend Framework




 Will do! Let me send a batched request now!
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
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
Ext.direct.* w/ Zend Framework




    ...?
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
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
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
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
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
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
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
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
Ext.direct.* w/ Zend Framework




       ...and now for something
          completely different.
Ext.direct.* w/ Zend Framework
Introducing

Sourcedevcon_Controller_Plugin_ExtRequest[5]
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
Ext.direct.* w/ Zend Framework
Ext.direct.* w/ Zend Framework



 dispatchLoopStartup
Ext.direct.* w/ Zend Framework



 dispatchLoopStartup



 dispatchLoopShutdown
Ext.direct.* w/ Zend Framework
                           pre
                        Dispatch




                                    Action
                        Dispatch
                                   Controller
 dispatchLoopStartup


                          post
 dispatchLoopShutdown
                        Dispatch




                                   Response
                                    Object
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
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
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS
Zend Framework MVC driven ExtJS

More Related Content

Similar to Zend Framework MVC driven ExtJS

Rapidly prototyping web applications using BackPress
Rapidly prototyping web applications using BackPressRapidly prototyping web applications using BackPress
Rapidly prototyping web applications using BackPressNathaniel Taintor
 
Django dev-env-my-way
Django dev-env-my-wayDjango dev-env-my-way
Django dev-env-my-wayRobert Lujo
 
Organinzing Your PHP Projects (2010 Memphis PHP)
Organinzing Your PHP Projects (2010 Memphis PHP)Organinzing Your PHP Projects (2010 Memphis PHP)
Organinzing Your PHP Projects (2010 Memphis PHP)Paul Jones
 
Organizing Your PHP Projects (2010 ConFoo)
Organizing Your PHP Projects (2010 ConFoo)Organizing Your PHP Projects (2010 ConFoo)
Organizing Your PHP Projects (2010 ConFoo)Paul Jones
 
Implementing a Symfony Based CMS in a Publishing Company
Implementing a Symfony Based CMS in a Publishing CompanyImplementing a Symfony Based CMS in a Publishing Company
Implementing a Symfony Based CMS in a Publishing CompanyMarcos Labad
 
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...Kostas Mavridis
 
UKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUlrich Krause
 
IDE and Toolset For Magento Development
IDE and Toolset For Magento DevelopmentIDE and Toolset For Magento Development
IDE and Toolset For Magento DevelopmentAbid Malik
 
APEX Application Lifecycle and Deployment 20220714.pdf
APEX Application Lifecycle and Deployment 20220714.pdfAPEX Application Lifecycle and Deployment 20220714.pdf
APEX Application Lifecycle and Deployment 20220714.pdfRichard Martens
 
Magento 2 Workflows
Magento 2 WorkflowsMagento 2 Workflows
Magento 2 WorkflowsRyan Street
 
Introduction to r
Introduction to rIntroduction to r
Introduction to rgslicraf
 
The Ultimate IBM and Lotus on Linux Workshop for Windows Admins
The Ultimate IBM and Lotus on Linux Workshop for Windows AdminsThe Ultimate IBM and Lotus on Linux Workshop for Windows Admins
The Ultimate IBM and Lotus on Linux Workshop for Windows AdminsBill Malchisky Jr.
 
MongoDB: Advantages of an Open Source NoSQL Database
MongoDB: Advantages of an Open Source NoSQL DatabaseMongoDB: Advantages of an Open Source NoSQL Database
MongoDB: Advantages of an Open Source NoSQL DatabaseFITC
 
Lecture 2_ Intro to laravel.pptx
Lecture 2_ Intro to laravel.pptxLecture 2_ Intro to laravel.pptx
Lecture 2_ Intro to laravel.pptxSaziaRahman
 

Similar to Zend Framework MVC driven ExtJS (20)

Rapidly prototyping web applications using BackPress
Rapidly prototyping web applications using BackPressRapidly prototyping web applications using BackPress
Rapidly prototyping web applications using BackPress
 
Django dev-env-my-way
Django dev-env-my-wayDjango dev-env-my-way
Django dev-env-my-way
 
Front end frameworks
Front end frameworksFront end frameworks
Front end frameworks
 
Organinzing Your PHP Projects (2010 Memphis PHP)
Organinzing Your PHP Projects (2010 Memphis PHP)Organinzing Your PHP Projects (2010 Memphis PHP)
Organinzing Your PHP Projects (2010 Memphis PHP)
 
Organizing Your PHP Projects (2010 ConFoo)
Organizing Your PHP Projects (2010 ConFoo)Organizing Your PHP Projects (2010 ConFoo)
Organizing Your PHP Projects (2010 ConFoo)
 
Implementing a Symfony Based CMS in a Publishing Company
Implementing a Symfony Based CMS in a Publishing CompanyImplementing a Symfony Based CMS in a Publishing Company
Implementing a Symfony Based CMS in a Publishing Company
 
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...
EoinWoods_WhereDidMyArchitectureGoPreservingSoftwareArchitectureInItsImplemen...
 
UKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basicsUKLUG 2012 - XPages, Beyond the basics
UKLUG 2012 - XPages, Beyond the basics
 
Scaling PHP apps
Scaling PHP appsScaling PHP apps
Scaling PHP apps
 
Node.js an Exectutive View
Node.js an Exectutive ViewNode.js an Exectutive View
Node.js an Exectutive View
 
Miami2015
Miami2015Miami2015
Miami2015
 
IDE and Toolset For Magento Development
IDE and Toolset For Magento DevelopmentIDE and Toolset For Magento Development
IDE and Toolset For Magento Development
 
APEX Application Lifecycle and Deployment 20220714.pdf
APEX Application Lifecycle and Deployment 20220714.pdfAPEX Application Lifecycle and Deployment 20220714.pdf
APEX Application Lifecycle and Deployment 20220714.pdf
 
Magento 2 Workflows
Magento 2 WorkflowsMagento 2 Workflows
Magento 2 Workflows
 
Automation in Drupal
Automation in DrupalAutomation in Drupal
Automation in Drupal
 
Introduction to r
Introduction to rIntroduction to r
Introduction to r
 
The Ultimate IBM and Lotus on Linux Workshop for Windows Admins
The Ultimate IBM and Lotus on Linux Workshop for Windows AdminsThe Ultimate IBM and Lotus on Linux Workshop for Windows Admins
The Ultimate IBM and Lotus on Linux Workshop for Windows Admins
 
MongoDB: Advantages of an Open Source NoSQL Database
MongoDB: Advantages of an Open Source NoSQL DatabaseMongoDB: Advantages of an Open Source NoSQL Database
MongoDB: Advantages of an Open Source NoSQL Database
 
Lecture 2_ Intro to laravel.pptx
Lecture 2_ Intro to laravel.pptxLecture 2_ Intro to laravel.pptx
Lecture 2_ Intro to laravel.pptx
 
New paradigms
New paradigmsNew paradigms
New paradigms
 

More from Thorsten Suckow-Homberg

More from Thorsten Suckow-Homberg (6)

Javascript - The Good, the Bad and the Ugly
Javascript - The Good, the Bad and the UglyJavascript - The Good, the Bad and the Ugly
Javascript - The Good, the Bad and the Ugly
 
Introduction to ExtJs 5
Introduction to ExtJs 5Introduction to ExtJs 5
Introduction to ExtJs 5
 
conjoon - The Open Source Webmail Client
conjoon - The Open Source Webmail Clientconjoon - The Open Source Webmail Client
conjoon - The Open Source Webmail Client
 
Einfuehrung in ExtJS 4
Einfuehrung in ExtJS 4Einfuehrung in ExtJS 4
Einfuehrung in ExtJS 4
 
Practices and obstacles in agile development
Practices and obstacles in agile developmentPractices and obstacles in agile development
Practices and obstacles in agile development
 
Webcon 2012 Mobile Development mit Sencha Touch
Webcon 2012  Mobile Development mit Sencha TouchWebcon 2012  Mobile Development mit Sencha Touch
Webcon 2012 Mobile Development mit Sencha Touch
 

Recently uploaded

Proudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxProudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxthorishapillay1
 
ACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfSpandanaRallapalli
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxAnupkumar Sharma
 
Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Seán Kennedy
 
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfLike-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfMr Bounab Samir
 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomnelietumpap1
 
4.18.24 Movement Legacies, Reflection, and Review.pptx
4.18.24 Movement Legacies, Reflection, and Review.pptx4.18.24 Movement Legacies, Reflection, and Review.pptx
4.18.24 Movement Legacies, Reflection, and Review.pptxmary850239
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4MiaBumagat1
 
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxBarangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxCarlos105
 
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...JhezDiaz1
 
Choosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for ParentsChoosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for Parentsnavabharathschool99
 
Keynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designKeynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designMIPLM
 
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfVirtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfErwinPantujan2
 
Judging the Relevance and worth of ideas part 2.pptx
Judging the Relevance  and worth of ideas part 2.pptxJudging the Relevance  and worth of ideas part 2.pptx
Judging the Relevance and worth of ideas part 2.pptxSherlyMaeNeri
 
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONTHEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONHumphrey A Beña
 
Karra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxKarra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxAshokKarra1
 

Recently uploaded (20)

Raw materials used in Herbal Cosmetics.pptx
Raw materials used in Herbal Cosmetics.pptxRaw materials used in Herbal Cosmetics.pptx
Raw materials used in Herbal Cosmetics.pptx
 
Proudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptxProudly South Africa powerpoint Thorisha.pptx
Proudly South Africa powerpoint Thorisha.pptx
 
ACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdfACC 2024 Chronicles. Cardiology. Exam.pdf
ACC 2024 Chronicles. Cardiology. Exam.pdf
 
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptxYOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
YOUVE GOT EMAIL_FINALS_EL_DORADO_2024.pptx
 
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
Model Call Girl in Tilak Nagar Delhi reach out to us at 🔝9953056974🔝
 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
 
Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...
 
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfLike-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choom
 
4.18.24 Movement Legacies, Reflection, and Review.pptx
4.18.24 Movement Legacies, Reflection, and Review.pptx4.18.24 Movement Legacies, Reflection, and Review.pptx
4.18.24 Movement Legacies, Reflection, and Review.pptx
 
ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4ANG SEKTOR NG agrikultura.pptx QUARTER 4
ANG SEKTOR NG agrikultura.pptx QUARTER 4
 
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxBarangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
 
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptxFINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
FINALS_OF_LEFT_ON_C'N_EL_DORADO_2024.pptx
 
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...
ENGLISH 7_Q4_LESSON 2_ Employing a Variety of Strategies for Effective Interp...
 
Choosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for ParentsChoosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for Parents
 
Keynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designKeynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-design
 
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdfVirtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
Virtual-Orientation-on-the-Administration-of-NATG12-NATG6-and-ELLNA.pdf
 
Judging the Relevance and worth of ideas part 2.pptx
Judging the Relevance  and worth of ideas part 2.pptxJudging the Relevance  and worth of ideas part 2.pptx
Judging the Relevance and worth of ideas part 2.pptx
 
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATIONTHEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
THEORIES OF ORGANIZATION-PUBLIC ADMINISTRATION
 
Karra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptxKarra SKD Conference Presentation Revised.pptx
Karra SKD Conference Presentation Revised.pptx
 

Zend Framework MVC driven ExtJS

  • 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
  • 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 you're using in your code ● ExtJS ● ZendFramework ● etc.
  • 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. The Basics – Directory Layout src
  • 15. The Basics – Directory Layout src ● Everything you're actually coding
  • 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. 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!“ Don't go berserk! There's 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.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. 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. 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. 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. 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. 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 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. 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 data class Zend_Controller_Action_Helper_ContextSwitch ContextSwitch.php
  • 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. Context based data How does it work?
  • 52. Context based data - detection We can define a context based on (virtually) all data that's available during runtime!
  • 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. 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. 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. 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. 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. 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. 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. 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. 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. Context based data So 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 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. 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() controller's 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 - 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. Context based data - example Request Client invokes request
  • 83. Context based data - example Request Router Zend Framework routes to User_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.
  • 96. Skeptikal Hippo It makes sense when working with Ext 1.* and 2.*, but what about Ext.direct.*?
  • 98. Ext.direct.* „Ext Direct is a platform and language agnostic technology to remote server-side methods to the client-side.“[4]
  • 99. Ext.direct.* ● That new kid in class no one wants to play with
  • 100. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs
  • 101. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs ● Clumsy
  • 102. Ext.direct.* ● That new kid in class no one wants to play with ● Bugs ● Clumsy ● Implementation too complex
  • 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.*
  • 104. 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
  • 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
  • 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 user.reception.getUser(); client.js
  • 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 module user.reception.getUser(); client.js
  • 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 controller user.reception.getUser(); client.js
  • 109. 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
  • 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
  • 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(); client.js
  • 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 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
  • 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 Firebug
  • 116. 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
  • 118. Ext.direct.* ● Can reduce serverload (1 request with n calls to specific actions instead of n calls)
  • 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)
  • 120. 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!
  • 121. Ext.direct.* w/ Zend Framework Unfortunately, not supported out of the box :(
  • 122. Ext.direct.* w/ Zend Framework … so let's find a solution. Let's sum up our goals:
  • 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 ● 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
  • 127. Ext.direct.* w/ Zend Framework What we need to do:
  • 128. 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
  • 129. Ext.direct.* w/ Zend Framework Change Ext.direct.RemotingProvider URLs on the fly
  • 130. 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.
  • 131. 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
  • 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 : [{ 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' }] }, namespace : 'eu.sourcedevcon.provider' }); client.js
  • 134. 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
  • 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' }); client.js eu.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' }] }, namespace : 'eu.sourcedevcon.provider' }); namespace client.js eu.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' }] action }, namespace : 'eu.sourcedevcon.provider' }); client.js eu.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' method }); client.js eu.sourcedevcon.provider.account.getEmailAccounts(); client.js
  • 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 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.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. 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. 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. 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. 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
  • 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. 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
  • 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(); 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. 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
  • 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 {"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. 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
  • 151. 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
  • 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
  • 154. 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
  • 155. Ext.direct.* w/ Zend Framework URL = module action = controller method = action client.js
  • 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. 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. 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. 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. 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. 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
  • 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) { ContextSwitch url += '/format/' + options.transaction.provider.format; } options.url = url; options.disableCaching = true; } }); client.js
  • 163. 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
  • 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
  • 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
  • 166. 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
  • 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
  • 168. 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
  • 169. Ext.direct.* w/ Zend Framework Will do! Let me send a batched request now!
  • 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
  • 171. 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
  • 172. Ext.direct.* w/ Zend Framework ...?
  • 173. 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
  • 174. 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
  • 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 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
  • 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); 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
  • 177. 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
  • 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) { 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 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
  • 180. 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
  • 181. Ext.direct.* w/ Zend Framework ...and now for something completely different.
  • 182. Ext.direct.* w/ Zend Framework Introducing Sourcedevcon_Controller_Plugin_ExtRequest[5]
  • 183. 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
  • 184. Ext.direct.* w/ Zend Framework
  • 185. Ext.direct.* w/ Zend Framework dispatchLoopStartup
  • 186. Ext.direct.* w/ Zend Framework dispatchLoopStartup dispatchLoopShutdown
  • 187. Ext.direct.* w/ Zend Framework pre Dispatch Action Dispatch Controller dispatchLoopStartup post dispatchLoopShutdown Dispatch Response Object
  • 188. 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
  • 189. 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