3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
18 * ServerProxy is a superclass of {@link Ext.data.proxy.JsonP JsonPProxy} and {@link Ext.data.proxy.Ajax AjaxProxy}, and
19 * would not usually be used directly.
21 * ServerProxy should ideally be named HttpProxy as it is a superclass for all HTTP proxies - for Ext JS 4.x it has been
22 * called ServerProxy to enable any 3.x applications that reference the HttpProxy to continue to work (HttpProxy is now
23 * an alias of AjaxProxy).
26 Ext.define('Ext.data.proxy.Server', {
27 extend: 'Ext.data.proxy.Proxy',
28 alias : 'proxy.server',
29 alternateClassName: 'Ext.data.ServerProxy',
30 uses : ['Ext.data.Request'],
34 * The URL from which to request the data object.
38 * @cfg {String} pageParam
39 * The name of the 'page' parameter to send in a request. Defaults to 'page'. Set this to undefined if you don't
40 * want to send a page parameter.
45 * @cfg {String} startParam
46 * The name of the 'start' parameter to send in a request. Defaults to 'start'. Set this to undefined if you don't
47 * want to send a start parameter.
52 * @cfg {String} limitParam
53 * The name of the 'limit' parameter to send in a request. Defaults to 'limit'. Set this to undefined if you don't
54 * want to send a limit parameter.
59 * @cfg {String} groupParam
60 * The name of the 'group' parameter to send in a request. Defaults to 'group'. Set this to undefined if you don't
61 * want to send a group parameter.
66 * @cfg {String} sortParam
67 * The name of the 'sort' parameter to send in a request. Defaults to 'sort'. Set this to undefined if you don't
68 * want to send a sort parameter.
73 * @cfg {String} filterParam
74 * The name of the 'filter' parameter to send in a request. Defaults to 'filter'. Set this to undefined if you don't
75 * want to send a filter parameter.
77 filterParam: 'filter',
80 * @cfg {String} directionParam
81 * The name of the direction parameter to send in a request. **This is only used when simpleSortMode is set to
82 * true.** Defaults to 'dir'.
84 directionParam: 'dir',
87 * @cfg {Boolean} simpleSortMode
88 * Enabling simpleSortMode in conjunction with remoteSort will only send one sort property and a direction when a
89 * remote sort is requested. The directionParam and sortParam will be sent with the property name and either 'ASC'
92 simpleSortMode: false,
95 * @cfg {Boolean} noCache
96 * Disable caching by adding a unique parameter name to the request. Set to false to allow caching. Defaults to true.
101 * @cfg {String} cacheString
102 * The name of the cache param added to the url when using noCache. Defaults to "_dc".
107 * @cfg {Number} timeout
108 * The number of milliseconds to wait for a response. Defaults to 30000 milliseconds (30 seconds).
114 * Specific urls to call on CRUD action methods "create", "read", "update" and "destroy". Defaults to:
117 * create : undefined,
119 * update : undefined,
120 * destroy : undefined
123 * The url is built based upon the action being executed [create|read|update|destroy] using the commensurate
124 * {@link #api} property, or if undefined default to the configured
125 * {@link Ext.data.Store}.{@link Ext.data.proxy.Server#url url}.
130 * create : '/controller/new',
131 * read : '/controller/load',
132 * update : '/controller/update',
133 * destroy : '/controller/destroy_action'
136 * If the specific URL for a given CRUD action is undefined, the CRUD action request will be directed to the
137 * configured {@link Ext.data.proxy.Server#url url}.
140 constructor: function(config) {
143 config = config || {};
147 * Fires when the server returns an exception
148 * @param {Ext.data.proxy.Proxy} this
149 * @param {Object} response The response from the AJAX request
150 * @param {Ext.data.Operation} operation The operation that triggered request
154 me.callParent([config]);
157 * @cfg {Object} extraParams
158 * Extra parameters that will be included on every request. Individual requests with params of the same name
159 * will override these params when they are in conflict.
161 me.extraParams = config.extraParams || {};
163 me.api = config.api || {};
165 //backwards compatibility, will be deprecated in 5.0
166 me.nocache = me.noCache;
169 //in a ServerProxy all four CRUD operations are executed in the same manner, so we delegate to doRequest in each case
171 return this.doRequest.apply(this, arguments);
175 return this.doRequest.apply(this, arguments);
179 return this.doRequest.apply(this, arguments);
182 destroy: function() {
183 return this.doRequest.apply(this, arguments);
187 * Creates and returns an Ext.data.Request object based on the options passed by the {@link Ext.data.Store Store}
188 * that this Proxy is attached to.
189 * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
190 * @return {Ext.data.Request} The request object
192 buildRequest: function(operation) {
193 var params = Ext.applyIf(operation.params || {}, this.extraParams || {}),
196 //copy any sorters, filters etc into the params so they can be sent over the wire
197 params = Ext.applyIf(params, this.getParams(operation));
199 if (operation.id && !params.id) {
200 params.id = operation.id;
203 request = Ext.create('Ext.data.Request', {
205 action : operation.action,
206 records : operation.records,
207 operation: operation,
211 request.url = this.buildUrl(request);
214 * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the
215 * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing
217 operation.request = request;
222 // Should this be documented as protected method?
223 processResponse: function(success, operation, request, response, callback, scope){
228 if (success === true) {
229 reader = me.getReader();
230 result = reader.read(me.extractResponseData(response));
232 if (result.success !== false) {
233 //see comment in buildRequest for why we include the response object here
234 Ext.apply(operation, {
239 operation.commitRecords(result.records);
240 operation.setCompleted();
241 operation.setSuccessful();
243 operation.setException(result.message);
244 me.fireEvent('exception', this, response, operation);
247 me.setException(operation, response);
248 me.fireEvent('exception', this, response, operation);
251 //this callback is the one that was passed to the 'read' or 'write' function above
252 if (typeof callback == 'function') {
253 callback.call(scope || me, operation);
256 me.afterRequest(request, success);
260 * Sets up an exception on the operation
262 * @param {Ext.data.Operation} operation The operation
263 * @param {Object} response The response
265 setException: function(operation, response){
266 operation.setException({
267 status: response.status,
268 statusText: response.statusText
273 * Template method to allow subclasses to specify how to get the response for the reader.
276 * @param {Object} response The server response
277 * @return {Object} The response data to be used by the reader
279 extractResponseData: function(response){
284 * Encode any values being sent to the server. Can be overridden in subclasses.
286 * @param {Array} An array of sorters/filters.
287 * @return {Object} The encoded value
289 applyEncoding: function(value){
290 return Ext.encode(value);
294 * Encodes the array of {@link Ext.util.Sorter} objects into a string to be sent in the request url. By default,
295 * this simply JSON-encodes the sorter data
296 * @param {Ext.util.Sorter[]} sorters The array of {@link Ext.util.Sorter Sorter} objects
297 * @return {String} The encoded sorters
299 encodeSorters: function(sorters) {
301 length = sorters.length,
304 for (; i < length; i++) {
306 property : sorters[i].property,
307 direction: sorters[i].direction
310 return this.applyEncoding(min);
315 * Encodes the array of {@link Ext.util.Filter} objects into a string to be sent in the request url. By default,
316 * this simply JSON-encodes the filter data
317 * @param {Ext.util.Filter[]} filters The array of {@link Ext.util.Filter Filter} objects
318 * @return {String} The encoded filters
320 encodeFilters: function(filters) {
322 length = filters.length,
325 for (; i < length; i++) {
327 property: filters[i].property,
328 value : filters[i].value
331 return this.applyEncoding(min);
336 * Copy any sorters, filters etc into the params so they can be sent over the wire
338 getParams: function(operation) {
341 isDef = Ext.isDefined,
342 groupers = operation.groupers,
343 sorters = operation.sorters,
344 filters = operation.filters,
345 page = operation.page,
346 start = operation.start,
347 limit = operation.limit,
349 simpleSortMode = me.simpleSortMode,
351 pageParam = me.pageParam,
352 startParam = me.startParam,
353 limitParam = me.limitParam,
354 groupParam = me.groupParam,
355 sortParam = me.sortParam,
356 filterParam = me.filterParam,
357 directionParam = me.directionParam;
359 if (pageParam && isDef(page)) {
360 params[pageParam] = page;
363 if (startParam && isDef(start)) {
364 params[startParam] = start;
367 if (limitParam && isDef(limit)) {
368 params[limitParam] = limit;
371 if (groupParam && groupers && groupers.length > 0) {
372 // Grouper is a subclass of sorter, so we can just use the sorter method
373 params[groupParam] = me.encodeSorters(groupers);
376 if (sortParam && sorters && sorters.length > 0) {
377 if (simpleSortMode) {
378 params[sortParam] = sorters[0].property;
379 params[directionParam] = sorters[0].direction;
381 params[sortParam] = me.encodeSorters(sorters);
386 if (filterParam && filters && filters.length > 0) {
387 params[filterParam] = me.encodeFilters(filters);
394 * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will add the
395 * cache-buster param to the end of the url. Subclasses may need to perform additional modifications to the url.
396 * @param {Ext.data.Request} request The request object
397 * @return {String} The url
399 buildUrl: function(request) {
401 url = me.getUrl(request);
405 Ext.Error.raise("You are using a ServerProxy but have not supplied it with a url.");
410 url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.cacheString, Ext.Date.now()));
417 * Get the url for the request taking into account the order of priority,
422 * @param {Ext.data.Request} request The request
423 * @return {String} The url
425 getUrl: function(request){
426 return request.url || this.api[request.action] || this.url;
430 * In ServerProxy subclasses, the {@link #create}, {@link #read}, {@link #update} and {@link #destroy} methods all
431 * pass through to doRequest. Each ServerProxy subclass must implement the doRequest method - see {@link
432 * Ext.data.proxy.JsonP} and {@link Ext.data.proxy.Ajax} for examples. This method carries the same signature as
433 * each of the methods that delegate to it.
435 * @param {Ext.data.Operation} operation The Ext.data.Operation object
436 * @param {Function} callback The callback function to call when the Operation has completed
437 * @param {Object} scope The scope in which to execute the callback
439 doRequest: function(operation, callback, scope) {
441 Ext.Error.raise("The doRequest function has not been implemented on your Ext.data.proxy.Server subclass. See src/data/ServerProxy.js for details");
446 * Optional callback function which can be used to clean up after a request has been completed.
447 * @param {Ext.data.Request} request The Request object
448 * @param {Boolean} success True if the request was successful
451 afterRequest: Ext.emptyFn,
453 onDestroy: function() {
454 Ext.destroy(this.reader, this.writer);