1 // ========================================================================== 2 // Project: The M-Project - Mobile HTML5 Application Framework 3 // Copyright: (c) 2010 M-Way Solutions GmbH. All rights reserved. 4 // (c) 2011 panacoda GmbH. All rights reserved. 5 // Creator: Sebastian 6 // Date: 02.12.2010 7 // License: Dual licensed under the MIT or GPL Version 2 licenses. 8 // http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE 9 // http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE 10 // ========================================================================== 11 12 m_require('core/datastore/data_provider.js'); 13 14 /** 15 * @class 16 * 17 * Encapsulates access to a remote storage, a json based web service. 18 * 19 * @extends M.DataProvider 20 */ 21 M.DataProviderRemoteStorage = M.DataProvider.extend( 22 /** @scope M.RemoteStorageProvider.prototype */ { 23 24 /** 25 * The type of this object. 26 * @type String 27 */ 28 type: 'M.DataProviderRemoteStorage', 29 30 /** 31 * The type of this object. 32 * @type Object 33 */ 34 config: null, 35 36 /* CRUD methods */ 37 38 save: function(obj) { 39 40 var config = this.config[obj.model.name]; 41 var result = null; 42 var dataResult = null; 43 44 if(obj.model.state === M.STATE_NEW) { /* if the model is new we need to make a create request, if not new then we make an update request */ 45 46 dataResult = config.create.map(obj.model.record); 47 48 this.remoteQuery('create', config.url + config.create.url(obj.model.get('ID')), config.create.httpMethod, dataResult, obj, null); 49 50 } else { // make an update request 51 52 dataResult = config.update.map(obj.model.record); 53 54 var updateUrl = config.url + config.update.url(obj.model.get('ID')); 55 56 this.remoteQuery('update', updateUrl, config.update.httpMethod, dataResult, obj, function(xhr) { 57 xhr.setRequestHeader("X-Http-Method-Override", config.update.httpMethod); 58 }); 59 } 60 61 }, 62 63 del: function(obj) { 64 var config = this.config[obj.model.name]; 65 var delUrl = config.del.url(obj.model.get('ID')); 66 delUrl = config.url + delUrl; 67 68 this.remoteQuery('delete', delUrl, config.del.httpMethod, null, obj, function(xhr) { 69 xhr.setRequestHeader("X-Http-Method-Override", config.del.httpMethod); 70 }); 71 }, 72 73 find: function(obj) { 74 var config = this.config[obj.model.name]; 75 76 var readUrl = obj.ID ? config.read.url.one(obj.ID) : config.read.url.all(); 77 readUrl = config.url + readUrl; 78 79 this.remoteQuery('read', readUrl, config.read.httpMethod, null, obj); 80 81 }, 82 83 createModelsFromResult: function(data, callback, obj) { 84 var result = []; 85 var config = this.config[obj.model.name]; 86 if(_.isArray(data)) { 87 for(var i in data) { 88 var res = data[i]; 89 /* create model record from result by first map with given mapper function before passing 90 * to createRecord 91 */ 92 result.push(obj.model.createRecord($.extend(config.read.map(res), {state: M.STATE_VALID}))); 93 } 94 } else if(typeof(data) === 'object') { 95 result.push(obj.model.createRecord($.extend(config.read.map(data), {state: M.STATE_VALID}))); 96 } 97 callback(result); 98 }, 99 100 remoteQuery: function(opType, url, type, data, obj, beforeSend) { 101 var that = this; 102 var config = this.config[obj.model.name]; 103 104 M.Request.init({ 105 url: url, 106 method: type, 107 isJSON: YES, 108 contentType: 'application/JSON', 109 data: data ? data : null, 110 onSuccess: function(data, msg, xhr) { 111 112 /* 113 * delete from record manager if delete request was made. 114 */ 115 if(opType === 'delete') { 116 obj.model.recordManager.remove(obj.model.m_id); 117 } 118 119 /* 120 * call the receiveIdentifier method if provided, that sets the ID for the newly created model 121 */ 122 if(opType === 'create') { 123 if(config.create.receiveIdentifier) { 124 config.create.receiveIdentifier(data, obj.model); 125 } else { 126 M.Logger.log('No ID receiving operation defined.'); 127 } 128 } 129 130 /* 131 * call callback 132 */ 133 if(obj.onSuccess) { 134 if(obj.onSuccess.target && obj.onSuccess.action) { 135 obj.onSuccess = that.bindToCaller(obj.onSuccess.target, obj.onSuccess.target[obj.onSuccess.action], [data]); 136 if(opType === 'read') { 137 that.createModelsFromResult(data, obj.onSuccess, obj); 138 } else { 139 obj.onSuccess(); 140 } 141 } else if(typeof(obj.onSuccess) === 'function') { 142 that.createModelsFromResult(data, obj.onSuccess, obj); 143 } 144 145 }else { 146 M.Logger.log('No success callback given.', M.WARN); 147 } 148 }, 149 onError: function(xhr, msg) { 150 151 var err = M.Error.extend({ 152 code: M.ERR_CONNECTION, 153 msg: msg 154 }); 155 156 if(obj.onError && typeof(obj.onError) === 'function') { 157 obj.onError(err); 158 } 159 if(obj.onError && obj.onError.target && obj.onError.action) { 160 obj.onError = this.bindToCaller(obj.onError.target, obj.onError.target[obj.onError.action], err); 161 obj.onError(); 162 } else if (typeof(obj.onError) !== 'function') { 163 M.Logger.log('No error callback given.', M.WARN); 164 } 165 }, 166 beforeSend: beforeSend ? beforeSend : null 167 }).send(); 168 }, 169 170 /** 171 * creates a new data provider instance with the passed configuration parameters 172 * @param obj 173 */ 174 configure: function(obj) { 175 console.log('configure() called.'); 176 // maybe some value checking 177 return this.extend({ 178 config:obj 179 }); 180 } 181 182 });