zend framework mvc driven extjs

198
Zend Framework MVC driven ExtJS Thorsten Suckow-Homberg, K&K GmbH Sourc{ - SenchaDev Conference May 5-7, 2011 Croatia, Split

Upload: thorsten-suckow-homberg

Post on 08-May-2015

15.854 views

Category:

Education


5 download

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

Page 1: Zend Framework MVC driven ExtJS

Zend Framework MVC driven ExtJS

Thorsten Suckow-Homberg, K&K GmbH

Sourc{ - SenchaDev ConferenceMay 5-7, 2011Croatia, Split

Page 2: Zend Framework MVC driven ExtJS

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

Page 3: Zend Framework MVC driven ExtJS

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)

Page 4: Zend Framework MVC driven ExtJS

This talk will show you...

● … how you should plan your directory layout in larger projects

Page 5: Zend Framework MVC driven ExtJS

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

Page 6: Zend Framework MVC driven ExtJS

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

Page 7: Zend Framework MVC driven ExtJS

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

Page 8: Zend Framework MVC driven ExtJS

The Basics

Directory Layout

Page 9: Zend Framework MVC driven ExtJS

The Basics – Directory Layout● Top level should be a

directory named after your project (obviously)

● ...containing three child directories:

Page 10: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

build-tools● Real tools, like:

● yuicompressor● phing● ant

Page 11: Zend Framework MVC driven ExtJS

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

Page 12: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

vendor● All the third party libs

you're using in your code● ExtJS ● ZendFramework● etc.

Page 13: Zend Framework MVC driven ExtJS

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

Page 14: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

src

Page 15: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

src● Everything you're actually

coding

Page 16: Zend Framework MVC driven ExtJS

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

Page 17: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

corelib

Page 18: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

corelib● js – your client libraries

(ExtJS, own implementations)

Page 19: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

corelib● js – your client libraries

(ExtJS, own implementations)

● php – your backend code (including tests)

Page 20: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

datastore● data storage

definition/structure goes here

Page 21: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

datastore● data storage

definition/structure goes here

Note:● build scripts can refer to the structure file when deploying

an application

Page 22: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

www● one step more towards

a „callable“ application

Page 23: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

application

Page 24: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

application● ZF specific „frontend“

code (controllers, templates)

Page 25: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

application● ZF specific „frontend“

code (controllers, templates)

● and:– Meta-Information

files for your application

– caching directories– etc.

Page 26: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

htdocs

Page 27: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

htdocs● Finally! The document

root for your application● the only „public“ folder

Page 28: Zend Framework MVC driven ExtJS

The Basics – Directory Layout

htdocs● Finally! The document

root for your application● the only „public“ folder

Note:● Build-process focuses on this folder

Page 29: Zend Framework MVC driven ExtJS

The Basics – Directory Layout„This layout gets way too complex!“

Don't go berserk!

There's a solution to all of it!

Page 30: Zend Framework MVC driven ExtJS

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

Page 31: Zend Framework MVC driven ExtJS

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

Page 32: Zend Framework MVC driven ExtJS

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

Page 33: Zend Framework MVC driven ExtJS

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

Page 34: Zend Framework MVC driven ExtJS

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

Page 35: Zend Framework MVC driven ExtJS

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

Page 36: Zend Framework MVC driven ExtJS

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

Page 37: Zend Framework MVC driven ExtJS

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

Page 38: Zend Framework MVC driven ExtJS

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“

Page 39: Zend Framework MVC driven ExtJS

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

Page 40: Zend Framework MVC driven ExtJS

Context based data

What is a „context“?

Page 41: Zend Framework MVC driven ExtJS

Context based data

Application Server

Page 42: Zend Framework MVC driven ExtJS

Context based data

Application Server

Desktop PC

send/receive

Page 43: Zend Framework MVC driven ExtJS

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

Page 44: Zend Framework MVC driven ExtJS

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

Context „default“

Page 45: Zend Framework MVC driven ExtJS

Context based data

Application Server

Desktop PC Mobile

send/receivesend/receive

Context „default“ Context „mobile“

Page 46: Zend Framework MVC driven ExtJS

Context based data

Why do we need it?

Page 47: Zend Framework MVC driven ExtJS

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

Page 48: Zend Framework MVC driven ExtJS

Context based data

What do we need?

Page 49: Zend Framework MVC driven ExtJS

Context based data

class Zend_Controller_Action_Helper_ContextSwitch

ContextSwitch.php

Page 50: Zend Framework MVC driven ExtJS

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

Page 51: Zend Framework MVC driven ExtJS

Context based data

How does it work?

Page 52: Zend Framework MVC driven ExtJS

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

Page 53: Zend Framework MVC driven ExtJS

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

Page 54: Zend Framework MVC driven ExtJS

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

Page 55: Zend Framework MVC driven ExtJS

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

Page 56: Zend Framework MVC driven ExtJS

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

Page 57: Zend Framework MVC driven ExtJS

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

Page 58: Zend Framework MVC driven ExtJS

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'

Page 59: Zend Framework MVC driven ExtJS

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!

Page 60: Zend Framework MVC driven ExtJS

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

Page 61: Zend Framework MVC driven ExtJS

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

Page 62: Zend Framework MVC driven ExtJS

Context based data

So what can it do for me?

Page 63: Zend Framework MVC driven ExtJS

Context based data● Detect devices/users (webbrowser, mobile, bots)

Page 64: Zend Framework MVC driven ExtJS

Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run

anywhere“

Page 65: Zend Framework MVC driven ExtJS

Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run

anywhere“

Page 66: Zend Framework MVC driven ExtJS

Context based data● Detect devices/users (webbrowser, mobile, bots)● One codebase for all devices: „Write once, run

anywhere“

Page 67: Zend Framework MVC driven ExtJS

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!

Page 68: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

ReceptionController.php

Page 69: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

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

ReceptionController.php

Page 70: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

...which happens here:

ReceptionController.php

Page 71: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

getUserAction() will now...

ReceptionController.php

Page 72: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

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

ReceptionController.php

Page 73: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}We have just added an action

