Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / data / DataWriter.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.data.DataWriter
9  * <p>Ext.data.DataWriter facilitates create, update, and destroy actions between
10  * an Ext.data.Store and a server-side framework. A Writer enabled Store will
11  * automatically manage the Ajax requests to perform CRUD actions on a Store.</p>
12  * <p>Ext.data.DataWriter is an abstract base class which is intended to be extended
13  * and should not be created directly. For existing implementations, see
14  * {@link Ext.data.JsonWriter}.</p>
15  * <p>Creating a writer is simple:</p>
16  * <pre><code>
17 var writer = new Ext.data.JsonWriter();
18  * </code></pre>
19  * <p>The proxy for a writer enabled store can be configured with a simple <code>url</code>:</p>
20  * <pre><code>
21 // Create a standard HttpProxy instance.
22 var proxy = new Ext.data.HttpProxy({
23     url: 'app.php/users'
24 });
25  * </code></pre>
26  * <p>For finer grained control, the proxy may also be configured with an <code>api</code>:</p>
27  * <pre><code>
28 // Use the api specification
29 var proxy = new Ext.data.HttpProxy({
30     api: {
31         read    : 'app.php/users/read',
32         create  : 'app.php/users/create',
33         update  : 'app.php/users/update',
34         destroy : 'app.php/users/destroy'
35     }
36 });
37  * </code></pre>
38  * <p>Creating a Writer enabled store:</p>
39  * <pre><code>
40 var store = new Ext.data.Store({
41     proxy: proxy,
42     reader: reader,
43     writer: writer
44 });
45  * </code></pre>
46  * @constructor Create a new DataWriter
47  * @param {Object} meta Metadata configuration options (implementation-specific)
48  * @param {Object} recordType Either an Array of field definition objects as specified
49  * in {@link Ext.data.Record#create}, or an {@link Ext.data.Record} object created
50  * using {@link Ext.data.Record#create}.
51  */
52 Ext.data.DataWriter = function(config){
53     Ext.apply(this, config);
54 };
55 Ext.data.DataWriter.prototype = {
56
57     /**
58      * @cfg {Boolean} writeAllFields
59      * <tt>false</tt> by default.  Set <tt>true</tt> to have DataWriter return ALL fields of a modified
60      * record -- not just those that changed.
61      * <tt>false</tt> to have DataWriter only request modified fields from a record.
62      */
63     writeAllFields : false,
64     /**
65      * @cfg {Boolean} listful
66      * <tt>false</tt> by default.  Set <tt>true</tt> to have the DataWriter <b>always</b> write HTTP params as a list,
67      * even when acting upon a single record.
68      */
69     listful : false,    // <-- listful is actually not used internally here in DataWriter.  @see Ext.data.Store#execute.
70
71     /**
72      * Writes data in preparation for server-write action.  Simply proxies to DataWriter#update, DataWriter#create
73      * DataWriter#destroy.
74      * @param {String} action [CREATE|UPDATE|DESTROY]
75      * @param {Object} params The params-hash to write-to
76      * @param {Record/Record[]} rs The recordset write.
77      */
78     write : function(action, params, rs) {
79         var data    = [],
80         renderer    = action + 'Record';
81         // TODO implement @cfg listful here
82         if (Ext.isArray(rs)) {
83             Ext.each(rs, function(rec){
84                 data.push(this[renderer](rec));
85             }, this);
86         }
87         else if (rs instanceof Ext.data.Record) {
88             data = this[renderer](rs);
89         }
90         this.render(action, rs, params, data);
91     },
92
93     /**
94      * abstract method meant to be overridden by all DataWriter extensions.  It's the extension's job to apply the "data" to the "params".
95      * The data-object provided to render is populated with data according to the meta-info defined in the user's DataReader config,
96      * @param {String} action [Ext.data.Api.actions.create|read|update|destroy]
97      * @param {Record[]} rs Store recordset
98      * @param {Object} params Http params to be sent to server.
99      * @param {Object} data object populated according to DataReader meta-data.
100      */
101     render : Ext.emptyFn,
102
103     /**
104      * @cfg {Function} updateRecord Abstract method that should be implemented in all subclasses
105      * (e.g.: {@link Ext.data.JsonWriter#updateRecord JsonWriter.updateRecord}
106      */
107     updateRecord : Ext.emptyFn,
108
109     /**
110      * @cfg {Function} createRecord Abstract method that should be implemented in all subclasses
111      * (e.g.: {@link Ext.data.JsonWriter#createRecord JsonWriter.createRecord})
112      */
113     createRecord : Ext.emptyFn,
114
115     /**
116      * @cfg {Function} destroyRecord Abstract method that should be implemented in all subclasses
117      * (e.g.: {@link Ext.data.JsonWriter#destroyRecord JsonWriter.destroyRecord})
118      */
119     destroyRecord : Ext.emptyFn,
120
121     /**
122      * Converts a Record to a hash.
123      * @param {Record}
124      * @private
125      */
126     toHash : function(rec) {
127         var map = rec.fields.map,
128             data = {},
129             raw = (this.writeAllFields === false && rec.phantom === false) ? rec.getChanges() : rec.data,
130             m;
131         Ext.iterate(raw, function(prop, value){
132             if((m = map[prop])){
133                 data[m.mapping ? m.mapping : m.name] = value;
134             }
135         });
136         // we don't want to write Ext auto-generated id to hash.  Careful not to remove it on Models not having auto-increment pk though.
137         // We can tell its not auto-increment if the user defined a DataReader field for it *and* that field's value is non-empty.
138         // we could also do a RegExp here for the Ext.data.Record AUTO_ID prefix.
139         if (rec.phantom) {
140             if (rec.fields.containsKey(this.meta.idProperty) && Ext.isEmpty(rec.data[this.meta.idProperty])) {
141                 delete data[this.meta.idProperty];
142             }
143         } else {
144             data[this.meta.idProperty] = rec.id
145         }
146         return data;
147     }
148 };