zend framework mvc driven extjs

Post on 08-May-2015

15.854 Views

Category:

Education

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Zend Framework MVC driven ExtJS

Thorsten Suckow-Homberg, K&K GmbH

Sourc{ - SenchaDev ConferenceMay 5-7, 2011Croatia, 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

„How do I get the resources from vendor into my src folder where – obviously - running code will resist?“

„Do I need to run a build process every time a line of code changed?“

The Basics – Directory Layoutworking copy (development): /var/www/your_project/vendor/ext-ux-util-messagebus/var/www/your_project/src/www/htdocs/index.php

The Basics – Directory Layout

<?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

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

<?php if ($isDeployment) { ?> <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script><?php } else { ?> <script type="text/javascript" src="/vendor/ext-ux-util-messagebus/src/messagebus.js"></script><?php } ?>

index.phtml

# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebus "/htdocs/your_project/vendor/ext-ux-util-messagebus/src"<Directory "/htdocs/your_project/vendor/ext-ux-util-messagebus/src">Order allow,denyAllow from all</Directory>

apache.conf

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

<?php if ($isDeployment) { ?> <script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script><?php } else { ?> <script type="text/javascript" src="/vendor/ext-ux-util-messagebus/src/messagebus.js"></script><?php } ?>

index.phtml

# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebus "/htdocs/your_project/vendor/ext-ux-util-messagebus/src"<Directory "/htdocs/your_project/vendor/ext-ux-util-messagebus/src">Order allow,denyAllow from all</Directory>

apache.conf

<script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script>

index.phtml

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

Virtual# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebusDevelopment:

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

Virtual

Build process

# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebusDevelopment:

...<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:

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

Virtual

Build process

# Alias for Ext.ux.util.MessageBusAlias /js/ext-ux-util-messagebusDevelopment:

...<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:

<script type="text/javascript" src="/js/ext-ux-util-messagebus/src/messagebus.js"></script>

index.phtml

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

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 LayoutPros

● 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

Desktop PC

send/receive

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

Context „default“

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

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

● 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]

ContextSwitch.php

Context based data

How does it work?

Context based data - detectionWe can define a context based on (virtually) all data that's available during runtime!

Context based data - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe 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 - detectionWe can define a context based on (virtually) all data that's available during runtime!

Another example:

User Agent

...$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';

}...

● 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') ->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'; }

}

implement parent's init() methodto add action contexts...

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'; }

}

...which happens here:

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'; }

}

getUserAction() will now...

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'; }

}

… return the response json-formatted ifthe get-Parameter „format“ was set to „json“

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'; }

}

ReceptionController.php

We have just added an action context to this action

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'; }

}

Call business logic...

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'; }

}

And finally: Assign values to thecontroller's view

ReceptionController.php

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; }

}ReceptionController.php

client.js

Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); }});

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; }

}ReceptionController.php

client.js

Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); }});

Module

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; }

}

ReceptionController.php

client.js

Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); }});

Controller

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; }

}

ReceptionController.php

client.js

Ext.Ajax.request({ url : „/user/reception/get.user/format/json“, success : function(response) { console.log(response.responseText); }});

Action

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

Zend Framework routes to User_ReceptionController::getUserAction()

Router

Context based data - example

Request

Any plugins defined? Signal a preDispatch to them!

Router preDispatch

Context based data - example

Request

Any plugins defined? Signal a preDispatch to them!

Router preDispatch

public function preDispatch() { }

Zend_Controller_Action_Helper_Abstract

Context based data - example

Request

Dispatch the action – getUserAction() gets processed!

Router preDispatch

Dispatch

Context based data - example

Request Router preDispatch

Dispatch ActionController

public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = 'peter@birdistheword.com'; } ReceptionController.php

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

Any plugins defined? Signal a postDispatch to them!

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