context to this action

ReceptionController.php

Page 74: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

ReceptionController.php

We have just added an action context to this action

Page 75: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

Call business logic...

ReceptionController.php

Page 76: Zend Framework MVC driven ExtJS

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 = '[email protected]'; }

}

And finally: Assign values to thecontroller's view

ReceptionController.php

Page 77: Zend Framework MVC driven ExtJS

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = '[email protected]'; }

}ReceptionController.php

client.js

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

Page 78: Zend Framework MVC driven ExtJS

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = '[email protected]'; }

}ReceptionController.php

client.js

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

Module

Page 79: Zend Framework MVC driven ExtJS

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = '[email protected]'; }

}

ReceptionController.php

client.js

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

Controller

Page 80: Zend Framework MVC driven ExtJS

Context based data - exampleclass User_ReceptionController extends Zend_Controller_Action() { ... public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = '[email protected]'; }

}

ReceptionController.php

client.js

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

Action

Page 81: Zend Framework MVC driven ExtJS

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

Page 82: Zend Framework MVC driven ExtJS

Context based data - example

Request

Client invokes request

Page 83: Zend Framework MVC driven ExtJS

Context based data - example

Request

Zend Framework routes to User_ReceptionController::getUserAction()

Router

Page 84: Zend Framework MVC driven ExtJS

Context based data - example

Request

Any plugins defined? Signal a preDispatch to them!

Router preDispatch

Page 85: Zend Framework MVC driven ExtJS

Context based data - example

Request

Any plugins defined? Signal a preDispatch to them!

Router preDispatch

public function preDispatch() { }

Zend_Controller_Action_Helper_Abstract

Page 86: Zend Framework MVC driven ExtJS

Context based data - example

Request

Dispatch the action – getUserAction() gets processed!

Router preDispatch

Dispatch

Page 87: Zend Framework MVC driven ExtJS

Context based data - example

Request Router preDispatch

Dispatch ActionController

