partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

HydraModel.js (11481B)


      1 Ext.define("PartKeepr.data.HydraModel", {
      2     extend: 'Ext.data.Model',
      3 
      4     mixins: ['PartKeepr.data.CallActions'],
      5 
      6     getData: function ()
      7     {
      8         var data = this.callParent(arguments);
      9 
     10         if (this.phantom) {
     11             delete data[this.idProperty];
     12         }
     13 
     14         return data;
     15     },
     16     isPartiallyEqualTo: function (model, fields)
     17     {
     18         var i;
     19 
     20         for (i = 0; i < fields.length; i++) {
     21             if (this.get(fields[i]) != model.get(fields[i])) {
     22                 return false;
     23             }
     24         }
     25 
     26         return true;
     27     },
     28     get: function (fieldName)
     29     {
     30         var ret, role, item, openingBracket, closingBracket, subEntity, index, subEntityStore;
     31 
     32         ret = this.callParent(arguments);
     33 
     34         if (ret === undefined) {
     35             // The field is undefined, attempt to retrieve data via associations
     36 
     37             if (typeof(fieldName) !== "string") {
     38                 return undefined;
     39             }
     40 
     41             var parts = fieldName.split(".");
     42 
     43             if (parts.length < 2) {
     44                 return ret;
     45             }
     46 
     47             if (this.associations[parts[0]] && this.getFieldType(parts[0]).type === "onetomany") {
     48                 role = this.associations[parts[0]];
     49                 item = role.getAssociatedItem(this);
     50 
     51                 if (item !== null) {
     52                     parts.shift();
     53                     return item.get(parts.join("."));
     54                 }
     55             } else {
     56                 openingBracket = parts[0].indexOf("[");
     57 
     58                 if (openingBracket !== -1) {
     59                     subEntity = parts[0].substring(0, openingBracket);
     60                     closingBracket = parts[0].indexOf("]", openingBracket);
     61                     index = parts[0].substring(openingBracket+1, closingBracket);
     62                 }
     63                 else {
     64                     // No index was passed for retrieving this field, try to return the first array member
     65                     subEntity = parts[0];
     66                     index = 0;    
     67                 }
     68 
     69                 subEntityStore = this[this.associations[subEntity].role]();
     70                 item = subEntityStore.getAt(index);
     71 
     72                 if (item !== null) {
     73                     parts.shift();
     74                     return item.get(parts.join("."));
     75                 }
     76             }
     77         }
     78         return ret;
     79     },
     80     /**
     81      * Returns the field type for a given field path as an object with the following properties:
     82      *
     83      * {
     84      *  type: "field", "onetomany" or "manytoone"
     85      *  reference: Only set if the type is "onetomany" or "manytoone" - holds the class name for the relation
     86      * }
     87      */
     88     getFieldType: function (fieldName)
     89     {
     90         var ret = null, role, tmp, i;
     91 
     92         for (i=0;i<this.fields.length;i++) {
     93             if (this.fields[i].getName() === fieldName) {
     94                 if (this.fields[i].reference !== null) {
     95                     return {
     96                         type: "onetomany",
     97                         reference: this.fields[i].reference
     98                     };
     99                 } else {
    100                     ret = {
    101                         type: "field"
    102                     };
    103                 }
    104             }
    105         }
    106 
    107         if (this.associations[fieldName]) {
    108             return {
    109                 type: "manytoone",
    110                 reference: this.associations[fieldName].type
    111             };
    112         }
    113 
    114         if (ret === null) {
    115             // The field is undefined, attempt to retrieve data via associations
    116             var parts = fieldName.split(".");
    117 
    118             if (parts.length < 2) {
    119                 return null;
    120             }
    121 
    122             for (i=0;i<this.fields.length;i++) {
    123                 if (this.fields[i].getName() === parts[0]) {
    124                     parts.shift();
    125                     tmp = Ext.create(this.fields[i].reference.type);
    126                     return tmp.getFieldType(parts.join("."));
    127                 }
    128             }
    129 
    130             if (this.associations[parts[0]]) {
    131                 role = this.associations[parts[0]];
    132                 tmp = Ext.create(role.type);
    133                 parts.shift();
    134                 return tmp.getFieldType(parts.join("."));
    135             }
    136         }
    137         return ret;
    138     },
    139     /**
    140      * Gets all of the data from this Models *loaded* associations. It does this
    141      * recursively. For example if we have a User which hasMany Orders, and each Order
    142      * hasMany OrderItems, it will return an object like this:
    143      *
    144      *     {
    145      *         orders: [
    146      *             {
    147      *                 id: 123,
    148      *                 status: 'shipped',
    149      *                 orderItems: [
    150      *                     ...
    151      *                 ]
    152      *             }
    153      *         ]
    154      *     }
    155      *
    156      * @param {Object} [result] The object on to which the associations will be added. If
    157      * no object is passed one is created. This object is then returned.
    158      * @param {Boolean/Object} [options] An object containing options describing the data
    159      * desired.
    160      * @param {Boolean} [options.associated=true] Pass `true` to include associated data from
    161      * other associated records.
    162      * @param {Boolean} [options.changes=false] Pass `true` to only include fields that
    163      * have been modified. Note that field modifications are only tracked for fields that
    164      * are not declared with `persist` set to `false`. In other words, only persistent
    165      * fields have changes tracked so passing `true` for this means `options.persist` is
    166      * redundant.
    167      * @param {Boolean} [options.critical] Pass `true` to include fields set as `critical`.
    168      * This is only meaningful when `options.changes` is `true` since critical fields may
    169      * not have been modified.
    170      * @param {Boolean} [options.persist] Pass `true` to only return persistent fields.
    171      * This is implied when `options.changes` is set to `true`.
    172      * @param {Boolean} [options.serialize=false] Pass `true` to invoke the `serialize`
    173      * method on the returned fields.
    174      * @return {Object} The nested data set for the Model's loaded associations.
    175      */
    176     getAssociatedData: function (result, options)
    177     {
    178         var me = this,
    179             associations = me.associations,
    180             deep, i, item, items, itemData, length,
    181             record, role, roleName, opts, clear, associated;
    182 
    183         result = result || {};
    184 
    185         me.$gathering = 1;
    186 
    187         if (options) {
    188             options = Ext.Object.chain(options);
    189         }
    190 
    191         for (roleName in associations) {
    192             role = associations[roleName];
    193 
    194             item = role.getAssociatedItem(me);
    195             if (!item || item.$gathering) {
    196                 continue;
    197             }
    198 
    199             if (item.isStore) {
    200                 item.$gathering = 1;
    201 
    202                 items = item.getData().items; // get the records for the store
    203                 length = items.length;
    204                 itemData = [];
    205 
    206                 for (i = 0; i < length; ++i) {
    207                     // NOTE - we don't check whether the record is gathering here because
    208                     // we cannot remove it from the store (it would invalidate the index
    209                     // values and misrepresent the content). Instead we tell getData to
    210                     // only get the fields vs descend further.
    211                     record = items[i];
    212                     deep = !record.$gathering;
    213                     record.$gathering = 1;
    214                     if (options) {
    215                         associated = options.associated;
    216                         if (associated === undefined) {
    217                             options.associated = deep;
    218                             clear = true;
    219                         } else {
    220                             if (!deep) {
    221                                 options.associated = false;
    222                                 clear = true;
    223                             }
    224                         }
    225                         opts = options;
    226                     } else {
    227                         opts = deep ? me._getAssociatedOptions : me._getNotAssociatedOptions;
    228                     }
    229                     itemData.push(record.getData(opts));
    230                     if (clear) {
    231                         options.associated = associated;
    232                         clear = false;
    233                     }
    234                     delete record.$gathering;
    235                 }
    236 
    237                 delete item.$gathering;
    238             } else {
    239                 opts = options || me._getAssociatedOptions;
    240                 if (options && options.associated === undefined) {
    241                     opts.associated = true;
    242                 }
    243 
    244                 if (this.getField(roleName) !== null && this.getField(roleName).byReference) {
    245                     itemData = item.getId();
    246                 } else {
    247                     itemData = item.getData(opts);
    248                 }
    249             }
    250 
    251             result[roleName] = itemData;
    252         }
    253 
    254         delete me.$gathering;
    255 
    256         return result;
    257     },
    258 
    259     /**
    260      * Returns data from all associations
    261      *
    262      * @return {Object} An object containing the associations as properties
    263      */
    264     getAssociationData: function ()
    265     {
    266         var roleName, values = [], role, item, store;
    267 
    268         for (roleName in this.associations) {
    269             role = this.associations[roleName];
    270             item = role.getAssociatedItem(this);
    271             if (!item || item.$gathering) {
    272                 continue;
    273             }
    274 
    275             var getterName = this.associations[roleName].getterName;
    276 
    277             if (item.isStore) {
    278                 store = this[getterName]();
    279                 values[roleName] = store.getData().items;
    280             } else {
    281                 values[roleName] = this[getterName]();
    282             }
    283         }
    284 
    285         return values;
    286     },
    287     /**
    288      * Sets data to all associations
    289      *
    290      * @param {Object} data The associations to set. Silently ignores non-existant associations.
    291      */
    292     setAssociationData: function (data)
    293     {
    294         var setterName, getterName, roleName, store, idProperty;
    295 
    296         for (roleName in data) {
    297             if (this.associations[roleName]) {
    298 
    299                 if (this.associations[roleName].isMany === true) {
    300                     getterName = this.associations[roleName].getterName;
    301                     store = this[getterName]();
    302 
    303                     for (var i = 0; i < data[roleName].length; i++) {
    304                         // Delete existing IDs for duplicated data
    305                         if (data[roleName][i].isEntity) {
    306                             idProperty = data[roleName][i].idProperty;
    307                             delete data[roleName][i].data[idProperty];
    308                         }
    309                     }
    310                     store.add(data[roleName]);
    311                 } else {
    312                     setterName = this.associations[roleName].setterName;
    313                     this[setterName](data[roleName]);
    314                 }
    315             }
    316         }
    317     },
    318     inheritableStatics: {
    319         callPostCollectionAction: function (action, parameters, callback, ignoreException)
    320         {
    321             var proxy = this.getProxy();
    322 
    323             proxy.callCollectionAction(action, "POST", parameters, callback, ignoreException);
    324         },
    325         callGetCollectionAction: function (action, parameters, callback, ignoreException)
    326         {
    327             var proxy = this.getProxy();
    328 
    329             proxy.callCollectionAction(action, "GET", parameters, callback, ignoreException);
    330         }
    331     }
    332 });