Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / Server.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-data-proxy-Server'>/**
19 </span> * @author Ed Spencer
20  * @class Ext.data.proxy.Server
21  * @extends Ext.data.proxy.Proxy
22  * 
23  * &lt;p&gt;ServerProxy is a superclass of {@link Ext.data.proxy.JsonP JsonPProxy} and {@link Ext.data.proxy.Ajax AjaxProxy},
24  * and would not usually be used directly.&lt;/p&gt;
25  * 
26  * &lt;p&gt;ServerProxy should ideally be named HttpProxy as it is a superclass for all HTTP proxies - for Ext JS 4.x it has been 
27  * called ServerProxy to enable any 3.x applications that reference the HttpProxy to continue to work (HttpProxy is now an 
28  * alias of AjaxProxy).&lt;/p&gt;
29  */
30 Ext.define('Ext.data.proxy.Server', {
31     extend: 'Ext.data.proxy.Proxy',
32     alias : 'proxy.server',
33     alternateClassName: 'Ext.data.ServerProxy',
34     uses  : ['Ext.data.Request'],
35     
36 <span id='Ext-data-proxy-Server-cfg-url'>    /**
37 </span>     * @cfg {String} url The URL from which to request the data object.
38      */
39     
40 <span id='Ext-data-proxy-Server-cfg-reader'>    /**
41 </span>     * @cfg {Object/String/Ext.data.reader.Reader} reader The Ext.data.reader.Reader to use to decode the server's response. This can
42      * either be a Reader instance, a config object or just a valid Reader type name (e.g. 'json', 'xml').
43      */
44     
45 <span id='Ext-data-proxy-Server-cfg-writer'>    /**
46 </span>     * @cfg {Object/String/Ext.data.writer.Writer} writer The Ext.data.writer.Writer to use to encode any request sent to the server.
47      * This can either be a Writer instance, a config object or just a valid Writer type name (e.g. 'json', 'xml').
48      */
49     
50 <span id='Ext-data-proxy-Server-cfg-pageParam'>    /**
51 </span>     * @cfg {String} pageParam The name of the 'page' parameter to send in a request. Defaults to 'page'. Set this to
52      * undefined if you don't want to send a page parameter
53      */
54     pageParam: 'page',
55     
56 <span id='Ext-data-proxy-Server-cfg-startParam'>    /**
57 </span>     * @cfg {String} startParam The name of the 'start' parameter to send in a request. Defaults to 'start'. Set this
58      * to undefined if you don't want to send a start parameter
59      */
60     startParam: 'start',
61
62 <span id='Ext-data-proxy-Server-cfg-limitParam'>    /**
63 </span>     * @cfg {String} limitParam The name of the 'limit' parameter to send in a request. Defaults to 'limit'. Set this
64      * to undefined if you don't want to send a limit parameter
65      */
66     limitParam: 'limit',
67     
68 <span id='Ext-data-proxy-Server-cfg-groupParam'>    /**
69 </span>     * @cfg {String} groupParam The name of the 'group' parameter to send in a request. Defaults to 'group'. Set this
70      * to undefined if you don't want to send a group parameter
71      */
72     groupParam: 'group',
73     
74 <span id='Ext-data-proxy-Server-cfg-sortParam'>    /**
75 </span>     * @cfg {String} sortParam The name of the 'sort' parameter to send in a request. Defaults to 'sort'. Set this
76      * to undefined if you don't want to send a sort parameter
77      */
78     sortParam: 'sort',
79     
80 <span id='Ext-data-proxy-Server-cfg-filterParam'>    /**
81 </span>     * @cfg {String} filterParam The name of the 'filter' parameter to send in a request. Defaults to 'filter'. Set 
82      * this to undefined if you don't want to send a filter parameter
83      */
84     filterParam: 'filter',
85     
86 <span id='Ext-data-proxy-Server-cfg-directionParam'>    /**
87 </span>     * @cfg {String} directionParam The name of the direction parameter to send in a request. &lt;strong&gt;This is only used when simpleSortMode is set to true.&lt;/strong&gt;
88      * Defaults to 'dir'.
89      */
90     directionParam: 'dir',
91     
92 <span id='Ext-data-proxy-Server-cfg-simpleSortMode'>    /**
93 </span>     * @cfg {Boolean} simpleSortMode Enabling simpleSortMode in conjunction with remoteSort will only send one sort property and a direction when a remote sort is requested.
94      * The directionParam and sortParam will be sent with the property name and either 'ASC' or 'DESC'
95      */
96     simpleSortMode: false,
97     
98 <span id='Ext-data-proxy-Server-cfg-noCache'>    /**
99 </span>     * @cfg {Boolean} noCache (optional) Defaults to true. Disable caching by adding a unique parameter
100      * name to the request.
101      */
102     noCache : true,
103     
104 <span id='Ext-data-proxy-Server-cfg-cacheString'>    /**
105 </span>     * @cfg {String} cacheString The name of the cache param added to the url when using noCache (defaults to &quot;_dc&quot;)
106      */
107     cacheString: &quot;_dc&quot;,
108     
109 <span id='Ext-data-proxy-Server-cfg-timeout'>    /**
110 </span>     * @cfg {Number} timeout (optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
111      */
112     timeout : 30000,
113     
114 <span id='Ext-data-proxy-Server-cfg-api'>    /**
115 </span>     * @cfg {Object} api
116      * Specific urls to call on CRUD action methods &quot;read&quot;, &quot;create&quot;, &quot;update&quot; and &quot;destroy&quot;.
117      * Defaults to:&lt;pre&gt;&lt;code&gt;
118 api: {
119     read    : undefined,
120     create  : undefined,
121     update  : undefined,
122     destroy : undefined
123 }
124      * &lt;/code&gt;&lt;/pre&gt;
125      * &lt;p&gt;The url is built based upon the action being executed &lt;tt&gt;[load|create|save|destroy]&lt;/tt&gt;
126      * using the commensurate &lt;tt&gt;{@link #api}&lt;/tt&gt; property, or if undefined default to the
127      * configured {@link Ext.data.Store}.{@link Ext.data.proxy.Server#url url}.&lt;/p&gt;&lt;br&gt;
128      * &lt;p&gt;For example:&lt;/p&gt;
129      * &lt;pre&gt;&lt;code&gt;
130 api: {
131     load :    '/controller/load',
132     create :  '/controller/new',
133     save :    '/controller/update',
134     destroy : '/controller/destroy_action'
135 }
136      * &lt;/code&gt;&lt;/pre&gt;
137      * &lt;p&gt;If the specific URL for a given CRUD action is undefined, the CRUD action request
138      * will be directed to the configured &lt;tt&gt;{@link Ext.data.proxy.Server#url url}&lt;/tt&gt;.&lt;/p&gt;
139      */
140     
141 <span id='Ext-data-proxy-Server-method-constructor'>    /**
142 </span>     * @ignore
143      */
144     constructor: function(config) {
145         var me = this;
146         
147         config = config || {};
148         this.addEvents(
149 <span id='Ext-data-proxy-Server-event-exception'>            /**
150 </span>             * @event exception
151              * Fires when the server returns an exception
152              * @param {Ext.data.proxy.Proxy} this
153              * @param {Object} response The response from the AJAX request
154              * @param {Ext.data.Operation} operation The operation that triggered request
155              */
156             'exception'
157         );
158         me.callParent([config]);
159         
160 <span id='Ext-data-proxy-Server-cfg-extraParams'>        /**
161 </span>         * @cfg {Object} extraParams Extra parameters that will be included on every request. Individual requests with params
162          * of the same name will override these params when they are in conflict.
163          */
164         me.extraParams = config.extraParams || {};
165         
166         me.api = config.api || {};
167         
168         //backwards compatibility, will be deprecated in 5.0
169         me.nocache = me.noCache;
170     },
171     
172     //in a ServerProxy all four CRUD operations are executed in the same manner, so we delegate to doRequest in each case
173     create: function() {
174         return this.doRequest.apply(this, arguments);
175     },
176     
177     read: function() {
178         return this.doRequest.apply(this, arguments);
179     },
180     
181     update: function() {
182         return this.doRequest.apply(this, arguments);
183     },
184     
185     destroy: function() {
186         return this.doRequest.apply(this, arguments);
187     },
188     
189 <span id='Ext-data-proxy-Server-method-buildRequest'>    /**
190 </span>     * Creates and returns an Ext.data.Request object based on the options passed by the {@link Ext.data.Store Store}
191      * that this Proxy is attached to.
192      * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
193      * @return {Ext.data.Request} The request object
194      */
195     buildRequest: function(operation) {
196         var params = Ext.applyIf(operation.params || {}, this.extraParams || {}),
197             request;
198         
199         //copy any sorters, filters etc into the params so they can be sent over the wire
200         params = Ext.applyIf(params, this.getParams(params, operation));
201         
202         if (operation.id &amp;&amp; !params.id) {
203             params.id = operation.id;
204         }
205         
206         request = Ext.create('Ext.data.Request', {
207             params   : params,
208             action   : operation.action,
209             records  : operation.records,
210             operation: operation,
211             url      : operation.url
212         });
213         
214         request.url = this.buildUrl(request);
215         
216         /*
217          * Save the request on the Operation. Operations don't usually care about Request and Response data, but in the
218          * ServerProxy and any of its subclasses we add both request and response as they may be useful for further processing
219          */
220         operation.request = request;
221         
222         return request;
223     },
224     
225 <span id='Ext-data-proxy-Server-method-processResponse'>    /**
226 </span>     * 
227      */
228     processResponse: function(success, operation, request, response, callback, scope){
229         var me = this,
230             reader,
231             result,
232             records,
233             length,
234             mc,
235             record,
236             i;
237             
238         if (success === true) {
239             reader = me.getReader();
240             result = reader.read(me.extractResponseData(response));
241             records = result.records;
242             length = records.length;
243             
244             if (result.success !== false) {
245                 mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
246                 mc.addAll(operation.records);
247                 for (i = 0; i &lt; length; i++) {
248                     record = mc.get(records[i].getId());
249                     
250                     if (record) {
251                         record.beginEdit();
252                         record.set(record.data);
253                         record.endEdit(true);
254                     }
255                 }
256                 
257                 //see comment in buildRequest for why we include the response object here
258                 Ext.apply(operation, {
259                     response: response,
260                     resultSet: result
261                 });
262                 
263                 operation.setCompleted();
264                 operation.setSuccessful();
265             } else {
266                 operation.setException(result.message);
267                 me.fireEvent('exception', this, response, operation);
268             }
269         } else {
270             me.setException(operation, response);
271             me.fireEvent('exception', this, response, operation);              
272         }
273             
274         //this callback is the one that was passed to the 'read' or 'write' function above
275         if (typeof callback == 'function') {
276             callback.call(scope || me, operation);
277         }
278             
279         me.afterRequest(request, success);
280     },
281     
282 <span id='Ext-data-proxy-Server-method-setException'>    /**
283 </span>     * Sets up an exception on the operation
284      * @private
285      * @param {Ext.data.Operation} operation The operation
286      * @param {Object} response The response
287      */
288     setException: function(operation, response){
289         operation.setException({
290             status: response.status,
291             statusText: response.statusText
292         });     
293     },
294     
295 <span id='Ext-data-proxy-Server-method-extractResponseData'>    /**
296 </span>     * Template method to allow subclasses to specify how to get the response for the reader.
297      * @private
298      * @param {Object} response The server response
299      * @return {Mixed} The response data to be used by the reader
300      */
301     extractResponseData: function(response){
302         return response; 
303     },
304     
305 <span id='Ext-data-proxy-Server-method-applyEncoding'>    /**
306 </span>     * Encode any values being sent to the server. Can be overridden in subclasses.
307      * @private
308      * @param {Array} An array of sorters/filters.
309      * @return {Mixed} The encoded value
310      */
311     applyEncoding: function(value){
312         return Ext.encode(value);
313     },
314     
315 <span id='Ext-data-proxy-Server-method-encodeSorters'>    /**
316 </span>     * Encodes the array of {@link Ext.util.Sorter} objects into a string to be sent in the request url. By default, 
317      * this simply JSON-encodes the sorter data
318      * @param {Array} sorters The array of {@link Ext.util.Sorter Sorter} objects
319      * @return {String} The encoded sorters
320      */
321     encodeSorters: function(sorters) {
322         var min = [],
323             length = sorters.length,
324             i = 0;
325         
326         for (; i &lt; length; i++) {
327             min[i] = {
328                 property : sorters[i].property,
329                 direction: sorters[i].direction
330             };
331         }
332         return this.applyEncoding(min);
333         
334     },
335     
336 <span id='Ext-data-proxy-Server-method-encodeFilters'>    /**
337 </span>     * Encodes the array of {@link Ext.util.Filter} objects into a string to be sent in the request url. By default, 
338      * this simply JSON-encodes the filter data
339      * @param {Array} sorters The array of {@link Ext.util.Filter Filter} objects
340      * @return {String} The encoded filters
341      */
342     encodeFilters: function(filters) {
343         var min = [],
344             length = filters.length,
345             i = 0;
346         
347         for (; i &lt; length; i++) {
348             min[i] = {
349                 property: filters[i].property,
350                 value   : filters[i].value
351             };
352         }
353         return this.applyEncoding(min);
354     },
355     
356 <span id='Ext-data-proxy-Server-method-getParams'>    /**
357 </span>     * @private
358      * Copy any sorters, filters etc into the params so they can be sent over the wire
359      */
360     getParams: function(params, operation) {
361         params = params || {};
362         
363         var me             = this,
364             isDef          = Ext.isDefined,
365             groupers       = operation.groupers,
366             sorters        = operation.sorters,
367             filters        = operation.filters,
368             page           = operation.page,
369             start          = operation.start,
370             limit          = operation.limit,
371             
372             simpleSortMode = me.simpleSortMode,
373             
374             pageParam      = me.pageParam,
375             startParam     = me.startParam,
376             limitParam     = me.limitParam,
377             groupParam     = me.groupParam,
378             sortParam      = me.sortParam,
379             filterParam    = me.filterParam,
380             directionParam       = me.directionParam;
381         
382         if (pageParam &amp;&amp; isDef(page)) {
383             params[pageParam] = page;
384         }
385         
386         if (startParam &amp;&amp; isDef(start)) {
387             params[startParam] = start;
388         }
389         
390         if (limitParam &amp;&amp; isDef(limit)) {
391             params[limitParam] = limit;
392         }
393         
394         if (groupParam &amp;&amp; groupers &amp;&amp; groupers.length &gt; 0) {
395             // Grouper is a subclass of sorter, so we can just use the sorter method
396             params[groupParam] = me.encodeSorters(groupers);
397         }
398         
399         if (sortParam &amp;&amp; sorters &amp;&amp; sorters.length &gt; 0) {
400             if (simpleSortMode) {
401                 params[sortParam] = sorters[0].property;
402                 params[directionParam] = sorters[0].direction;
403             } else {
404                 params[sortParam] = me.encodeSorters(sorters);
405             }
406             
407         }
408         
409         if (filterParam &amp;&amp; filters &amp;&amp; filters.length &gt; 0) {
410             params[filterParam] = me.encodeFilters(filters);
411         }
412         
413         return params;
414     },
415     
416 <span id='Ext-data-proxy-Server-method-buildUrl'>    /**
417 </span>     * Generates a url based on a given Ext.data.Request object. By default, ServerProxy's buildUrl will
418      * add the cache-buster param to the end of the url. Subclasses may need to perform additional modifications
419      * to the url.
420      * @param {Ext.data.Request} request The request object
421      * @return {String} The url
422      */
423     buildUrl: function(request) {
424         var me = this,
425             url = me.getUrl(request);
426         
427         //&lt;debug&gt;
428         if (!url) {
429             Ext.Error.raise(&quot;You are using a ServerProxy but have not supplied it with a url.&quot;);
430         }
431         //&lt;/debug&gt;
432         
433         if (me.noCache) {
434             url = Ext.urlAppend(url, Ext.String.format(&quot;{0}={1}&quot;, me.cacheString, Ext.Date.now()));
435         }
436         
437         return url;
438     },
439     
440 <span id='Ext-data-proxy-Server-method-getUrl'>    /**
441 </span>     * Get the url for the request taking into account the order of priority,
442      * - The request
443      * - The api
444      * - The url
445      * @private
446      * @param {Ext.data.Request} request The request
447      * @return {String} The url
448      */
449     getUrl: function(request){
450         return request.url || this.api[request.action] || this.url;
451     },
452     
453 <span id='Ext-data-proxy-Server-method-doRequest'>    /**
454 </span>     * In ServerProxy subclasses, the {@link #create}, {@link #read}, {@link #update} and {@link #destroy} methods all pass
455      * through to doRequest. Each ServerProxy subclass must implement the doRequest method - see {@link Ext.data.proxy.JsonP}
456      * and {@link Ext.data.proxy.Ajax} for examples. This method carries the same signature as each of the methods that delegate to it.
457      * @param {Ext.data.Operation} operation The Ext.data.Operation object
458      * @param {Function} callback The callback function to call when the Operation has completed
459      * @param {Object} scope The scope in which to execute the callback
460      */
461     doRequest: function(operation, callback, scope) {
462         //&lt;debug&gt;
463         Ext.Error.raise(&quot;The doRequest function has not been implemented on your Ext.data.proxy.Server subclass. See src/data/ServerProxy.js for details&quot;);
464         //&lt;/debug&gt;
465     },
466     
467 <span id='Ext-data-proxy-Server-method-afterRequest'>    /**
468 </span>     * Optional callback function which can be used to clean up after a request has been completed.
469      * @param {Ext.data.Request} request The Request object
470      * @param {Boolean} success True if the request was successful
471      * @method
472      */
473     afterRequest: Ext.emptyFn,
474     
475     onDestroy: function() {
476         Ext.destroy(this.reader, this.writer);
477     }
478 });
479 </pre>
480 </body>
481 </html>