public function getUserAction() { ... $this->view->userName = 'Peter Griffin'; $this->view->userEmail = '[email protected]'; } ReceptionController.php

Page 88: Zend Framework MVC driven ExtJS

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

Any plugins defined? Signal a postDispatch to them!

Page 89: Zend Framework MVC driven ExtJS

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!

Page 90: Zend Framework MVC driven ExtJS

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

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

actionsleft?

Response Object

ContextSwitch.php

Page 91: Zend Framework MVC driven ExtJS

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

Page 92: Zend Framework MVC driven ExtJS

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

actionsleft?

Response Object

send response

Page 93: Zend Framework MVC driven ExtJS

Context based data - example

Request Router preDispatch

Dispatch ActionController

postDispatch

actionsleft?

Response Object

{'userName' : „Peter Griffin“, 'userEmail' : „[email protected]“}

send response

console

Page 94: Zend Framework MVC driven ExtJS

Context based data

AWESOME!

This makes coding a real blast!

Page 95: Zend Framework MVC driven ExtJS
Page 96: Zend Framework MVC driven ExtJS

Skeptikal Hippo

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

Page 97: Zend Framework MVC driven ExtJS

Ext.direct.*

What is Ext.direct.*?

Page 98: Zend Framework MVC driven ExtJS

Ext.direct.*

„Ext Direct is a platform and language agnostic technology to remote server-side methods to the

client-side.“[4]

Page 99: Zend Framework MVC driven ExtJS

Ext.direct.*● That new kid in class no one wants to play with

Page 100: Zend Framework MVC driven ExtJS

Ext.direct.*● That new kid in class no one wants to play with

● Bugs

Page 101: Zend Framework MVC driven ExtJS

Ext.direct.*● That new kid in class no one wants to play with

● Bugs● Clumsy

Page 102: Zend Framework MVC driven ExtJS

Ext.direct.*● That new kid in class no one wants to play with

● Bugs● Clumsy● Implementation too complex

Page 103: Zend Framework MVC driven ExtJS

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

Page 104: Zend Framework MVC driven ExtJS

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

Page 105: Zend Framework MVC driven ExtJS

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

client codeclass User_ReceptionController extends Zend_Controller_Action {

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

Page 106: Zend Framework MVC driven ExtJS

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

Page 107: Zend Framework MVC driven ExtJS

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

Page 108: Zend Framework MVC driven ExtJS

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

Page 109: Zend Framework MVC driven ExtJS

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

Page 110: Zend Framework MVC driven ExtJS

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

Page 111: Zend Framework MVC driven ExtJS

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

Page 112: Zend Framework MVC driven ExtJS

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

Page 113: Zend Framework MVC driven ExtJS

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

Page 114: Zend Framework MVC driven ExtJS

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

Page 115: Zend Framework MVC driven ExtJS

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

Page 116: Zend Framework MVC driven ExtJS

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

Page 117: Zend Framework MVC driven ExtJS

Ext.direct.*

Batched request – what gives?

Page 118: Zend Framework MVC driven ExtJS

Ext.direct.*● Can reduce serverload (1 request with n calls to

specific actions instead of n calls)

Page 119: Zend Framework MVC driven ExtJS

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)

Page 120: Zend Framework MVC driven ExtJS

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!

Page 121: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

Unfortunately, not supported out of the box :(

Page 122: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

… so let's find a solution.Let's sum up our goals:

Page 123: Zend Framework MVC driven ExtJS

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

Page 124: Zend Framework MVC driven ExtJS

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

Page 125: Zend Framework MVC driven ExtJS

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

Page 126: Zend Framework MVC driven ExtJS

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

Page 127: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

What we need to do:

Page 128: Zend Framework MVC driven ExtJS

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

Page 129: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

Change Ext.direct.RemotingProvider URLs on the fly

Page 130: Zend Framework MVC driven ExtJS

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.

Page 131: Zend Framework MVC driven ExtJS

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

Page 132: Zend Framework MVC driven ExtJS

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

Page 133: Zend Framework MVC driven ExtJS

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“

Page 134: Zend Framework MVC driven ExtJS

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

Page 135: Zend Framework MVC driven ExtJS

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();

Page 136: Zend Framework MVC driven ExtJS

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

Page 137: Zend Framework MVC driven ExtJS

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

Page 138: Zend Framework MVC driven ExtJS

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

Page 139: Zend Framework MVC driven ExtJS

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

Page 140: Zend Framework MVC driven ExtJS

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}

