PDA

View Full Version : [3.0 RC1.1] DirectStore.api.save request params Question



curvatique
25 May 2009, 12:42 PM
Hello All,

I seem to have some trouble understanding the way DirectStore.Api.save maps its request data. Looking at firefox when some record in the store gets saved the request takes on the following format (json):



{
"action":"employee",
"method":"update",
"data":[
"115",
{"name":"Employee 121sss","id":"115"}],"type":"rpc",
"tid":3
}
Is the data property intentionally an array with both scalars ánd objects? Why does it put the ID separate from the rest of the data (even with API methods that have a len of 1) - in other words, why supply two sets of parameters to the server when there's only one parameter that is expected by the server?

Then if this is intentionally then how to expect the router (and/or the client) to know to go to the second set of data to get all of the neccesary parameters

the following code will reproduce the scenario:


Ext.onReady(function(){

Ext.Direct.addProvider(Ext.app.EXT_API);

//reader
var reader = new Ext.data.JsonReader({
totalProperty: 'total',
successProperty: 'success',
idProperty: 'id',
root: 'data'
}, [
{ name: 'id', type: 'int'},
{ name: 'name',type: 'string'},
{ name: 'email', type: 'string' },
{ name: 'salary', type: 'float'},
{ name: 'active', type: 'boolean'},
{ name: 'created_at', type: 'date', dateFormat: 'Y-m-d H:i:s'}
]);

//writer
var writer = new Ext.data.JsonWriter({
returnJson: false,
writeAllFields: false
})

//Direct Store
var store = new Ext.data.DirectStore({
storeId:'employee-store',
api: {
load: employee.load,
save: employee.update
},
sortInfo: {
field: 'created_at',
direction: 'DESC'
},
remoteSort: true,
paramsAsHash: true,
autoLoad : true,
reader: reader,
writer: writer
});

//grid
var grid = new Ext.grid.EditorGridPanel({
store: store,
width: 600,
region:'center',
margins: '0 5 5 5',
autoExpandColumn: 'name',
loadMask: true,
columns: [{
id: 'name',
header: 'name',
dataIndex: 'name',
width: 220,
sortable: true,
editor: {
xtype: 'textfield',
allowBlank: false
}
},{
header: 'Email',
dataIndex: 'email',
width: 150,
sortable: true,
editor: {
xtype: 'textfield',
allowBlank: false,
vtype: 'email'
}
},{
xtype: 'datecolumn',
header: 'Start Date',
dataIndex: 'created_at',
format: 'm/d/Y',
width: 100,
sortable: true,
groupRenderer: Ext.util.Format.dateRenderer('M y'),
editor: {
xtype: 'datefield',
allowBlank: false,
minValue: '01/01/2006',
minText: 'Can\'t have a start date before the company existed!',
maxValue: (new Date()).format('m/d/Y')
}
},{
xtype: 'numbercolumn',
header: 'Salary',
dataIndex: 'salary',
format: '$0,0.00',
width: 100,
sortable: true,
editor: {
xtype: 'numberfield',
allowBlank: false,
minValue: 1,
maxValue: 150000
}
},{
xtype: 'booleancolumn',
header: 'Active',
dataIndex: 'active',
align: 'center',
width: 50,
trueText: 'Yes',
falseText: 'No',
editor: {
xtype: 'checkbox'
}
}],
bbar: new Ext.PagingToolbar({
pageSize: 25,
store: store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
})
});

//Layout
var layout = new Ext.Panel({
title: 'Employees',
layout: 'border',
layoutConfig: {
columns: 1
},
width:600,
height: 600,
items: [grid]
});
layout.render(Ext.getBody());

});

Kind Regards

Ad

christocracy
28 May 2009, 5:57 AM
Hi, yes this one has been on the back of my mind. I'll ponder it a bit.

curvatique
28 May 2009, 8:06 AM
Great, im looking forward to your insight. Trying to get the ext.direct specifications and philosophy crystal clear.

mjlecomte
28 May 2009, 12:57 PM
FWIW I thought I read in the specifications something about the intent to go from array to object in the future?!

