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 });