Page 141: Zend Framework MVC driven ExtJS

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}

Page 142: Zend Framework MVC driven ExtJS

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}

Page 143: Zend Framework MVC driven ExtJS

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}

Page 144: Zend Framework MVC driven ExtJS

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}

Page 145: Zend Framework MVC driven ExtJS

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

Page 146: Zend Framework MVC driven ExtJS

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

Page 147: Zend Framework MVC driven ExtJS

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

Page 148: Zend Framework MVC driven ExtJS

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

Page 149: Zend Framework MVC driven ExtJS

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

Page 150: Zend Framework MVC driven ExtJS

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

Page 151: Zend Framework MVC driven ExtJS

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

Page 152: Zend Framework MVC driven ExtJS

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

Page 153: Zend Framework MVC driven ExtJS

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

Page 154: Zend Framework MVC driven ExtJS

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'

});

Page 155: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

client.js

URL = module action = controller method = action

Page 156: Zend Framework MVC driven ExtJS

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

Page 157: Zend Framework MVC driven ExtJS

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

Page 158: Zend Framework MVC driven ExtJS

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

Page 159: Zend Framework MVC driven ExtJS

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

Page 160: Zend Framework MVC driven ExtJS

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

Page 161: Zend Framework MVC driven ExtJS

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

Page 162: Zend Framework MVC driven ExtJS

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

Page 163: Zend Framework MVC driven ExtJS

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

Page 164: Zend Framework MVC driven ExtJS

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();

Page 165: Zend Framework MVC driven ExtJS

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

Page 166: Zend Framework MVC driven ExtJS

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

Page 167: Zend Framework MVC driven ExtJS

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

Page 168: Zend Framework MVC driven ExtJS

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

Page 169: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

Will do! Let me send a batched request now!

Page 170: Zend Framework MVC driven ExtJS

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();

Page 171: Zend Framework MVC driven ExtJS

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

Page 172: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

. . . ?

Page 173: Zend Framework MVC driven ExtJS

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

Page 174: Zend Framework MVC driven ExtJS

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

Page 175: Zend Framework MVC driven ExtJS

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

Page 176: Zend Framework MVC driven ExtJS

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

Page 177: Zend Framework MVC driven ExtJS

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

Page 178: Zend Framework MVC driven ExtJS

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();

Page 179: Zend Framework MVC driven ExtJS

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

Page 180: Zend Framework MVC driven ExtJS

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

Page 181: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

...and now for something completely different.

Page 182: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

Introducing

Sourcedevcon_Controller_Plugin_ExtRequest[5]

Page 183: Zend Framework MVC driven ExtJS

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

Page 184: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

Page 185: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

dispatchLoopStartup

Page 186: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

dispatchLoopStartup

dispatchLoopShutdown

Page 187: Zend Framework MVC driven ExtJS

Ext.direct.* w/ Zend Framework

dispatchLoopStartup

dispatchLoopShutdown

preDispatch

Dispatch ActionController

postDispatch

ResponseObject

Page 188: Zend Framework MVC driven ExtJS

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

Page 189: Zend Framework MVC driven ExtJS

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

Page 190: Zend Framework MVC driven ExtJS

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

Page 191: Zend Framework MVC driven ExtJS

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

Page 192: Zend Framework MVC driven ExtJS

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

Page 193: Zend Framework MVC driven ExtJS

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

Page 194: Zend Framework MVC driven ExtJS

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();}

Page 195: Zend Framework MVC driven ExtJS

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();}

Page 196: Zend Framework MVC driven ExtJS

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

Page 197: Zend Framework MVC driven ExtJS

Thank you

Thank you!

... questions?

Page 198: Zend Framework MVC driven ExtJS

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