ficeto
2 Jun 2009, 4:48 PM
I also tried the same grid and a different result:

{"action":"MySQL","method":"DirectGrid","data":["1754"],"type":"rpc","tid":4}and this was while using ext-all.js.
i did some changes to Ext.data.DirectProxy.doRequest(), so i can really use all api options and even better, have a single directFn to deal with my stuff. so what i came up with is:

doRequest : function(action, rs, params, reader, callback, scope, options) {
var args = [];
var directFn = this.api[action] || this.directFn;

switch (action) {
case Ext.data.Api.CREATE:
Ext.apply(params,{data:rs.data});
args.push(params);
break;
case Ext.data.Api.READ:
args.push(params);
break;
case Ext.data.Api.UPDATE:
Ext.apply(params,{data:rs.data});
args.push(params);
break;
case Ext.data.Api.DESTROY:
Ext.apply(params,{data:rs.data});
args.push(params);
break;
}
args.push(this.createCallback(action, reader, callback, scope, options));
directFn.apply(window, args);
}that way the request looks like:

{"action":"MySQL","method":"DirectGrid","data":[{"id":"1754","data":{"id":1754,"event":"PAUSEALLtwetw"
,"agent":"Agent/200","time":"2009-01-09T15:32:16","data":""},"xaction":"save","table":"queue_log"}],"type":"rpc","tid":4}which actually gives me all the data i might need.
sad part is that i have to use ext-all-debug or i have to write a new class and include it every time i need to Ext.Direct a store :(

christocracy
2 Jun 2009, 4:55 PM
The API of RC2 has some big changes from the version you're using. DirectProxy#doRequest now goes like this:



doRequest : function(action, rs, params, reader, callback, scope, options) {
var args = [];
var directFn = this.api[action] || this.directFn;

switch (action) {
case Ext.data.Api.actions.create:
args.push(params[reader.meta.root]); // <-- create(Hash)
break;
case Ext.data.Api.actions.read:
if(this.paramOrder){
for(var i = 0, len = this.paramOrder.length; i < len; i++){
args.push(params[this.paramOrder[i]]);
}
}else if(this.paramsAsHash){
args.push(params);
}
break;
case Ext.data.Api.actions.update:
args.push(params[reader.meta.idProperty]); // <-- save(Integer/Integer[], Hash/Hash[])
args.push(params[reader.meta.root]);
break;
case Ext.data.Api.actions.destroy:
args.push(params[reader.meta.root]); // <-- destroy(Int/Int[])
break;
}

var trans = {
params : params || {},
callback : callback,
scope : scope,
arg : options,
reader: reader
};

args.push(this.createCallback(action, rs, trans), this);
directFn.apply(window, args);
},

ficeto
3 Jun 2009, 4:04 AM
OK!
lots of changes here.....
first, api method names are changed from:


api:{
load: myDirectFn,
create: myDirectFn,
save: myDirectFn,
destroy: E myDirectFn
}

to:


api:{
read: myDirectFn,
create: myDirectFn,
update: myDirectFn,
destroy: E myDirectFn
}



Also there is another thing: why would you create the possibility to use directFn if the number of arguments change and no type of action parameter is sent?

what i mean is:
read sends only parameter to directFn (or api.read) that is the params of the store (limit,order, baseParams, etc).
create sends also only parameter which is the data created.
update on other side sends two parameters which are the ID of the record updated and the data that was changed.
and last but not least, destroy sends one parameter - ID of record deleted.
using the Ext.Direct provider (i use the php backend), when defining a server side call to a method, we define the number of arguments it accepts, so it throws an exception when i try to send less arguments that it needs (if I define them as 2).

so just to elaborate:
directFn works if you don't intend to create,update or destroy any data (meaning you will only read data from the server), otherwise we need to use the api configuration object and expose 4 server side methods to manage the requests (sending xaction would have helped a bit) :(
And, I still kinda like my approach ( which i need to revise a bit ). It works with directFn or api, and always passes one parameter to the directFn.