-
9 Nov 2012 8:54 AM #1
Answered: How can i force store commitRecords after sync in batch mode if just one record fails
Answered: How can i force store commitRecords after sync in batch mode if just one record fails
Extjs 4.1.1.a
I'm doing a store.sync() batch save
For example i save 5 records.
4 of them in php were succesfully saved and one have an error.
php returns json with success: false, data: with array of 4 successfully saves records
I need to process in failure callback of sync that the 4 records refreshed data is commit in store, because of success = false it does'nt commit any records by default.
How ?-------------------
Manel Juàrez
-
Best Answer Posted by maneljn
That's my workaround
Basically i have to return diferent structure response if succes was true or false
If success = true, i return something like this , and sync() does all store commits automatically
If success = false, i have to put the 'data' inside the 'message', because 'message' is the only thing that sync() will see with operation.getError()Code:{ "success": true, "data": [...] // an array of updated or newly created records with ids }
This is my pieces of source code working example.Code:{ "success": false, "message": [ "myerrorsmessages":[{ ....... }], "data": [...] // an array of updated or newly created records with ids ] }
The model definition
The store definitionCode://@charset UTF-8 // Modelo de datos para las direcciones Ext.define('esicontactos.model.direccion', { extend: 'Ext.data.Model', idProperty: 'dir_id', fields: [ { name: 'dir_id', type: 'integer' }, { name: 'dir_guid', type: 'string' }, { name: 'dir_contacto_id', type: 'integer' }, { name: 'dir_fiscal', type: 'boolean' }, { name: 'dir_alias', type: 'string' }, { name: 'dir_via', type: 'string' }, { name: 'dir_nom', type: 'string' }, { name: 'dir_num', type: 'integer' }, { name: 'dir_esc', type: 'string' }, { name: 'dir_pis', type: 'string' }, { name: 'dir_pue', type: 'string' }, { name: 'dir_direc1', type: 'string' }, { name: 'dir_direc2', type: 'string' }, { name: 'dir_pos', type: 'string' }, { name: 'dir_pob', type: 'string' }, { name: 'dir_pro', type: 'string' }, { name: 'dir_pais_iso3', type: 'string' }, { name: 'dir_tel1', type: 'string' }, { name: 'dir_tel2', type: 'string' }, { name: 'dir_fax', type: 'string' }, { name: 'dir_email', type: 'string' }, { name: 'dir_web', type: 'string' }, { name: 'dir_activo', type: 'boolean' }, { name: 'dir_usralta_id', type: 'integer', persist: false }, { name: 'dir_fechaalta', type: 'date', dateFormat: 'Y-m-d H:i:s', persist: false }, { name: 'dir_usrmod_id', type: 'integer', persist: false }, { name: 'dir_fechamod', type: 'date', dateFormat: 'Y-m-d H:i:s' }, // Este campo se usará para el aviso de sobreescritura en concurrencia (2 usuarios grabando en el mismo registro a la vez) { name: 'dir_usralta_nombre', type: 'string', persist: false }, { name: 'dir_usrmod_nombre', type: 'string', persist: false } ] });
The store creationCode://@charset UTF-8 // Store para las direcciones Ext.define('esicontactos.store.direcciones', { extend: 'Ext.data.Store', requires: [ 'esicontactos.model.direccion' ], constructor: function(cfg) { var me = this; cfg = cfg || {}; me.callParent([Ext.apply({ autoLoad: false, autoSync: false, buffered: false, model: 'esicontactos.model.direccion', remoteSort: true, remoteFilter: true, pageSize: 50, proxy: { type: 'direct', batchActions: true, // Al ser gestionado en una sublista permitimos hacer sync() en batch mode batchOrder: 'destroy,create,update', // Cambiamos orden por defecto para que primero haga los destroy. paramAsHash: true, extraParams: { buscar: null }, api: { read: Ext.esicontactosDirect.esicontactos_direcciones.getDirecciones, create: Ext.esicontactosDirect.esicontactos_direcciones.createDireccion, update: Ext.esicontactosDirect.esicontactos_direcciones.updateDireccion, destroy: Ext.esicontactosDirect.esicontactos_direcciones.destroyDireccion }, reader: { type: 'json', root: 'data', idProperty: 'dir_id', totalProperty: 'total', successProperty: 'success', messageProperty : 'message' } } }, cfg)]); } });
The controller sync()Code:me.store = Ext.create('esicontactos.store.direcciones', { storeId: Ext.id(), pageSize: -1, // Impedimos que la reordenacion haga un query en php porque perderiamos los cambios pendientes de guardar. // Al no paginar los datos se ordenara localmente sin problemas. remoteSort: false });
The php server side of create/update batch processCode:syncDirecciones: function(registroContacto, panelEdicion) { var me= this; var cto_id = registroContacto.get('cto_id'); var gridDirecciones = panelEdicion.down('esicontactos_view_direcciones_mantGrid'); var storeDirecciones = gridDirecciones.getStore(); var formulario = panelEdicion.formularioContactos; var registro = formulario.getRecord(); var mainStatusBar = panelEdicion.up('esicontactos_view_main').down('esicontactos_view_mainStatusBar[name="mainStatusBar"]'); // Comprobar si hay registros que actualizar if ( !(storeDirecciones.getModifiedRecords().length>0 || storeDirecciones.getRemovedRecords().length>0) ) { // Informar que hemos completado correctamente la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', true); return true; } // Si el contacto era nuevo y aun no se habia guardado por primera vez hay que poner el contacto_id en las direcciones if ( panelEdicion.modo=="nuevo" ) { var regsModificadosoNuevos = storeDirecciones.getModifiedRecords(); for (var i=0; i<regsModificadosoNuevos.length; i++) { regsModificadosoNuevos[i].set('dir_contacto_id',cto_id); } var regsBorrados = storeDirecciones.getRemovedRecords(); // No haria falta ponerlo en los borrados. for (var i=0; i<regsBorrados.length; i++) { regsBorrados[i].set('dir_contacto_id',cto_id); } } // Mostrar "guardando" en barra de estado if (mainStatusBar) { mainStatusBar.setStatus({ text: gt.dgettext('esicontactos','Guardando registro ... ') + registroContacto.get('cto_nombre_fiscal') + ' ' + gt.dgettext('esicontactos','direcciones ... '), iconCls: 'x-status-busy', clear: false }); } // Mostrar mascara panelEdicion.getEl().mask(gt.dgettext('esicontactos','Guardando direcciones ...')); // Ejecutar el sync del store (lanza en modo batch todos los destroy, create y update a través del proxy de forma asincrona) storeDirecciones.sync({ // operaciones crud todas correctas success: function(batch, options) { // Limpiar barra de estado if (mainStatusBar) { mainStatusBar.clearStatus({ useDefaults:true, anim: false }); } panelEdicion.getEl().unmask(); // Informar que hemos completado correctamente la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', true); }, // Alguna operacion crud con fallos failure: function(batch, options) { // Limpiar barra de estado if (mainStatusBar) { mainStatusBar.clearStatus({ useDefaults:true, anim: false }); } panelEdicion.getEl().unmask(); // Cadena con el mensaje de error a mostrar var mensajeError = null; // Recorrer resultados de las operaciones crud generadas automaticamente por sync() for (var i=0; i<batch.operations.length; i++) { var operacion = batch.operations[i]; // Error en la operacion (solo puede ser create, update o destroy) if (operacion.hasException()) { // Obtener registros que han generado la operacion. var registrosOperacion = operacion.getRecords(); // Si solo se mandó un registro el único error posible no viene en un array sino en un string directo if (registrosOperacion.length==1 || (typeof operacion.getError())=="string") { var registroOperacion = registrosOperacion[0]; if (registroOperacion) { // Si la accion era borrar y ha fallado volver a poner el registro borrado en el store if (operacion.action=='destroy') { storeDirecciones.add(registroOperacion); } // Montar cadena mensaje de error mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Dirección:') + ' ' + registroOperacion.get('dir_alias') + '<br />' + operacion.getError(); } } else { // Si se mandaron multiples registros aunque solo haya un error viene en un array con 2 partes // php $respuesta['message']['errores'] array de mensajes de error // php $respuesta['message']['data'] registros refrescados despues de procesar o con el valor original si han fallado // obtener array de mensajes de error si los hay (en sync batch mode sera un array con estas keys 'indexRegOpe', 'errorNum' , 'errorMsg', 'message' var mensajesErrorOperacion = operacion.getError().errores; // Montar cadena error y recuperar borrados que han fallado if (mensajesErrorOperacion==null || mensajesErrorOperacion.length<=0) { mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Error al guardar las direcciones.') +' ('+operacion.action+')'; } else { // Bucle para montar el mensaje de error for (var j=0; j<mensajesErrorOperacion.length; j++) { if (typeof mensajesErrorOperacion[j]['indexRegOpe'] != "undefined") { if ( mensajesErrorOperacion[j]['indexRegOpe']>=0 && mensajesErrorOperacion[j]['indexRegOpe']<registrosOperacion.length) { // Coger el registro original que corresponde al error recibido var registroOperacion = registrosOperacion[ mensajesErrorOperacion[j]['indexRegOpe'] ]; if (registroOperacion) { // Si la accion era borrar y ha fallado volver a poner el registro borrado en el store if (operacion.action=='destroy') { storeDirecciones.add(registroOperacion); } // Montar cadena mensaje de error mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Dirección:') + ' ' + registroOperacion.get('dir_alias') + '<br />' + mensajesErrorOperacion[j]['message']; } } } } } // Aunque haya errores actualizamos los otros registros en create y update // que si hayan ido bien y han devuelto el data refrescado // php $respuesta['message']['data'] registros refrescados despues de procesar o con el valor original si han fallado var dataRespuestaOperacion = operacion.getError().data; if (dataRespuestaOperacion) { var registrosRespuestaOperacion = storeDirecciones.getProxy().getReader().read(dataRespuestaOperacion).records; if ((operacion.action=='create' || operacion.action=='update') && registrosRespuestaOperacion) { // Recorremos todos los registros originales enviados en la operacion para ver si se pueden actualizar // con su homonimo recibido del php for (var r=0; r<registrosOperacion.length; r++) { // Mirar si el index r no esta entre los registros que tiene error var regConError = false; for (var j=0; j<mensajesErrorOperacion.length; j++) { if ( mensajesErrorOperacion[j]['indexRegOpe']==r) { regConError = true; break; } } if (!regConError) { var registroOperacion = registrosOperacion[r]; var registroRespuestaOperacion = registrosRespuestaOperacion[r]; if (registroOperacion && registroRespuestaOperacion) { // Si el registro original no es nuevo (phantom), asegurarse que los ids coinciden entre el registro original enviado y el recibido. if(registroOperacion.getId() === registroRespuestaOperacion.getId() || registroOperacion.phantom ) { registroOperacion.copyFrom(registroRespuestaOperacion); registroOperacion.commit(); } } } } } } // Fin commits } // Fin varios registros } // Fin tiene algun error operacion } // Fin bucle operaciones // Se muestra un solo mensaje de error con los textos de todas las operaciones if (mensajeError) { Ext.Msg.show({ title: gt.dgettext('esicontactos','Direcciones'), msg: mensajeError, buttons: Ext.Msg.OK, icon: Ext.Msg.WARNING }); } // Puesto que si falla algun borrar se reagrega el registro al store, limpiamos el array de borrados para el siguiente sync. storeDirecciones.removed = []; // Informar que hemos completado con errores la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', false); } }); }
Like this i can send some sync() actions: multiple creates, updates, deletes and refresh/commit in store all the records that went good, and show all the error messages from all operations.Code:public static function guardarBatchDireccion( $modo, $_parametros) { // Cuando se usa el sync() del store en batchActions=true se reciben todos los CREATEs y UPDATEs en un solo POST // y los parametros vienen en un array de objetos. // Sistema sync() batch mode (bucle) $respuestaData = null; $respuestaErrores = null; foreach($_parametros as $indexRegOpe => $_parametrosRegistro) { $respuestaRegistro = self::guardarDireccion( $modo, $_parametrosRegistro ); if (!$respuestaRegistro['success']) { $respuestaErrores[] = array( 'indexRegOpe' => $indexRegOpe, // Indicamos en que registro origen se produjo el error de proceso 'errorNum' => (isset($respuestaRegistro['errorNum']) ? $respuestaRegistro['errorNum'] : null), 'errorMsg' => (isset($respuestaRegistro['errorMsg']) ? $respuestaRegistro['errorMsg'] : null), 'message' => (isset($respuestaRegistro['message']) ? $respuestaRegistro['message'] : null) ); } // Nos autoobligamos por la estructuracion de los eventos succes i failure del sync en extjs receptor // a devolver siempre el mismo número de registros recibidos para procesar en el mismo orden. // Si tenemos datos refrescados ponemos los refrescados, y sino por error o cualquier otro motivo // ponemos el registro original. if (isset($respuestaRegistro['data'][0])) { $respuestaData[] = $respuestaRegistro['data'][0]; } else { $respuestaData[] = $_parametrosRegistro; } } // El formato de respuesta serà distinto si és succes true o false // Para true, anadimos el array ['data'] con los registros a devolver. // En la parte cliente extjs el sync hace los commits en el store automàticamente. // Si es false, tenemos que colar el ['data'] dentro del message que es lo único que procesa el sync () con el evento failure // y así en la parte cliente se pueden actualizar los registros que si que han sido correctos, mostrando error en los otros. if (count($respuestaErrores)>0) { $respuesta['success'] = false; $respuesta['errores'] = count($respuestaErrores); $respuesta['message']['errores'] = $respuestaErrores; $respuesta['message']['data'] = $respuestaData; } else { $respuesta['success'] = true; $respuesta['data'] = $respuestaData; } return $respuesta; }
-
9 Nov 2012 6:50 PM #2
For updating/creating requests if you return successful response then all newly created/modified records will be committed, if you return failed response then all records will not be committed. So with your case, I think you have to process the response and do the committing records by yourself. You can do this by some ways:
- Defining callbacks for store.sync():
- Defining onCreateRecords, onUpdateRecords for the store:Code:store.sync({ success: function(batch, options){ ... }, failure: function(batch, options){ ... } })
- Defining listeners for 'exception' event on store proxy.Code:var store = Ext.create('Ext.data.Store', { ... onCreateRecords: function(records, operation, success){ ... }, onUpdateRecords: function(records, operation, success){ ... } });
- etc
-
10 Nov 2012 7:41 AM #3
That's my workaround
Basically i have to return diferent structure response if succes was true or false
If success = true, i return something like this , and sync() does all store commits automatically
If success = false, i have to put the 'data' inside the 'message', because 'message' is the only thing that sync() will see with operation.getError()Code:{ "success": true, "data": [...] // an array of updated or newly created records with ids }
This is my pieces of source code working example.Code:{ "success": false, "message": [ "myerrorsmessages":[{ ....... }], "data": [...] // an array of updated or newly created records with ids ] }
The model definition
The store definitionCode://@charset UTF-8 // Modelo de datos para las direcciones Ext.define('esicontactos.model.direccion', { extend: 'Ext.data.Model', idProperty: 'dir_id', fields: [ { name: 'dir_id', type: 'integer' }, { name: 'dir_guid', type: 'string' }, { name: 'dir_contacto_id', type: 'integer' }, { name: 'dir_fiscal', type: 'boolean' }, { name: 'dir_alias', type: 'string' }, { name: 'dir_via', type: 'string' }, { name: 'dir_nom', type: 'string' }, { name: 'dir_num', type: 'integer' }, { name: 'dir_esc', type: 'string' }, { name: 'dir_pis', type: 'string' }, { name: 'dir_pue', type: 'string' }, { name: 'dir_direc1', type: 'string' }, { name: 'dir_direc2', type: 'string' }, { name: 'dir_pos', type: 'string' }, { name: 'dir_pob', type: 'string' }, { name: 'dir_pro', type: 'string' }, { name: 'dir_pais_iso3', type: 'string' }, { name: 'dir_tel1', type: 'string' }, { name: 'dir_tel2', type: 'string' }, { name: 'dir_fax', type: 'string' }, { name: 'dir_email', type: 'string' }, { name: 'dir_web', type: 'string' }, { name: 'dir_activo', type: 'boolean' }, { name: 'dir_usralta_id', type: 'integer', persist: false }, { name: 'dir_fechaalta', type: 'date', dateFormat: 'Y-m-d H:i:s', persist: false }, { name: 'dir_usrmod_id', type: 'integer', persist: false }, { name: 'dir_fechamod', type: 'date', dateFormat: 'Y-m-d H:i:s' }, // Este campo se usará para el aviso de sobreescritura en concurrencia (2 usuarios grabando en el mismo registro a la vez) { name: 'dir_usralta_nombre', type: 'string', persist: false }, { name: 'dir_usrmod_nombre', type: 'string', persist: false } ] });
The store creationCode://@charset UTF-8 // Store para las direcciones Ext.define('esicontactos.store.direcciones', { extend: 'Ext.data.Store', requires: [ 'esicontactos.model.direccion' ], constructor: function(cfg) { var me = this; cfg = cfg || {}; me.callParent([Ext.apply({ autoLoad: false, autoSync: false, buffered: false, model: 'esicontactos.model.direccion', remoteSort: true, remoteFilter: true, pageSize: 50, proxy: { type: 'direct', batchActions: true, // Al ser gestionado en una sublista permitimos hacer sync() en batch mode batchOrder: 'destroy,create,update', // Cambiamos orden por defecto para que primero haga los destroy. paramAsHash: true, extraParams: { buscar: null }, api: { read: Ext.esicontactosDirect.esicontactos_direcciones.getDirecciones, create: Ext.esicontactosDirect.esicontactos_direcciones.createDireccion, update: Ext.esicontactosDirect.esicontactos_direcciones.updateDireccion, destroy: Ext.esicontactosDirect.esicontactos_direcciones.destroyDireccion }, reader: { type: 'json', root: 'data', idProperty: 'dir_id', totalProperty: 'total', successProperty: 'success', messageProperty : 'message' } } }, cfg)]); } });
The controller sync()Code:me.store = Ext.create('esicontactos.store.direcciones', { storeId: Ext.id(), pageSize: -1, // Impedimos que la reordenacion haga un query en php porque perderiamos los cambios pendientes de guardar. // Al no paginar los datos se ordenara localmente sin problemas. remoteSort: false });
The php server side of create/update batch processCode:syncDirecciones: function(registroContacto, panelEdicion) { var me= this; var cto_id = registroContacto.get('cto_id'); var gridDirecciones = panelEdicion.down('esicontactos_view_direcciones_mantGrid'); var storeDirecciones = gridDirecciones.getStore(); var formulario = panelEdicion.formularioContactos; var registro = formulario.getRecord(); var mainStatusBar = panelEdicion.up('esicontactos_view_main').down('esicontactos_view_mainStatusBar[name="mainStatusBar"]'); // Comprobar si hay registros que actualizar if ( !(storeDirecciones.getModifiedRecords().length>0 || storeDirecciones.getRemovedRecords().length>0) ) { // Informar que hemos completado correctamente la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', true); return true; } // Si el contacto era nuevo y aun no se habia guardado por primera vez hay que poner el contacto_id en las direcciones if ( panelEdicion.modo=="nuevo" ) { var regsModificadosoNuevos = storeDirecciones.getModifiedRecords(); for (var i=0; i<regsModificadosoNuevos.length; i++) { regsModificadosoNuevos[i].set('dir_contacto_id',cto_id); } var regsBorrados = storeDirecciones.getRemovedRecords(); // No haria falta ponerlo en los borrados. for (var i=0; i<regsBorrados.length; i++) { regsBorrados[i].set('dir_contacto_id',cto_id); } } // Mostrar "guardando" en barra de estado if (mainStatusBar) { mainStatusBar.setStatus({ text: gt.dgettext('esicontactos','Guardando registro ... ') + registroContacto.get('cto_nombre_fiscal') + ' ' + gt.dgettext('esicontactos','direcciones ... '), iconCls: 'x-status-busy', clear: false }); } // Mostrar mascara panelEdicion.getEl().mask(gt.dgettext('esicontactos','Guardando direcciones ...')); // Ejecutar el sync del store (lanza en modo batch todos los destroy, create y update a través del proxy de forma asincrona) storeDirecciones.sync({ // operaciones crud todas correctas success: function(batch, options) { // Limpiar barra de estado if (mainStatusBar) { mainStatusBar.clearStatus({ useDefaults:true, anim: false }); } panelEdicion.getEl().unmask(); // Informar que hemos completado correctamente la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', true); }, // Alguna operacion crud con fallos failure: function(batch, options) { // Limpiar barra de estado if (mainStatusBar) { mainStatusBar.clearStatus({ useDefaults:true, anim: false }); } panelEdicion.getEl().unmask(); // Cadena con el mensaje de error a mostrar var mensajeError = null; // Recorrer resultados de las operaciones crud generadas automaticamente por sync() for (var i=0; i<batch.operations.length; i++) { var operacion = batch.operations[i]; // Error en la operacion (solo puede ser create, update o destroy) if (operacion.hasException()) { // Obtener registros que han generado la operacion. var registrosOperacion = operacion.getRecords(); // Si solo se mandó un registro el único error posible no viene en un array sino en un string directo if (registrosOperacion.length==1 || (typeof operacion.getError())=="string") { var registroOperacion = registrosOperacion[0]; if (registroOperacion) { // Si la accion era borrar y ha fallado volver a poner el registro borrado en el store if (operacion.action=='destroy') { storeDirecciones.add(registroOperacion); } // Montar cadena mensaje de error mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Dirección:') + ' ' + registroOperacion.get('dir_alias') + '<br />' + operacion.getError(); } } else { // Si se mandaron multiples registros aunque solo haya un error viene en un array con 2 partes // php $respuesta['message']['errores'] array de mensajes de error // php $respuesta['message']['data'] registros refrescados despues de procesar o con el valor original si han fallado // obtener array de mensajes de error si los hay (en sync batch mode sera un array con estas keys 'indexRegOpe', 'errorNum' , 'errorMsg', 'message' var mensajesErrorOperacion = operacion.getError().errores; // Montar cadena error y recuperar borrados que han fallado if (mensajesErrorOperacion==null || mensajesErrorOperacion.length<=0) { mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Error al guardar las direcciones.') +' ('+operacion.action+')'; } else { // Bucle para montar el mensaje de error for (var j=0; j<mensajesErrorOperacion.length; j++) { if (typeof mensajesErrorOperacion[j]['indexRegOpe'] != "undefined") { if ( mensajesErrorOperacion[j]['indexRegOpe']>=0 && mensajesErrorOperacion[j]['indexRegOpe']<registrosOperacion.length) { // Coger el registro original que corresponde al error recibido var registroOperacion = registrosOperacion[ mensajesErrorOperacion[j]['indexRegOpe'] ]; if (registroOperacion) { // Si la accion era borrar y ha fallado volver a poner el registro borrado en el store if (operacion.action=='destroy') { storeDirecciones.add(registroOperacion); } // Montar cadena mensaje de error mensajeError = (mensajeError==null ? '' : mensajeError + '<br />') + gt.dgettext('esicontactos','Dirección:') + ' ' + registroOperacion.get('dir_alias') + '<br />' + mensajesErrorOperacion[j]['message']; } } } } } // Aunque haya errores actualizamos los otros registros en create y update // que si hayan ido bien y han devuelto el data refrescado // php $respuesta['message']['data'] registros refrescados despues de procesar o con el valor original si han fallado var dataRespuestaOperacion = operacion.getError().data; if (dataRespuestaOperacion) { var registrosRespuestaOperacion = storeDirecciones.getProxy().getReader().read(dataRespuestaOperacion).records; if ((operacion.action=='create' || operacion.action=='update') && registrosRespuestaOperacion) { // Recorremos todos los registros originales enviados en la operacion para ver si se pueden actualizar // con su homonimo recibido del php for (var r=0; r<registrosOperacion.length; r++) { // Mirar si el index r no esta entre los registros que tiene error var regConError = false; for (var j=0; j<mensajesErrorOperacion.length; j++) { if ( mensajesErrorOperacion[j]['indexRegOpe']==r) { regConError = true; break; } } if (!regConError) { var registroOperacion = registrosOperacion[r]; var registroRespuestaOperacion = registrosRespuestaOperacion[r]; if (registroOperacion && registroRespuestaOperacion) { // Si el registro original no es nuevo (phantom), asegurarse que los ids coinciden entre el registro original enviado y el recibido. if(registroOperacion.getId() === registroRespuestaOperacion.getId() || registroOperacion.phantom ) { registroOperacion.copyFrom(registroRespuestaOperacion); registroOperacion.commit(); } } } } } } // Fin commits } // Fin varios registros } // Fin tiene algun error operacion } // Fin bucle operaciones // Se muestra un solo mensaje de error con los textos de todas las operaciones if (mensajeError) { Ext.Msg.show({ title: gt.dgettext('esicontactos','Direcciones'), msg: mensajeError, buttons: Ext.Msg.OK, icon: Ext.Msg.WARNING }); } // Puesto que si falla algun borrar se reagrega el registro al store, limpiamos el array de borrados para el siguiente sync. storeDirecciones.removed = []; // Informar que hemos completado con errores la tarea de guardar las direcciones para el multiguardar me.completarMultiGuardar(registroContacto, panelEdicion, 'direcciones', false); } }); }
Like this i can send some sync() actions: multiple creates, updates, deletes and refresh/commit in store all the records that went good, and show all the error messages from all operations.Code:public static function guardarBatchDireccion( $modo, $_parametros) { // Cuando se usa el sync() del store en batchActions=true se reciben todos los CREATEs y UPDATEs en un solo POST // y los parametros vienen en un array de objetos. // Sistema sync() batch mode (bucle) $respuestaData = null; $respuestaErrores = null; foreach($_parametros as $indexRegOpe => $_parametrosRegistro) { $respuestaRegistro = self::guardarDireccion( $modo, $_parametrosRegistro ); if (!$respuestaRegistro['success']) { $respuestaErrores[] = array( 'indexRegOpe' => $indexRegOpe, // Indicamos en que registro origen se produjo el error de proceso 'errorNum' => (isset($respuestaRegistro['errorNum']) ? $respuestaRegistro['errorNum'] : null), 'errorMsg' => (isset($respuestaRegistro['errorMsg']) ? $respuestaRegistro['errorMsg'] : null), 'message' => (isset($respuestaRegistro['message']) ? $respuestaRegistro['message'] : null) ); } // Nos autoobligamos por la estructuracion de los eventos succes i failure del sync en extjs receptor // a devolver siempre el mismo número de registros recibidos para procesar en el mismo orden. // Si tenemos datos refrescados ponemos los refrescados, y sino por error o cualquier otro motivo // ponemos el registro original. if (isset($respuestaRegistro['data'][0])) { $respuestaData[] = $respuestaRegistro['data'][0]; } else { $respuestaData[] = $_parametrosRegistro; } } // El formato de respuesta serà distinto si és succes true o false // Para true, anadimos el array ['data'] con los registros a devolver. // En la parte cliente extjs el sync hace los commits en el store automàticamente. // Si es false, tenemos que colar el ['data'] dentro del message que es lo único que procesa el sync () con el evento failure // y así en la parte cliente se pueden actualizar los registros que si que han sido correctos, mostrando error en los otros. if (count($respuestaErrores)>0) { $respuesta['success'] = false; $respuesta['errores'] = count($respuestaErrores); $respuesta['message']['errores'] = $respuestaErrores; $respuesta['message']['data'] = $respuestaData; } else { $respuesta['success'] = true; $respuesta['data'] = $respuestaData; } return $respuesta; }-------------------
Manel Juàrez


Reply With Quote