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.
17 * @class Ext.data.proxy.Server
18 * @extends Ext.data.proxy.Proxy
20 * <p>ServerProxy is a superclass of {@link Ext.data.proxy.JsonP JsonPProxy} and {@link Ext.data.proxy.Ajax AjaxProxy},
21 * and would not usually be used directly.</p>
23 * <p>ServerProxy should ideally be named HttpProxy as it is a superclass for all HTTP proxies - for Ext JS 4.x it has been
24 * called ServerProxy to enable any 3.x applications that reference the HttpProxy to continue to work (HttpProxy is now an
25 * alias of AjaxProxy).</p>
27 Ext.define('Ext.data.proxy.Server', {
28 extend: 'Ext.data.proxy.Proxy',
29 alias : 'proxy.server',
30 alternateClassName: 'Ext.data.ServerProxy',
31 uses : ['Ext.data.Request'],
34 * @cfg {String} url The URL from which to request the data object.
38 * @cfg {Object/String/Ext.data.reader.Reader} reader The Ext.data.reader.Reader to use to decode the server's response. This can
39 * either be a Reader instance, a config object or just a valid Reader type name (e.g. 'json', 'xml').
43 * @cfg {Object/String/Ext.data.writer.Writer} writer The Ext.data.writer.Writer to use to encode any request sent to the server.
44 * This can either be a Writer instance, a config object or just a valid Writer type name (e.g. 'json', 'xml').
48 * @cfg {String} pageParam The name of the 'page' parameter to send in a request. Defaults to 'page'. Set this to
49 * undefined if you don't want to send a page parameter
54 * @cfg {String} startParam The name of the 'start' parameter to send in a request. Defaults to 'start'. Set this
55 * to undefined if you don't want to send a start parameter
60 * @cfg {String} limitParam The name of the 'limit' parameter to send in a request. Defaults to 'limit'. Set this
61 * to undefined if you don't want to send a limit parameter
66 * @cfg {String} groupParam The name of the 'group' parameter to send in a request. Defaults to 'group'. Set this
67 * to undefined if you don't want to send a group parameter
72 * @cfg {String} sortParam The name of the 'sort' parameter to send in a request. Defaults to 'sort'. Set this
73 * to undefined if you don't want to send a sort parameter
78 * @cfg {String} filterParam The name of the 'filter' parameter to send in a request. Defaults to 'filter'. Set
79 * this to undefined if you don't want to send a filter parameter
81 filterParam: 'filter',
84 * @cfg {String} directionParam The name of the direction parameter to send in a request. <strong>This is only used when simpleSortMode is set to true.</strong>
87 directionParam: 'dir',
90 * @cfg {Boolean} simpleSortMode Enabling simpleSortMode in conjunction with remoteSort will only send one sort property and a direction when a remote sort is requested.
91 * The directionParam and sortParam will be sent with the property name and either 'ASC' or 'DESC'
93 simpleSortMode: false,
96 * @cfg {Boolean} noCache (optional) Defaults to true. Disable caching by adding a unique parameter
97 * name to the request.
102 * @cfg {String} cacheString The name of the cache param added to the url when using noCache (defaults to "_dc")
107 * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response.
108 * Defaults to 30000 milliseconds (30 seconds).
114 * Specific urls to call on CRUD action methods "create", "read", "update" and "destroy".
115 * Defaults to:<pre><code>
123 * <p>The url is built based upon the action being executed <tt>[create|read|update|destroy]</tt>
124 * using the commensurate <tt>{@link #api}</tt> property, or if undefined default to the
125 * configured {@link Ext.data.Store}.{@link Ext.data.proxy.Server#url url}.</p><br>
126 * <p>For example:</p>
129 create : '/controller/new',
130 read : '/controller/load',
131 update : '/controller/update',
132 destroy : '/controller/destroy_action'
135 * <p>If the specific URL for a given CRUD action is undefined, the CRUD action request
136 * will be directed to the configured <tt>{@link Ext.data.proxy.Server#url url}</tt>.</p>
142 constructor: function(config) {
145 config = config || {};
149 * Fires when the server returns an exception
150 * @param {Ext.data.proxy.Proxy} this
151 * @param {Object} response The response from the AJAX request
152 * @param {Ext.data.Operation} operation The operation that triggered request
156 me.callParent([config]);
159 * @cfg {Object} extraParams Extra parameters that will be included on every request. Individual requests with params
160 * of the same name will override these params when they are in conflict.
162 me.extraParams = config.extraParams || {};
164 me.api = config.api || {};
166 //backwards compatibility, will be deprecated in 5.0
167 me.nocache = me.noCache;
170 //in a ServerProxy all four CRUD operations are executed in the same manner, so we delegate to doRequest in each case
172 return this.doRequest.apply(this, arguments);
176 return this.doRequest.apply(this, arguments);
180 return this.doRequest.apply(this, arguments);
183 destroy: function() {
184 return this.doRequest.apply(this, arguments);
188 * Creates and returns an Ext.data.Request object based on the options passed by the {@link Ext.data.Store Store}
189 * that this Proxy is attached to.
190 * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
191 * @return {Ext.data.Request} The request object
193 buildRequest: function(operation) {
194 var params = Ext.applyIf(operation.params || {}, this.extraParams || {}),
197 //copy any sorters, filters etc into the params so they can be sent over the wire
198 params = Ext.applyIf(params, this.getParams(params, operation));
200 if (operation.id && !params.id) {
201 params.id = operation.id;
204 request = Ext.create('Ext.data.Request', {
206 action : operation.action,
207 records : operation.records,
208 operation: operation,
212 request.url = this.buildUrl(request);
215 * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the
216 * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing
218 operation.request = request;
226 processResponse: function(success, operation, request, response, callback, scope){
236 if (success === true) {
237 reader = me.getReader();
238 result = reader.read(me.extractResponseData(response));
239 records = result.records;
240 length = records.length;
242 if (result.success !== false) {
243 mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
244 mc.addAll(operation.records);
245 for (i = 0; i < length; i++) {
246 record = mc.get(records[i].getId());
250 record.set(record.data);
251 record.endEdit(true);
255 //see comment in buildRequest for why we include the response object here
256 Ext.apply(operation, {
261 operation.setCompleted();
262 operation.setSuccessful();
264 operation.setException(result.message);
265 me.fireEvent('exception', this, response, operation);
268 me.setException(operation, response);
269 me.fireEvent('exception', this, response, operation);
272 //this callback is the one that was passed to the 'read' or 'write' function above
273 if (typeof callback == 'function') {
274 callback.call(scope || me, operation);
277 me.afterRequest(request, success);
281 * Sets up an exception on the operation
283 * @param {Ext.data.Operation} operation The operation
284 * @param {Object} response The response
286 setException: function(operation, response){
287 operation.setException({
288 status: response.status,
289 statusText: response.statusText
294 * Template method to allow subclasses to specify how to get the response for the reader.
296 * @param {Object} response The server response
297 * @return {Mixed} The response data to be used by the reader
299 extractResponseData: function(response){
304 * Encode any values being sent to the server. Can be overridden in subclasses.
306 * @param {Array} An array of sorters/filters.
307 * @return {Mixed} The encoded value
309 applyEncoding: function(value){
310 return Ext.encode(value);
314 * Encodes the array of {@link Ext.util.Sorter} objects into a string to be sent in the request url. By default,
315 * this simply JSON-encodes the sorter data
316 * @param {Array} sorters The array of {@link Ext.util.Sorter Sorter} objects
317 * @return {String} The encoded sorters
319 encodeSorters: function(sorters) {
321 length = sorters.length,
324 for (; i < length; i++) {
326 property : sorters[i].property,
327 direction: sorters[i].direction
330 return this.applyEncoding(min);
335 * Encodes the array of {@link Ext.util.Filter} objects into a string to be sent in the request url. By default,
336 * this simply JSON-encodes the filter data
337 * @param {Array} sorters The array of {@link Ext.util.Filter Filter} objects
338 * @return {String} The encoded filters
340 encodeFilters: function(filters) {
342 length = filters.length,
345 for (; i < length; i++) {
347 property: filters[i].property,
348 value : filters[i].value
351 return this.applyEncoding(min);
356 * Copy any sorters, filters etc into the params so they can be sent over the wire
358 getParams: function(params, operation) {
359 params = params || {};
362 isDef = Ext.isDefined,
363 groupers = operation.groupers,
364 sorters = operation.sorters,
365 filters = operation.filters,
366 page = operation.page,
367 start = operation.start,
368 limit = operation.limit,
370 simpleSortMode = me.simpleSortMode,
372 pageParam = me.pageParam,
373 startParam = me.startParam,
374 limitParam = me.limitParam,
375 groupParam = me.groupParam,
376 sortParam = me.sortParam,
377 filterParam = me.filterParam,
378 directionParam = me.directionParam;
380 if (pageParam && isDef(page)) {
381 params[pageParam] = page;
384 if (startParam && isDef(start)) {
385 params[startParam] = start;
388 if (limitParam && isDef(limit)) {
389 params[limitParam] = limit;
392 if (groupParam && groupers && groupers.length > 0) {
393 // Grouper is a subclass of sorter, so we can just use the sorter method
394 params[groupParam] = me.encodeSorters(groupers);
397 if (sortParam && sorters && sorters.length > 0) {
398 if (simpleSortMode) {
399 params[sortParam] = sorters[0].property;
400 params[directionParam] = sorters[0].direction;
402 params[sortParam] = me.encodeSorters(sorters);
407 if (filterParam && filters && filters.length > 0) {
408 params[filterParam] = me.encodeFilters(filters);
415 * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will
416 * add the cache-buster param to the end of the url. Subclasses may need to perform additional modifications
418 * @param {Ext.data.Request} request The request object
419 * @return {String} The url
421 buildUrl: function(request) {
423 url = me.getUrl(request);
427 Ext.Error.raise("You are using a ServerProxy but have not supplied it with a url.");
432 url = Ext.urlAppend(url, Ext.String.format("{0}={1}", me.cacheString, Ext.Date.now()));
439 * Get the url for the request taking into account the order of priority,
444 * @param {Ext.data.Request} request The request
445 * @return {String} The url
447 getUrl: function(request){
448 return request.url || this.api[request.action] || this.url;
452 * In ServerProxy subclasses, the {@link #create}, {@link #read}, {@link #update} and {@link #destroy} methods all pass
453 * through to doRequest. Each ServerProxy subclass must implement the doRequest method - see {@link Ext.data.proxy.JsonP}
454 * and {@link Ext.data.proxy.Ajax} for examples. This method carries the same signature as each of the methods that delegate to it.
455 * @param {Ext.data.Operation} operation The Ext.data.Operation object
456 * @param {Function} callback The callback function to call when the Operation has completed
457 * @param {Object} scope The scope in which to execute the callback
459 doRequest: function(operation, callback, scope) {
461 Ext.Error.raise("The doRequest function has not been implemented on your Ext.data.proxy.Server subclass. See src/data/ServerProxy.js for details");
466 * Optional callback function which can be used to clean up after a request has been completed.
467 * @param {Ext.data.Request} request The Request object
468 * @param {Boolean} success True if the request was successful
471 afterRequest: Ext.emptyFn,
473 onDestroy: function() {
474 Ext.destroy(this.reader, this.writer);