Changeset 1605 for trunk/grails-app
- Timestamp:
- Mar 8, 2011, 6:04:12 PM (10 years ago)
- Location:
- trunk/grails-app
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/grails-app/controllers/dbnp/studycapturing/SimpleController.groovy
r1601 r1605 28 28 def fileService 29 29 def importerService 30 def gdtService = new GdtService() 30 def gdtService 31 def simpleService 31 32 32 33 /** … … 40 41 entry { 41 42 action{ 42 flow.study = getStudyFromRequest( params )43 flow.study = simpleService.getStudyFromRequest( params ) 43 44 if (!flow.study) retrievalError() 44 45 } … … 49 50 study { 50 51 on("next") { 51 handleStudy( flow.study, params )52 if( ! validateObject( flow.study ) )52 simpleService.handleStudy( flow.study, params ) 53 if( !simpleService.validateObject( flow.study ) ) 53 54 error() 54 55 }.to "decisionState" 55 on("refresh") { handleStudy( flow.study, params );}.to "study"56 on( "success" ) { handleStudy( flow.study, params ) }.to "study"56 on("refresh") { simpleService.handleStudy( flow.study, params ) }.to "study" 57 on( "success" ) { simpleService.handleStudy( flow.study, params ) }.to "study" 57 58 } 58 59 … … 74 75 75 76 if (flow.study.samples) 76 checkStudySimplicity(flow.study) ? existingSamples() : complexStudy()77 simpleService.checkStudySimplicity(flow.study) ? existingSamples() : complexStudy() 77 78 else 78 79 samples() … … 96 97 existingSamples { 97 98 on("next") { 98 handleExistingSamples( flow.study, params, flow ) ? success() : error()99 simpleService.handleExistingSamples( flow.study, params, flow ) ? success() : error() 99 100 }.to "startAssays" 100 101 on("previous").to "study" 101 102 on("update") { 102 handleExistingSamples( flow.study, params, flow ) ? success() : error()103 simpleService.handleExistingSamples( flow.study, params, flow ) ? success() : error() 103 104 }.to "samples" 104 105 … … 113 114 samples { 114 115 on("next") { 115 handleSamples( flow.study, params, flow ) ? success() : error ()116 simpleService.handleSamples( flow.study, params, flow ) ? success() : error () 116 117 117 118 // Add domain fields for all entities … … 140 141 columns { 141 142 on( "next" ) { 142 handleColumns( flow.study, params, flow ) ? success() : error()143 simpleService.handleColumns( flow.study, params, flow ) ? success() : error() 143 144 }.to "checkImportedEntities" 144 145 on( "previous" ).to "samples" … … 166 167 missingFields { 167 168 on( "next" ) { 168 if( ! handleMissingFields( flow.study, params ) )169 if( !simpleService.handleMissingFields( flow.study, params ) ) 169 170 error(); 170 171 … … 192 193 assays { 193 194 on( "next" ) { 194 handleAssays( flow.assay, params, flow );195 if( ! validateObject( flow.assay ) )195 simpleService.handleAssays( flow.assay, params, flow ); 196 if( !simpleService.validateObject( flow.assay ) ) 196 197 error(); 197 198 }.to "overview" … … 205 206 }.to "overview" 206 207 on( "previous" ).to "returnFromAssays" 207 on("refresh") { handleAssays( flow.assay, params, flow ); }.to "assays"208 on("refresh") { simpleService.handleAssays( flow.assay, params, flow ); }.to "assays" 208 209 } 209 210 … … 266 267 } 267 268 } 268 269 /**270 * Retrieves the required study from the database or return an empty Study object if271 * no id is given272 *273 * @param params Request parameters with params.id being the ID of the study to be retrieved274 * @return A study from the database or an empty study if no id was given275 */276 protected Study getStudyFromRequest( def params ) {277 int id = params.int( "id" );278 279 if( !id ) {280 return new Study( title: "New study", owner: authenticationService.getLoggedInUser() );281 }282 283 Study s = Study.get( id );284 285 if( !s ) {286 flash.error = "No study found with given id";287 return null;288 }289 if( !s.canWrite( authenticationService.getLoggedInUser() ) ) {290 flash.error = "No authorization to edit this study."291 return null;292 }293 294 return s295 }296 297 /**298 * Handles study input299 * @param study Study to update300 * @param params Request parameter map301 * @return True if everything went OK, false otherwise. An error message is put in flash.error302 */303 def handleStudy( study, params ) {304 // did the study template change?305 if (params.get('template') && study.template?.name != params.get('template')) {306 // set the template307 study.template = Template.findByName(params.remove('template'))308 }309 310 // does the study have a template set?311 if (study.template && study.template instanceof Template) {312 // yes, iterate through template fields313 study.giveFields().each() {314 // and set their values315 study.setFieldValue(it.name, params.get(it.escapedName()))316 }317 }318 319 // handle public checkbox320 if (params.get("publicstudy")) {321 study.publicstudy = params.get("publicstudy")322 }323 324 // handle publications325 handleStudyPublications(study, params)326 327 // handle contacts328 handleStudyContacts(study, params)329 330 // handle users (readers, writers)331 handleStudyUsers(study, params, 'readers')332 handleStudyUsers(study, params, 'writers')333 334 return true335 }336 337 /**338 * Handles the editing of existing samples339 * @param study Study to update340 * @param params Request parameter map341 * @return True if everything went OK, false otherwise. An error message is put in flash.error342 */343 def handleExistingSamples( study, params, flow ) {344 flash.validationErrors = [:];345 346 def errors = false;347 348 // iterate through objects; set field values and validate the object349 def eventgroups = study.samples.parentEventGroup.findAll { it }350 def events;351 if( !eventgroups )352 events = []353 else354 events = eventgroups.events?.getAt(0);355 356 def objects = [357 'Sample': study.samples,358 'Subject': study.samples.parentSubject.findAll { it },359 'SamplingEvent': study.samples.parentEvent.findAll { it },360 'Event': events.flatten().findAll { it }361 ];362 363 objects.each {364 def type = it.key;365 def entities = it.value;366 367 entities.each { entity ->368 // iterate through entity fields369 entity.giveFields().each() { field ->370 def value = params.get( type.toLowerCase() + '_' + entity.getIdentifier() + '_' + field.escapedName())371 372 // set field value; name cannot be set to an empty value373 if (field.name != 'name' || value) {374 log.info "setting "+field.name+" to "+value375 entity.setFieldValue(field.name, value)376 }377 }378 379 // has the template changed?380 def templateName = params.get(type.toLowerCase() + '_' + entity.getIdentifier() + '_template')381 if (templateName && entity.template?.name != templateName) {382 entity.template = Template.findByName(templateName)383 }384 385 // validate sample386 if (!entity.validate()) {387 errors = true;388 flash.validationErrors << getHumanReadableErrors( entity )389 }390 }391 }392 393 return !errors394 }395 396 /**397 * Handles the upload of sample data398 * @param study Study to update399 * @param params Request parameter map400 * @return True if everything went OK, false otherwise. An error message is put in flash.error401 */402 def handleSamples( study, params, flow ) {403 def filename = params.get( 'importfile' );404 405 // Handle 'existing*' in front of the filename. This is put in front to make a distinction between406 // an already uploaded file test.txt (maybe moved to some other directory) and a newly uploaded file test.txt407 // still being in the temporary directory.408 // This import step doesn't have to make that distinction, since all files remain in the temporary directory.409 if( filename == 'existing*' )410 filename = '';411 else if( filename[0..8] == 'existing*' )412 filename = filename[9..-1]413 414 def sampleTemplateId = params.long( 'sample_template_id' )415 def subjectTemplateId = params.long( 'subject_template_id' )416 def eventTemplateId = params.long( 'event_template_id' )417 def samplingEventTemplateId = params.long( 'samplingEvent_template_id' )418 419 // These fields have been removed from the form, so will always contain420 // their default value. The code however remains like this for future use.421 int sheetIndex = (params.int( 'sheetindex' ) ?: 1 )422 int dataMatrixStart = (params.int( 'datamatrix_start' ) ?: 2 )423 int headerRow = (params.int( 'headerrow' ) ?: 1 )424 425 // Save form data in session426 flow.sampleForm = [427 importFile: filename,428 templateId: [429 'Sample': sampleTemplateId,430 'Subject': subjectTemplateId,431 'Event': eventTemplateId,432 'SampingEvent': samplingEventTemplateId433 ],434 template: [435 'Sample': sampleTemplateId ? Template.get( sampleTemplateId ) : null,436 'Subject': subjectTemplateId ? Template.get( subjectTemplateId ) : null,437 'Event': eventTemplateId ? Template.get( eventTemplateId ) : null,438 'SampingEvent': samplingEventTemplateId ? Template.get( samplingEventTemplateId ) : null439 ],440 sheetIndex: sheetIndex,441 dataMatrixStart: dataMatrixStart,442 headerRow: headerRow443 ];444 445 // Check whether the template exists446 if (!sampleTemplateId || !Template.get( sampleTemplateId ) ){447 log.error ".simple study wizard not all fields are filled in: " + sampleTemplateId448 flash.error = "No template was chosen. Please choose a template for the samples you provided."449 return false450 }451 452 def importedfile = fileService.get( filename )453 def workbook454 if (importedfile.exists()) {455 try {456 workbook = importerService.getWorkbook(new FileInputStream(importedfile))457 } catch (Exception e) {458 log.error ".simple study wizard could not load file: " + e459 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";460 return false461 }462 } else {463 log.error ".simple study wizard no file given";464 flash.error = "No file was given. Please provide an excel file for entering samples.";465 return false;466 }467 468 if( !workbook ) {469 log.error ".simple study wizard could not load file into a workbook"470 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";471 return false472 }473 474 def selectedentities = []475 476 if( !excelChecks( workbook, sheetIndex, headerRow, dataMatrixStart ) )477 return false;478 479 // Get the header from the Excel file using the arguments given in the first step of the wizard480 def importerHeader;481 def importerDataMatrix;482 483 try {484 importerHeader = importerService.getHeader(workbook,485 sheetIndex - 1, // 0 == first sheet486 headerRow, // 1 == first row :s487 dataMatrixStart - 1, // 0 == first row488 Sample.class)489 490 importerDataMatrix = importerService.getDatamatrix(491 workbook,492 importerHeader,493 sheetIndex - 1, // 0 == first sheet494 dataMatrixStart - 1, // 0 == first row495 5)496 } catch( Exception e ) {497 // An error occurred while reading the excel file.498 log.error ".simple study wizard error while reading the excel file";499 e.printStackTrace();500 501 // Show a message to the user502 flash.error = "An error occurred while reading the excel file. Have you provided the right sheet number and row numbers. Contact your system administrator if this problem persists.";503 return false;504 }505 506 // Save read excel data into session507 def dataMatrix = [];508 def df = new DataFormatter();509 importerDataMatrix.each {510 dataMatrix << it.collect{ it ? df.formatCellValue(it) : "" }511 }512 513 flow.excel = [514 filename: filename,515 sheetIndex: sheetIndex,516 dataMatrixStart: dataMatrixStart,517 headerRow: headerRow,518 data: [519 header: importerHeader,520 dataMatrix: dataMatrix521 ]522 ]523 524 return true525 }526 527 528 /**529 * Handles the matching of template fields with excel columns by the user530 * @param study Study to update531 * @param params Request parameter map532 * @return True if everything went OK, false otherwise. An error message is put in flash.error533 * The field session.simpleWizard.imported.numInvalidEntities reflects the number of534 * entities that have errors, and should be fixed before saving. The errors for those entities535 * are saved into session.simpleWizard.imported.errors536 */537 def handleColumns( study, params, flow ) {538 // Find actual Template object from the chosen template name539 def templates = [:];540 flow.sampleForm.templateId.each {541 templates[ it.key ] = it.value ? Template.get( it.value ) : null;542 }543 544 def headers = flow.excel.data.header;545 546 if( !params.matches ) {547 log.error( ".simple study wizard no column matches given" );548 flash.error = "No column matches given";549 return false;550 }551 552 // Retrieve the chosen matches from the request parameters and put them into553 // the headers-structure, for later reference554 params.matches.index.each { columnindex, value ->555 // Determine the entity and property by splitting it556 def parts = value.toString().tokenize( "||" );557 558 def property559 def entityName560 if( parts.size() > 1 ) {561 property = parts[ 1 ];562 entityName = "dbnp.studycapturing." + parts[ 0 ];563 } else if( parts.size() == 1 ) {564 property = parts[ 0 ];565 entityName = headers[columnindex.toInteger()].entityclass.getName();566 }567 568 // Create an actual class instance of the selected entity with the selected template569 // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities570 def entityClass = Class.forName( entityName, true, this.getClass().getClassLoader())571 def entityObj = entityClass.newInstance(template: templates[ entityName[entityName.lastIndexOf( '.' ) + 1..-1] ])572 573 headers[ columnindex.toInteger() ].entityclass = entityClass574 575 // Store the selected property for this column into the column map for the ImporterService576 headers[columnindex.toInteger()].property = property577 578 // Look up the template field type of the target TemplateField and store it also in the map579 headers[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property)580 581 // Is a "Don't import" property assigned to the column?582 headers[columnindex.toInteger()].dontimport = (property == "dontimport") ? true : false583 584 //if it's an identifier set the mapping column true or false585 entityClass.giveDomainFields().each {586 headers[columnindex.toInteger()].identifier = ( it.preferredIdentifier && (it.name == property) )587 }588 }589 590 // Import the workbook and store the table with entity records and store the failed cells591 println "Importing samples for study " + study + " (" + study.id + ")";592 593 def importedfile = fileService.get( flow.excel.filename )594 def workbook595 if (importedfile.exists()) {596 try {597 workbook = importerService.getWorkbook(new FileInputStream(importedfile))598 } catch (Exception e) {599 log.error ".simple study wizard could not load file: " + e600 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";601 return false602 }603 } else {604 log.error ".simple study wizard no file given";605 flash.error = "No file was given. Please provide an excel file for entering samples.";606 return false;607 }608 609 if( !workbook ) {610 log.error ".simple study wizard could not load file into a workbook"611 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";612 return false613 }614 615 616 def imported = importerService.importOrUpdateDataBySampleIdentifier(templates,617 workbook,618 flow.excel.sheetIndex - 1,619 flow.excel.dataMatrixStart - 1,620 flow.excel.data.header,621 flow.study,622 true // Also create entities for which no data is imported but where templates were chosen623 );624 625 def table = imported.table626 def failedcells = imported.failedCells627 628 flow.imported = [629 data: table,630 failedCells: failedcells631 ];632 633 // loop through all entities to validate them and add them to failedcells if an error occurs634 def numInvalidEntities = 0;635 def errors = [];636 637 // Add all samples638 table.each { record ->639 record.each { entity ->640 if( entity ) {641 // Determine entity class and add a parent642 def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );643 def equalClosure = { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) }644 645 entity.parent = study646 647 switch( entity.class ) {648 case Sample:649 if( preferredIdentifier && !study.samples?.find( equalClosure ) ) {650 study.addToSamples( entity );651 }652 break;653 case Subject:654 if( preferredIdentifier && !study.subjects?.find( equalClosure ) ) {655 study.addToSubjects( entity );656 }657 break;658 case Event:659 if( preferredIdentifier && !study.events?.find( equalClosure ) ) {660 study.addToEvents( entity );661 }662 break;663 case SamplingEvent:664 if( preferredIdentifier && !study.samplingEvents?.find( equalClosure ) ) {665 study.addToSamplingEvents( entity );666 }667 break;668 }669 670 if (!entity.validate()) {671 numInvalidEntities++;672 673 // Add this field to the list of failed cells, in order to give the user feedback674 failedcells = addNonValidatingCells( failedcells, entity )675 676 // Also create a full list of errors677 errors += getHumanReadableErrors( entity );678 }679 }680 }681 }682 683 flow.imported.numInvalidEntities = numInvalidEntities + failedcells?.size();684 flow.imported.errors = errors;685 686 return true687 }688 689 690 691 /**692 * Handles the update of the edited fields by the user693 * @param study Study to update694 * @param params Request parameter map695 * @return True if everything went OK, false otherwise. An error message is put in flash.error.696 * The field session.simpleWizard.imported.numInvalidEntities reflects the number of697 * entities that still have errors, and should be fixed before saving. The errors for those entities698 * are saved into session.simpleWizard.imported.errors699 */700 def handleMissingFields( study, params, flow ) {701 def numInvalidEntities = 0;702 def errors = [];703 704 // Check which fields failed previously705 def failedCells = flow.imported.failedCells706 707 flow.imported.data.each { table ->708 table.each { entity ->709 def invalidFields = 0710 711 // Set the fields for this entity by retrieving values from the params712 entity.giveFields().each { field ->713 def fieldName = importerService.getFieldNameInTableEditor( entity, field );714 715 if( params[ fieldName ] == "#invalidterm" ) {716 // If the value '#invalidterm' is chosen, the user hasn't fixed anything, so this field is still incorrect717 invalidFields++;718 } else {719 if( field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM || field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST ) {720 // If this field is an ontologyterm field or a stringlist field, the value has changed, so remove the field from721 // the failedCells list722 importerService.removeFailedCell( failedCells, entity, field )723 }724 725 // Update the field, regardless of the type of field726 entity.setFieldValue(field.name, params[ fieldName ] )727 }728 }729 730 // Determine entity class and add a parent731 entity.parent = study;732 733 // Try to validate the entity now all fields have been set. If it fails, return an error734 if (!entity.validate() || invalidFields) {735 numInvalidEntities++;736 737 // Add this field to the list of failed cells, in order to give the user feedback738 failedCells = addNonValidatingCells( failedCells, entity )739 740 // Also create a full list of errors741 errors += getHumanReadableErrors( entity );742 } else {743 importerService.removeFailedCell( failedCells, entity )744 }745 } // end of record746 } // end of table747 748 flow.imported.numInvalidEntities = numInvalidEntities;749 flow.imported.errors = errors;750 751 return true752 }753 754 /**755 * Handles assay input756 * @param study Study to update757 * @param params Request parameter map758 * @return True if everything went OK, false otherwise. An error message is put in flash.error759 */760 def handleAssays( assay, params, flow ) {761 // did the study template change?762 if (params.get('template') && assay.template?.name != params.get('template')) {763 // set the template764 assay.template = Template.findByName(params.remove('template'))765 }766 767 // does the study have a template set?768 if (assay.template && assay.template instanceof Template) {769 // yes, iterate through template fields770 assay.giveFields().each() {771 // and set their values772 assay.setFieldValue(it.name, params.get(it.escapedName()))773 }774 }775 776 // Save the assay in session777 flow.assay = assay;778 779 return true780 }781 782 783 /**784 * Checks whether the given study is simple enough to be edited using this controller.785 *786 * The study is simple enough if the samples, subjects, events and samplingEvents can be787 * edited as a flat table. That is:788 * - Every subject belongs to 0 or 1 eventgroup789 * - Every eventgroup belongs to 0 or 1 sample790 * - Every eventgroup has 0 or 1 subjects, 0 or 1 event and 0 or 1 samplingEvents791 * - If a sample belongs to an eventgroup:792 * - If that eventgroup has a samplingEvent, that same samplingEvent must also be793 * the sampling event that generated this sample794 * - If that eventgroup has a subject, that same subject must also be the subject795 * from whom the sample was taken796 *797 * @param study Study to check798 * @return True if the study can be edited by this controller, false otherwise799 */800 def checkStudySimplicity( study ) {801 def simplicity = true;802 803 if( !study )804 return false805 806 if( study.eventGroups ) {807 study.eventGroups.each { eventGroup ->808 // Check for simplicity of eventgroups: only 0 or 1 subject, 0 or 1 event and 0 or 1 samplingEvent809 if( eventGroup.subjects?.size() > 1 || eventGroup.events?.size() > 1 || eventGroup.samplingEvents?.size() > 1 ) {810 flash.message = "One or more eventgroups contain multiple subjects or events."811 simplicity = false;812 }813 814 // Check whether this eventgroup only belongs to (max) 1 sample815 def numSamples = 0;816 study.samples.each { sample ->817 // If no id is given for the eventGroup, it has been entered in this wizard, but818 // not yet saved. In that case, it is always OK819 if( eventGroup.id && sample.parentEventGroup?.id == eventGroup.id )820 numSamples++;821 }822 823 if( numSamples > 1 ) {824 flash.message = "One or more eventgroups belong to multiple samples."825 simplicity = false;826 }827 }828 829 if( !simplicity ) return false;830 831 // Check whether subject only belong to zero or one event group832 if( study.subjects ) {833 study.subjects.each { subject ->834 def numEventGroups = 0835 study.eventGroups.each { eventGroup ->836 // If no id is given for the subject, it has been entered in this wizard, but837 // not yet saved. In that case, it is always OK838 if( subject.id && eventGroup.subjects[0]?.id == subject.id )839 numEventGroups++840 }841 842 if( numEventGroups > 1 ) {843 flash.message = "One or more subjects belong to multiple eventgroups."844 simplicity = false;845 }846 }847 }848 849 if( !simplicity ) return false;850 851 // Check whether the samples that belong to an eventgroup have the right parentObjects852 study.samples.each { sample ->853 if( sample.parentEventGroup ) {854 // If no id is given for the subject, it has been entered in this wizard, but855 // not yet saved. In that case, it is always OK856 if( sample.parentSubject && sample.parentSubject.id) {857 if( !sample.parentEventGroup.subjects || sample.parentEventGroup.subjects[0]?.id != sample.parentSubject.id ) {858 flash.message = "The structure of the eventgroups of one or more samples is too complex"859 simplicity = false;860 }861 }862 863 // If no id is given for the sampling event, it has been entered in this wizard, but864 // not yet saved. In that case, it is always OK865 if( sample.parentEvent && sample.parentEvent.id) {866 if( !sample.parentEventGroup.samplingEvents || sample.parentEventGroup.samplingEvents[0]?.id != sample.parentEvent.id ) {867 flash.message = "The structure of the eventgroups of one or more samples is too complex"868 simplicity = false;869 }870 }871 }872 }873 874 if( !simplicity ) return false;875 }876 877 return simplicity;878 }879 880 /**881 * Checks an excel workbook whether the given sheetindex and rownumbers are correct882 * @param workbook Excel workbook to read883 * @param sheetIndex 1-based sheet index for the sheet to read (1=first sheet)884 * @param headerRow 1-based row number for the header row (1=first row)885 * @param dataMatrixStart 1-based row number for the first data row (1=first row)886 * @return True if the sheet index and row numbers are correct.887 */888 protected boolean excelChecks( def workbook, int sheetIndex, int headerRow, int dataMatrixStart ) {889 // Perform some basic checks on the excel file. These checks should be performed by the importerservice890 // in a perfect scenario.891 if( sheetIndex > workbook.getNumberOfSheets() ) {892 log.error ".simple study wizard Sheet index is too high: " + sheetIndex + " / " + workbook.getNumberOfSheets();893 flash.error = "Your excel sheet contains too few excel sheets. The provided excel sheet has only " + workbook.getNumberOfSheets() + " sheet(s).";894 return false895 }896 897 def sheet = workbook.getSheetAt(sheetIndex - 1);898 def firstRowNum = sheet.getFirstRowNum();899 def lastRowNum = sheet.getLastRowNum();900 def numRows = lastRowNum - firstRowNum + 1;901 902 if( headerRow > numRows ) {903 log.error ".simple study wizard Header row number is incorrect: " + headerRow + " / " + numRows;904 flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";905 return false906 }907 908 if( dataMatrixStart > numRows ) {909 log.error ".simple study wizard Data row number is incorrect: " + dataMatrixStart + " / " + numRows;910 flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";911 return false912 }913 914 return true;915 }916 917 /**918 * Validates an object and puts human readable errors in validationErrors variable919 * @param entity Entity to validate920 * @return True iff the entity validates, false otherwise921 */922 protected boolean validateObject( def entity ) {923 if( !entity.validate() ) {924 flash.validationErrors = getHumanReadableErrors( entity )925 return false;926 }927 return true;928 }929 930 /**931 * transform domain class validation errors into a human readable932 * linked hash map933 * @param object validated domain class934 * @return object linkedHashMap935 */936 def getHumanReadableErrors(object) {937 def errors = [:]938 object.errors.getAllErrors().each() { error ->939 // error.codes.each() { code -> println code }940 941 // generally speaking g.message(...) should work,942 // however it fails in some steps of the wizard943 // (add event, add assay, etc) so g is not always944 // availably. Using our own instance of the945 // validationTagLib instead so it is always946 // available to us947 errors[error.getArguments()[0]] = validationTagLib.message(error: error)948 }949 950 return errors951 }952 269 }
Note: See TracChangeset
for help on using the changeset viewer.