Proxy2.html 18.8 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>The source code</title>
  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  <style type="text/css">
    .highlight { display: block; background-color: #ddd; }
  </style>
  <script type="text/javascript">
    function highlight() {
      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
    }
  </script>
</head>
<body onload="prettyPrint(); highlight();">
  <pre class="prettyprint lang-js"><span id='Ext-data-proxy-Proxy'>/**
</span> * @author Ed Spencer
 *
 * Proxies are used by {@link Ext.data.Store Stores} to handle the loading and saving of {@link Ext.data.Model Model}
 * data. Usually developers will not need to create or interact with proxies directly.
 *
 * # Types of Proxy
 *
 * There are two main types of Proxy - {@link Ext.data.proxy.Client Client} and {@link Ext.data.proxy.Server Server}.
 * The Client proxies save their data locally and include the following subclasses:
 *
 * - {@link Ext.data.proxy.LocalStorage LocalStorageProxy} - saves its data to localStorage if the browser supports it
 * - {@link Ext.data.proxy.SessionStorage SessionStorageProxy} - saves its data to sessionStorage if the browsers supports it
 * - {@link Ext.data.proxy.Memory MemoryProxy} - holds data in memory only, any data is lost when the page is refreshed
 *
 * The Server proxies save their data by sending requests to some remote server. These proxies include:
 *
 * - {@link Ext.data.proxy.Ajax Ajax} - sends requests to a server on the same domain
 * - {@link Ext.data.proxy.JsonP JsonP} - uses JSON-P to send requests to a server on a different domain
 * - {@link Ext.data.proxy.Rest Rest} - uses RESTful HTTP methods (GET/PUT/POST/DELETE) to communicate with server
 * - {@link Ext.data.proxy.Direct Direct} - uses {@link Ext.direct.Manager} to send requests
 *
 * Proxies operate on the principle that all operations performed are either Create, Read, Update or Delete. These four
 * operations are mapped to the methods {@link #create}, {@link #read}, {@link #update} and {@link #destroy}
 * respectively. Each Proxy subclass implements these functions.
 *
 * The CRUD methods each expect an {@link Ext.data.Operation Operation} object as the sole argument. The Operation
 * encapsulates information about the action the Store wishes to perform, the {@link Ext.data.Model model} instances
 * that are to be modified, etc. See the {@link Ext.data.Operation Operation} documentation for more details. Each CRUD
 * method also accepts a callback function to be called asynchronously on completion.
 *
 * Proxies also support batching of Operations via a {@link Ext.data.Batch batch} object, invoked by the {@link #batch}
 * method.
 */
Ext.define('Ext.data.proxy.Proxy', {
    alias: 'proxy.proxy',
    alternateClassName: ['Ext.data.DataProxy', 'Ext.data.Proxy'],

    uses: [
        'Ext.data.Batch',
        'Ext.data.Operation',
        'Ext.data.Model'
    ],

    mixins: {
        observable: 'Ext.util.Observable'
    },

<span id='Ext-data-proxy-Proxy-cfg-batchOrder'>    /**
</span>     * @cfg {String} batchOrder
     * Comma-separated ordering 'create', 'update' and 'destroy' actions when batching. Override this to set a different
     * order for the batched CRUD actions to be executed in. Defaults to 'create,update,destroy'.
     */
    batchOrder: 'create,update,destroy',

<span id='Ext-data-proxy-Proxy-cfg-batchActions'>    /**
</span>     * @cfg {Boolean} batchActions
     * True to batch actions of a particular type when synchronizing the store. Defaults to true.
     */
    batchActions: true,

<span id='Ext-data-proxy-Proxy-cfg-defaultReaderType'>    /**
</span>     * @cfg {String} defaultReaderType
     * The default registered reader type. Defaults to 'json'.
     * @private
     */
    defaultReaderType: 'json',

<span id='Ext-data-proxy-Proxy-cfg-defaultWriterType'>    /**
</span>     * @cfg {String} defaultWriterType
     * The default registered writer type. Defaults to 'json'.
     * @private
     */
    defaultWriterType: 'json',

<span id='Ext-data-proxy-Proxy-cfg-model'>    /**
</span>     * @cfg {String/Ext.data.Model} model
     * The name of the Model to tie to this Proxy. Can be either the string name of the Model, or a reference to the
     * Model constructor. Required.
     */

<span id='Ext-data-proxy-Proxy-cfg-reader'>    /**
</span>     * @cfg {Object/String/Ext.data.reader.Reader} reader
     * The Ext.data.reader.Reader to use to decode the server's response or data read from client. This can either be a
     * Reader instance, a config object or just a valid Reader type name (e.g. 'json', 'xml').
     */

<span id='Ext-data-proxy-Proxy-cfg-writer'>    /**
</span>     * @cfg {Object/String/Ext.data.writer.Writer} writer
     * The Ext.data.writer.Writer to use to encode any request sent to the server or saved to client. This can either be
     * a Writer instance, a config object or just a valid Writer type name (e.g. 'json', 'xml').
     */

<span id='Ext-data-proxy-Proxy-property-isProxy'>    /**
</span>     * @property {Boolean} isProxy
     * `true` in this class to identify an object as an instantiated Proxy, or subclass thereof.
     */
    isProxy: true,

<span id='Ext-data-proxy-Proxy-method-constructor'>    /**
</span>     * Creates the Proxy
     * @param {Object} config (optional) Config object.
     */
    constructor: function(config) {
        config = config || {};

        if (config.model === undefined) {
            delete config.model;
        }

        this.mixins.observable.constructor.call(this, config);

        if (this.model !== undefined &amp;&amp; !(this.model instanceof Ext.data.Model)) {
            this.setModel(this.model);
        }

<span id='Ext-data-proxy-Proxy-event-metachange'>        /**
</span>         * @event metachange
         * Fires when this proxy's reader provides new metadata. Metadata usually consists
         * of new field definitions, but can include any configuration data required by an
         * application, and can be processed as needed in the event handler.
         * This event is currently only fired for JsonReaders. Note that this event is also
         * propagated by {@link Ext.data.Store}, which is typically where it would be handled.
         * @param {Ext.data.proxy.Proxy} this
         * @param {Object} meta The JSON metadata
         */
    },

<span id='Ext-data-proxy-Proxy-method-setModel'>    /**
</span>     * Sets the model associated with this proxy. This will only usually be called by a Store
     *
     * @param {String/Ext.data.Model} model The new model. Can be either the model name string,
     * or a reference to the model's constructor
     * @param {Boolean} setOnStore Sets the new model on the associated Store, if one is present
     */
    setModel: function(model, setOnStore) {
        this.model = Ext.ModelManager.getModel(model);

        var reader = this.reader,
            writer = this.writer;

        this.setReader(reader);
        this.setWriter(writer);

        if (setOnStore &amp;&amp; this.store) {
            this.store.setModel(this.model);
        }
    },

<span id='Ext-data-proxy-Proxy-method-getModel'>    /**
</span>     * Returns the model attached to this Proxy
     * @return {Ext.data.Model} The model
     */
    getModel: function() {
        return this.model;
    },

<span id='Ext-data-proxy-Proxy-method-setReader'>    /**
</span>     * Sets the Proxy's Reader by string, config object or Reader instance
     *
     * @param {String/Object/Ext.data.reader.Reader} reader The new Reader, which can be either a type string,
     * a configuration object or an Ext.data.reader.Reader instance
     * @return {Ext.data.reader.Reader} The attached Reader object
     */
    setReader: function(reader) {
        var me = this,
            needsCopy = true;

        if (reader === undefined || typeof reader == 'string') {
            reader = {
                type: reader
            };
            needsCopy = false;
        }

        if (reader.isReader) {
            reader.setModel(me.model);
        } else {
            if (needsCopy) {
                reader = Ext.apply({}, reader);
            }
            Ext.applyIf(reader, {
                proxy: me,
                model: me.model,
                type : me.defaultReaderType
            });

            reader = Ext.createByAlias('reader.' + reader.type, reader);
        }

        if (reader.onMetaChange) {
            reader.onMetaChange = Ext.Function.createSequence(reader.onMetaChange, this.onMetaChange, this);
        }

        me.reader = reader;
        return me.reader;
    },

<span id='Ext-data-proxy-Proxy-method-getReader'>    /**
</span>     * Returns the reader currently attached to this proxy instance
     * @return {Ext.data.reader.Reader} The Reader instance
     */
    getReader: function() {
        return this.reader;
    },

<span id='Ext-data-proxy-Proxy-method-onMetaChange'>    /**
</span>     * @private
     * Called each time the reader's onMetaChange is called so that the proxy can fire the metachange event
     */
    onMetaChange: function(meta) {
        this.fireEvent('metachange', this, meta);
    },

<span id='Ext-data-proxy-Proxy-method-setWriter'>    /**
</span>     * Sets the Proxy's Writer by string, config object or Writer instance
     *
     * @param {String/Object/Ext.data.writer.Writer} writer The new Writer, which can be either a type string,
     * a configuration object or an Ext.data.writer.Writer instance
     * @return {Ext.data.writer.Writer} The attached Writer object
     */
    setWriter: function(writer) {
        var me = this,
            needsCopy = true;
            
        if (writer === undefined || typeof writer == 'string') {
            writer = {
                type: writer
            };
            needsCopy = false;
        }

        if (!writer.isWriter) {
            if (needsCopy) {
                writer = Ext.apply({}, writer);
            }
            Ext.applyIf(writer, {
                model: me.model,
                type : me.defaultWriterType
            });

            writer = Ext.createByAlias('writer.' + writer.type, writer);
        }

        me.writer = writer;

        return me.writer;
    },

<span id='Ext-data-proxy-Proxy-method-getWriter'>    /**
</span>     * Returns the writer currently attached to this proxy instance
     * @return {Ext.data.writer.Writer} The Writer instance
     */
    getWriter: function() {
        return this.writer;
    },

<span id='Ext-data-proxy-Proxy-method-create'>    /**
</span>     * Performs the given create operation.
     * @param {Ext.data.Operation} operation The Operation to perform
     * @param {Function} callback Callback function to be called when the Operation has completed (whether
     * successful or not)
     * @param {Object} scope Scope to execute the callback function in
     * @method
     */
    create: Ext.emptyFn,

<span id='Ext-data-proxy-Proxy-method-read'>    /**
</span>     * Performs the given read operation.
     * @param {Ext.data.Operation} operation The Operation to perform
     * @param {Function} callback Callback function to be called when the Operation has completed (whether
     * successful or not)
     * @param {Object} scope Scope to execute the callback function in
     * @method
     */
    read: Ext.emptyFn,

<span id='Ext-data-proxy-Proxy-method-update'>    /**
</span>     * Performs the given update operation.
     * @param {Ext.data.Operation} operation The Operation to perform
     * @param {Function} callback Callback function to be called when the Operation has completed (whether
     * successful or not)
     * @param {Object} scope Scope to execute the callback function in
     * @method
     */
    update: Ext.emptyFn,

<span id='Ext-data-proxy-Proxy-method-destroy'>    /**
</span>     * Performs the given destroy operation.
     * @param {Ext.data.Operation} operation The Operation to perform
     * @param {Function} callback Callback function to be called when the Operation has completed (whether
     * successful or not)
     * @param {Object} scope Scope to execute the callback function in
     * @method
     */
    destroy: Ext.emptyFn,

<span id='Ext-data-proxy-Proxy-method-batch'>    /**
</span>     * Performs a batch of {@link Ext.data.Operation Operations}, in the order specified by {@link #batchOrder}. Used
     * internally by {@link Ext.data.Store}'s {@link Ext.data.Store#sync sync} method. Example usage:
     *
     *     myProxy.batch({
     *         create : [myModel1, myModel2],
     *         update : [myModel3],
     *         destroy: [myModel4, myModel5]
     *     });
     *
     * Where the myModel* above are {@link Ext.data.Model Model} instances - in this case 1 and 2 are new instances and
     * have not been saved before, 3 has been saved previously but needs to be updated, and 4 and 5 have already been
     * saved but should now be destroyed.
     * 
     * Note that the previous version of this method took 2 arguments (operations and listeners). While this is still
     * supported for now, the current signature is now a single `options` argument that can contain both operations and
     * listeners, in addition to other options. The multi-argument signature will likely be deprecated in a future release.
     *
     * @param {Object} options Object containing one or more properties supported by the batch method:
     * 
     * @param {Object} options.operations Object containing the Model instances to act upon, keyed by action name
     * 
     * @param {Object} [options.listeners] Event listeners object passed straight through to the Batch -
     * see {@link Ext.data.Batch} for details
     * 
     * @param {Ext.data.Batch/Object} [options.batch] A {@link Ext.data.Batch} object (or batch config to apply 
     * to the created batch). If unspecified a default batch will be auto-created.
     * 
     * @param {Function} [options.callback] The function to be called upon completion of processing the batch.
     * The callback is called regardless of success or failure and is passed the following parameters:
     * @param {Ext.data.Batch} options.callback.batch The {@link Ext.data.Batch batch} that was processed,
     * containing all operations in their current state after processing
     * @param {Object} options.callback.options The options argument that was originally passed into batch
     * 
     * @param {Function} [options.success] The function to be called upon successful completion of the batch. The 
     * success function is called only if no exceptions were reported in any operations. If one or more exceptions
     * occurred then the `failure` function will be called instead. The success function is called 
     * with the following parameters:
     * @param {Ext.data.Batch} options.success.batch The {@link Ext.data.Batch batch} that was processed,
     * containing all operations in their current state after processing
     * @param {Object} options.success.options The options argument that was originally passed into batch
     * 
     * @param {Function} [options.failure] The function to be called upon unsuccessful completion of the batch. The 
     * failure function is called when one or more operations returns an exception during processing (even if some
     * operations were also successful). In this case you can check the batch's {@link Ext.data.Batch#exceptions
     * exceptions} array to see exactly which operations had exceptions. The failure function is called with the 
     * following parameters:
     * @param {Ext.data.Batch} options.failure.batch The {@link Ext.data.Batch batch} that was processed,
     * containing all operations in their current state after processing
     * @param {Object} options.failure.options The options argument that was originally passed into batch
     * 
     * @param {Object} [options.scope] The scope in which to execute any callbacks (i.e. the `this` object inside
     * the callback, success and/or failure functions). Defaults to the proxy.
     *
     * @return {Ext.data.Batch} The newly created Batch
     */
    batch: function(options, /* deprecated */listeners) {
        var me = this,
            useBatch = me.batchActions,
            batch,
            records,
            actions, aLen, action, a, r, rLen, record;

        if (options.operations === undefined) {
            // the old-style (operations, listeners) signature was called
            // so convert to the single options argument syntax
            options = {
                operations: options,
                listeners: listeners
            };
        }

        if (options.batch) {
            if (Ext.isDefined(options.batch.runOperation)) {
                batch = Ext.applyIf(options.batch, {
                    proxy: me,
                    listeners: {}
                });
            }
        } else {
            options.batch = {
                proxy: me,
                listeners: options.listeners || {}
            };
        }

        if (!batch) {
            batch = new Ext.data.Batch(options.batch);
        }

        batch.on('complete', Ext.bind(me.onBatchComplete, me, [options], 0));

        actions = me.batchOrder.split(',');
        aLen    = actions.length;

        for (a = 0; a &lt; aLen; a++) {
            action  = actions[a];
            records = options.operations[action];

            if (records) {
                if (useBatch) {
                    batch.add(new Ext.data.Operation({
                        action  : action,
                        records : records
                    }));
                } else {
                    rLen = records.length;

                    for (r = 0; r &lt; rLen; r++) {
                        record = records[r];

                        batch.add(new Ext.data.Operation({
                            action  : action,
                            records : [record]
                        }));
                    }
                }
            }
        }

        batch.start();
        return batch;
    },

<span id='Ext-data-proxy-Proxy-method-onBatchComplete'>    /**
</span>     * @private
     * The internal callback that the proxy uses to call any specified user callbacks after completion of a batch
     */
    onBatchComplete: function(batchOptions, batch) {
        var scope = batchOptions.scope || this;

        if (batch.hasException) {
            if (Ext.isFunction(batchOptions.failure)) {
                Ext.callback(batchOptions.failure, scope, [batch, batchOptions]);
            }
        } else if (Ext.isFunction(batchOptions.success)) {
            Ext.callback(batchOptions.success, scope, [batch, batchOptions]);
        }

        if (Ext.isFunction(batchOptions.callback)) {
            Ext.callback(batchOptions.callback, scope, [batch, batchOptions]);
        }
    }
}, function() {
    //backwards compatibility
    Ext.data.DataProxy = this;
});
</pre>
</body>
</html>