public function postDispatch() { $context = $this->getCurrentContext(); ... //$this->postJsonContext(); } ContextSwitch.php

Any plugins defined? Signal a postDispatch to them!

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

$response->setHeader('Content-Type', 'application/json');

actionsleft?

Response Object

ContextSwitch.php

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

$response->setHeader('Content-Type', 'application/json');

actionsleft?

Response Object

$response->setBody(Zend_Json::encode($view->getVars()));

ContextSwitch.php

ContextSwitch.php

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

actionsleft?

Response Object

send response

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

actionsleft?

Response Object

{'userName' : „Peter Griffin“, 'userEmail' : „peter@birdistheword.com“}

send response

console

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 codeclass User_ReceptionController extends Zend_Controller_Action {

public function getUserAction() { ... }} ReceptionController.php

Ext.direct.* - advantages● Let's you call remote procedures directly from

client codeclass 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 codeclass User_ReceptionController extends Zend_Controller_Action {

public function getUserAction() { ... }} ReceptionController.php

user.reception.getUser();client.js

module

Ext.direct.* - advantages● Let's you call remote procedures directly from

client codeclass User_ReceptionController extends Zend_Controller_Action {

public function getUserAction() { ... }} ReceptionController.php

user.reception.getUser();client.js

controller

Ext.direct.* - advantages● Let's you call remote procedures directly from

client codeclass User_ReceptionController extends Zend_Controller_Action {

public function getUserAction() { ... }} ReceptionController.php

user.reception.getUser();client.js

action

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.jsPOST http://sourcedevcon/groupware/account/get.email.accountsPOST 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

Firebug

POST http://sourcedevcon/groupware

POST http://sourcedevcon/groupware/account/get.email.accountsPOST 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

Firebug

POST http://sourcedevcon/groupwareextDirectData[{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1},{"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}]

POST http://sourcedevcon/groupware/account/get.email.accountsPOST http://sourcedevcon/groupware/account/get.feed.accounts

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 FrameworkExt.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 FrameworkExt.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

URL

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

URL

„action“

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

URL

„action“

method

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

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

client.js

eu.sourcedevcon.provider.account.getEmailAccounts();

namespace

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

client.js

eu.sourcedevcon.provider.account.getEmailAccounts();

action

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

client.js

eu.sourcedevcon.provider.account.getEmailAccounts();

method

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

Firebug

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

Firebug

extDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

Firebug

extDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

Firebug

extDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

Firebug

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

Firebug

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

http://sourcedevcon/groupware/account/get.email.accounts

Firebug

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

Http://sourcedevcon/groupware/account/get.email.accounts

Firebug

URL = module

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

http://sourcedevcon/groupware/account/get.email.accounts

Firebug

action = controller

URL = module

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

http://sourcedevcon/groupware/account/get.email.accounts

Firebug

action = controller

URL = module

method = action

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

/groupware

if (isset($_POST['extDirectData'])) { ... }

http://sourcedevcon/groupware/account/get.email.accounts

Firebug

action = controller

URL = module

method = action

URL

„action“

method

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

ZendProvider.js

Ext.define('eu.sourcedevcon.direct.ZendProvider', { alias : 'direct.zendprovider', extend : 'Ext.direct.RemotingProvider'

});

Ext.direct.* w/ Zend Framework

client.js

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

ContextSwitch

Ext.direct.* w/ Zend Framework

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;

}});

URL = module action = controller method = action

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();

POST http://sourcedevcon/groupware/account/get.email.accounts/format/json

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

POST http://sourcedevcon/groupware

Ext.direct.* w/ Zend FrameworkPOST http://sourcedevcon/groupware/account/get.email.accounts/format/json

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

Note:● Teach your actions the „extDirectData“-POST parameter

Ext.direct.* w/ Zend FrameworkPOST http://sourcedevcon/groupware/account/get.email.accounts/format/json

FirebugextDirectData{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1}

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 FrameworkExt.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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts();

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

client.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts();

POST http://sourcedevcon/groupware

Firebug

extDirectData[{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1},{"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}]

Ext.direct.* w/ Zend Framework

. . . ?

Ext.direct.* w/ Zend FrameworkqueueTransaction: 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 FrameworkqueueTransaction: 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

add transaction to callBuffer Array

Ext.direct.* w/ Zend FrameworkqueueTransaction: 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

add transaction to callBuffer Array

if batching is enabled, create a task

Ext.direct.* w/ Zend FrameworkqueueTransaction: 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

add transaction to callBuffer Array

if batching is enabled, create a task

wait for 10ms for another transaction to be added

Ext.direct.* w/ Zend FrameworkqueueTransaction: 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

add transaction to callBuffer Array

if batching is enabled, create a task

wait for 10ms for another transaction to be added

no more transactions coming in? Call combineAndSend

Ext.direct.* w/ Zend Framework

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.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts();

Ext.direct.* w/ Zend Framework

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.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts();

false

Ext.direct.* w/ Zend Framework

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; ...

client.jseu.sourcedevcon.provider.account.getEmailAccounts();eu.sourcedevcon.provider.account.getFeedAccounts();

false

POST http://sourcedevcon/groupware

Firebug

extDirectData[{"action":"account","method":"getEmailAccounts","data":null,"type":"rpc","tid":1},{"action":"account","method":"getFeedAccounts","data":null,"type":"rpc","tid":2}]

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

dispatchLoopStartup

dispatchLoopShutdown

preDispatch

Dispatch ActionController

postDispatch

ResponseObject

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', 'additionalHeaders' => array('Content-Type' => 'application/json'), 'additionalParams' => array('format' => 'json'), 'action' => 'multi.request', 'controller' => 'ext', 'module' => 'default'));

$extDirect->registerPlugins();index.php

The POST parameter that holds a batched request

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

Additional headers for the 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

Additional parameters we add to each sandboxed request

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

The default module/controller/action before disassembling

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

Register the plugins at the Front Controller

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

PreDispatcher.php

public function dispatchLoopStartup() { $this->_parent->notifyDispatchLoopStartup();}

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

PreDispatcher.php

public function dispatchLoopStartup() { $this->_parent->notifyDispatchLoopStartup();}

PostDispatcher.php

public function dispatchLoopShutdown() { $this->_parent->notifyDispatchLoopShutdown();}

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

PreDispatcher.php

public function dispatchLoopStartup() { $this->_parent->notifyDispatchLoopStartup();}

PostDispatcher.php

public function dispatchLoopShutdown() { $this->_parent->notifyDispatchLoopShutdown();}

preDispatch postDispatchdispatch

Request_Http Response_Http

Thank you

Thank you!

... questions?

Resources[1]

http://en.wikipedia.org/wiki/Continuous_integration

[2] http://svnbook.red-bean.com/en/1.5/svn.advanced.vendorbr.html

[3] http://zendframework.com/manual/en/zend.controller.actionhelpers.html

[4] http://www.sencha.com/products/extjs/extdirect

[5] http://thorsten.suckow-homberg.de/sourcedevcon

[6] http://framework.zend.com/manual/en/zend.controller.basics.html

top related