source: trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy @ 368

Last change on this file since 368 was 368, checked in by duh, 9 years ago
  • Property svn:keywords set to Date Author Rev
File size: 21.1 KB
RevLine 
[86]1package dbnp.studycapturing
[101]2
[138]3import dbnp.data.*
[86]4
5/**
6 * Wizard Controler
7 *
8 * The wizard controller handles the handeling of pages and data flow
9 * through the study capturing wizard.
10 *
[275]11 * TODO: refactor the 'handle*' methods to work as subflows instead
12 *               of methods outside of the flow
13 *
[101]14 * @author Jeroen Wesbeek
15 * @since 20100107
[86]16 * @package studycapturing
17 *
18 * Revision information:
19 * $Rev: 368 $
20 * $Author: duh $
21 * $Date: 2010-04-21 15:31:52 +0000 (wo, 21 apr 2010) $
22 */
23class WizardController {
[101]24        /**
25         * index method, redirect to the webflow
26         * @void
27         */
28        def index = {
29                /**
30                 * Do you believe it in your head?
31                 * I can go with the flow
32                 * Don't say it doesn't matter (with the flow) matter anymore
33                 * I can go with the flow (I can go)
34                 * Do you believe it in your head?
35                 */
36                redirect(action: 'pages')
37        }
[86]38
[101]39        /**
40         * WebFlow definition
41         * @see http://grails.org/WebFlow
42         * @void
43         */
44        def pagesFlow = {
45                // start the flow
46                onStart {
47                        // define flow variables
48                        flow.page = 0
49                        flow.pages = [
[238]50                                //[title: 'Templates'],                 // templates
51                                [title: 'Start'],                               // load or create a study
[209]52                                [title: 'Study'],                               // study
53                                [title: 'Subjects'],                    // subjects
54                                [title: 'Event Descriptions'],  // event descriptions
[217]55                                [title: 'Events'],                              // events and event grouping
[216]56                                [title: 'Confirmation'],                // confirmation page
[209]57                                [title: 'Done']                                 // finish page
[101]58                        ]
59                }
[86]60
[105]61                // render the main wizard page which immediately
62                // triggers the 'next' action (hence, the main
63                // page dynamically renders the study template
64                // and makes the flow jump to the study logic)
[101]65                mainPage {
66                        render(view: "/wizard/index")
67                        onRender {
68                                flow.page = 1
69                        }
[238]70                        on("next").to "start"
[101]71                }
[86]72
[238]73                // create or modify a study
74                start {
75                        render(view: "_start")
76                        onRender {
77                                flow.page = 1
78                        }
[341]79                        on("next").to "study"
80                        on("modify").to "modify"
81                }
82
83                // load a study to modify
84                modify {
85                        render(view: "_modify")
86                        onRender {
87                                flow.page = 1
88                                flash.cancel = true
89                        }
[343]90                        on("cancel") {
91                                flow.study = null
92                        }.to "start"
[238]93                        on("next") {
[341]94                                // TODO: loading a study is not yet implemented
95                                //       create a error stating this feature is
96                                //       not yet implemented
97                                flash.errors = [:]
98                                this.appendErrorMap(
99                                        ['study': 'Loading a study and modifying it has not yet been implemented. Please press \'cancel\' to go back to the initial page...'],
100                                        flash.errors
101                                )
102                        }.to "modify"
[238]103                }
104
[195]105                // render and handle the study page
[238]106                // TODO: make sure both template as well as logic will
107                //       handle Study templates as well!!!
[195]108                study {
109                        render(view: "_study")
110                        onRender {
111                                flow.page = 2
112                        }
[368]113                        on("refresh") {
114                                flash.values = params
115
116                                // handle study data
117                                this.handleStudy(flow, flash, params)
118
119                                // remove errors as we don't want any warnings now
120                                flash.errors = [:]                             
121                        }.to "study"
[240]122                        on("switchTemplate") {
[368]123                                flash.values = params
124
[252]125                                // handle study data
[240]126                                this.handleStudy(flow, flash, params)
[252]127
128                                // remove errors as we don't want any warnings now
129                                flash.errors = [:]
[240]130                        }.to "study"
[195]131                        on("previous") {
[252]132                                flash.errors = [:]
[195]133
[343]134                                // handle the study
135                                this.handleStudy(flow, flash, params)
136
137                                // reset errors
138                                flash.errors = [:]
139
140                                success()
[238]141                        }.to "start"
[195]142                        on("next") {
[252]143                                flash.errors = [:]
[195]144
145                                if (this.handleStudy(flow, flash, params)) {
146                                        success()
147                                } else {
148                                        error()
149                                }
[138]150                        }.to "subjects"
[101]151                }
152
[189]153                // render and handle subjects page
[138]154                subjects {
155                        render(view: "_subjects")
[101]156                        onRender {
[195]157                                flow.page = 3
[138]158
159                                if (!flow.subjects) {
[140]160                                        flow.subjects = []
[252]161                                        flow.subjectTemplates = [:]
[138]162                                }
[101]163                        }
[356]164                        on("refresh") {
165                                flash.values = params
166                        }.to "subjects"
[180]167                        on("add") {
[349]168                                flash.values = params
[367]169                                def speciesTerm = Term.findByName(params.species);
170                                def subjectTemplateName = params.get('template');
171                                def subjectTemplate = Template.findByName(subjectTemplateName);
[180]172
[238]173                                // add this subject template to the subject template array
174                                if (!flow.subjectTemplates[ subjectTemplateName ]) {
175                                        flow.subjectTemplates[ subjectTemplateName ] = [
176                                                name: subjectTemplateName,
177                                                template: subjectTemplate,
178                                                subjects: []
179                                        ]
180                                }
181
[367]182                                // add x subjects of species y
[138]183                                (params.addNumber as int).times {
184                                        def increment = flow.subjects.size()
[238]185                                        def subject = new Subject(
[180]186                                                name: 'Subject ' + (increment + 1),
187                                                species: speciesTerm,
[238]188                                                template: subjectTemplate
[138]189                                        )
[238]190
191                                        // instantiate a new Subject
192                                        flow.subjects[ increment ] = subject
193
194                                        // and remember the subject id with the template
195                                        def subjectsSize = flow.subjectTemplates[ subjectTemplateName ]['subjects'].size()
196                                        flow.subjectTemplates[ subjectTemplateName ]['subjects'][ subjectsSize ] = increment
[138]197                                }
198                        }.to "subjects"
[101]199                        on("next") {
[252]200                                flash.errors = [:]
[180]201
[192]202                                // check if we have at least one subject
203                                // and check form data
204                                if (flow.subjects.size() < 1) {
205                                        // append error map
206                                        this.appendErrorMap(['subjects': 'You need at least to create one subject for your study'], flash.errors)
[181]207                                        error()
[192]208                                } else if (!this.handleSubjects(flow, flash, params)) {
209                                        error()
[180]210                                } else {
[181]211                                        success()
[180]212                                }
[209]213                        }.to "eventDescriptions"
[275]214                        on("delete") {
215                                flash.errors = [:]
216                                def delete = params.get('do') as int;
217
218                                // remove subject
219                                if (flow.subjects[ delete ] && flow.subjects[ delete ] instanceof Subject) {
220                                        flow.subjectTemplates.each() { templateName, templateData ->
221                                                templateData.subjects.remove(delete)
222                                        }
223
224                                        flow.subjects.remove( delete )
225                                }
226                        }.to "subjects"
[181]227                        on("previous") {
[252]228                                flash.errors = [:]
[180]229
[181]230                                // handle form data
231                                if (!this.handleSubjects(flow, flash, params)) {
[138]232                                        error()
[180]233                                } else {
234                                        success()
[138]235                                }
[103]236                        }.to "study"
[101]237                }
238
[209]239                // render page three
240                eventDescriptions {
241                        render(view: "_eventDescriptions")
242                        onRender {
243                                flow.page = 4
244
245                                if (!flow.eventDescriptions) {
246                                        flow.eventDescriptions = []
247                                }
248                        }
249                        on("add") {
250                                // fetch classification by name (as posted by the form)
[238]251                                //params.classification = Term.findByName(params.classification)
[209]252
[350]253                                /* TODO: rewrite to Event template
254
[246]255                                // fetch protocol by name (as posted by the form)
256                                params.protocol = Protocol.findByName(params.protocol)
257
[209]258                                // transform checkbox form value to boolean
259                                params.isSamplingEvent = (params.containsKey('isSamplingEvent'))
260
[350]261
[209]262                                // instantiate EventDescription with parameters
263                                def eventDescription = new EventDescription(params)
264
265                                // validate
266                                if (eventDescription.validate()) {
267                                        def increment = flow.eventDescriptions.size()
268                                        flow.eventDescriptions[increment] = eventDescription
269                                        success()
270                                } else {
271                                        // validation failed, feedback errors
[252]272                                        flash.errors = [:]
[213]273                                        flash.values = params
[209]274                                        this.appendErrors(eventDescription, flash.errors)
275                                        error()
276                                }
[350]277
278                                */
[209]279                        }.to "eventDescriptions"
[217]280                        on("delete") {
281                                def delete = params.get('do') as int;
282
[350]283                                /* TODO: rewrite to Event template
284                               
[217]285                                // handle form data
286                                if (!this.handleEventDescriptions(flow, flash, params)) {
287                                        flash.values = params
288                                        error()
289                                } else {
290                                        success()
291                                }
292
293                                // remove eventDescription
294                                if (flow.eventDescriptions[ delete ] && flow.eventDescriptions[ delete ] instanceof EventDescription) {
295                                        // remove all events based on this eventDescription
296                                        for ( i in flow.events.size()..0 ) {
297                                                if (flow.events[ i ] && flow.events[ i ].eventDescription == flow.eventDescriptions[ delete ]) {
298                                                        flow.events.remove(i)
299                                                }
300                                        }
301
302                                        flow.eventDescriptions.remove(delete)
303                                }
[350]304
305                                */
[217]306                        }.to "eventDescriptions"
[209]307                        on("previous") {
[252]308                                flash.errors = [:]
[209]309
310                                // handle form data
311                                if (!this.handleEventDescriptions(flow, flash, params)) {
[213]312                                        flash.values = params
[209]313                                        error()
314                                } else {
315                                        success()
316                                }
317                        }.to "subjects"
318                        on("next") {
[252]319                                flash.errors = [:]
[209]320
321                                // check if we have at least one subject
322                                // and check form data
323                                if (flow.eventDescriptions.size() < 1) {
324                                        // append error map
[213]325                                        flash.values = params
[209]326                                        this.appendErrorMap(['eventDescriptions': 'You need at least to create one eventDescription for your study'], flash.errors)
327                                        error()
328                                } else if (!this.handleEventDescriptions(flow, flash, params)) {
[213]329                                        flash.values = params
[209]330                                        error()
331                                } else {
332                                        success()
333                                }
334                        }.to "events"
335                }
336
337                // render events page
338                events {
339                        render(view: "_events")
340                        onRender {
341                                flow.page = 5
342
343                                if (!flow.events) {
344                                        flow.events = []
345                                }
346
347                                if (!flow.eventGroups) {
348                                        flow.eventGroups = []
[213]349                                        flow.eventGroups[0] = new EventGroup(name: 'Group 1')   // 1 group by default
[209]350                                }
351                        }
352                        on("add") {
353                                // create date instances from date string?
354                                // @see WizardTagLibrary::timeElement{...}
355                                if (params.get('startTime')) {
356                                        params.startTime = new Date().parse("d/M/yyyy HH:mm", params.get('startTime').toString())
357                                }
358                                if (params.get('endTime')) {
359                                        params.get('endTime').toString()
360                                        params.endTime = new Date().parse("d/M/yyyy HH:mm", params.get('endTime').toString())
361                                }
362
363                                // get eventDescription instance by name
[216]364                                params.eventDescription = this.getObjectByName(params.get('eventDescription'), flow.eventDescriptions)
[209]365
366                                // instantiate Event with parameters
[275]367                                def event = (params.eventDescription.isSamplingEvent) ? new SamplingEvent(params) : new Event(params)
[209]368
[216]369                                // handle event groupings
370                                this.handleEventGrouping(flow, flash, params)
371
[209]372                                // validate event
373                                if (event.validate()) {
374                                        def increment = flow.events.size()
375                                        flow.events[increment] = event
376                                        success()
377                                } else {
378                                        // validation failed, feedback errors
[252]379                                        flash.errors = [:]
[213]380                                        flash.values = params
[209]381                                        this.appendErrors(event, flash.errors)
382
[216]383                                        flash.startTime = params.startTime
384                                        flash.endTime = params.endTime
385                                        flash.eventDescription = params.eventDescription
386
[209]387                                        error()
388                                }
389                        }.to "events"
[217]390                        on("deleteEvent") {
391                                flash.values = params
392                                def delete = params.get('do') as int;
393
394                                // handle event groupings
395                                this.handleEventGrouping(flow, flash, params)
396
397                                // remove event
398                                if (flow.events[ delete ] && flow.events[ delete ] instanceof Event) {
399                                        flow.events.remove(delete)
400                                }
401                        }.to "events"
[209]402                        on("addEventGroup") {
[217]403                                flash.values = params
404                               
405                                // handle event groupings
406                                this.handleEventGrouping(flow, flash, params)
407
[209]408                                def increment = flow.eventGroups.size()
[216]409                                def groupName = "Group " + (increment + 1)
410
411                                // check if group name exists
412                                def nameExists = true
413                                def u = 0
414
415                                // make sure a unique name is generated
416                                while (nameExists) {
417                                        u++
418                                        def count = 0
419                                       
420                                        flow.eventGroups.each() {
421                                                if (it.name == groupName) {
422                                                        groupName = "Group " + (increment + 1) + "," + u
423                                                } else {
424                                                        count++
425                                                }
426                                        }
427
428                                        nameExists = !(count == flow.eventGroups.size())
429                                }
430
431                                flow.eventGroups[increment] = new EventGroup(name: groupName)
[209]432                        }.to "events"
[216]433                        on("deleteEventGroup") {
[217]434                                flash.values = params
435                               
[216]436                                def delete = params.get('do') as int;
437
438                                // handle event groupings
439                                this.handleEventGrouping(flow, flash, params)
440
441                                // remove the group with this specific id
442                                if (flow.eventGroups[delete] && flow.eventGroups[delete] instanceof EventGroup) {
443                                        // remove this eventGroup
444                                        flow.eventGroups.remove(delete)
445                                }
446                        }.to "events"
[209]447                        on("previous") {
[216]448                                // handle event groupings
449                                this.handleEventGrouping(flow, flash, params)
[209]450                        }.to "eventDescriptions"
451                        on("next") {
[217]452                                flash.values = params
[252]453                                flash.errors = [:]
[209]454
[216]455                                // handle event groupings
456                                this.handleEventGrouping(flow, flash, params)
457
[213]458                                // check if we have at least one subject
459                                // and check form data
460                                if (flow.events.size() < 1) {
461                                        // append error map
462                                        flash.values = params
463                                        this.appendErrorMap(['events': 'You need at least to create one event for your study'], flash.errors)
464                                        error()
[145]465                                }
[252]466                        }.to "confirm"
[145]467                }
468
[213]469                confirm {
470                        render(view: "_confirmation")
[195]471                        onRender {
[213]472                                flow.page = 6
[195]473                        }
[252]474                        on("toStudy").to "study"
475                        on("toSubjects").to "subjects"
476                        on("toEvents").to "events"
[275]477                        on("previous").to "events"
478                        on("next").to "save"
479                }
480
481                // store all study data
482                save {
483                        action {
484                                println "saving..."
485                                flash.errors = [:]
486
487                                // start transaction
488                                def transaction = sessionFactory.getCurrentSession().beginTransaction()
489
490                                // persist data to the database
491                                try {
492                                        // save EventDescriptions
493                                        flow.eventDescriptions.each() {
[278]494                                                if (!it.save(flush:true)) {
[275]495                                                        this.appendErrors(it, flash.errors)
496                                                        throw new Exception('error saving eventDescription')
497                                                }
498                                                println "saved eventdescription "+it
499                                        }
500
[296]501                                        // TODO: eventDescriptions that are not linked to an event are currently
502                                        //               stored but end up in a black hole. We should either decide to
503                                        //               NOT store these eventDescriptions, or add "hasmany eventDescriptions"
504                                        //               to Study domain class
505
[275]506                                        // save events
507                                        flow.events.each() {
[278]508                                                if (!it.save(flush:true)) {
[275]509                                                        this.appendErrors(it, flash.errors)
510                                                        throw new Exception('error saving event')
511                                                }
512                                                println "saved event "+it
513
514                                                // add to study
515                                                if (it instanceof SamplingEvent) {
516                                                        flow.study.addToSamplingEvents(it)
517                                                } else {
518                                                        flow.study.addToEvents(it)
519                                                }
520                                        }
521
522                                        // save eventGroups
523                                        flow.eventGroups.each() {
[278]524                                                if (!it.save(flush:true)) {
[275]525                                                        this.appendErrors(it, flash.errors)
526                                                        throw new Exception('error saving eventGroup')
527                                                }
528                                                println "saved eventGroup "+it
529
530                                                // add to study
531                                                flow.study.addToEventGroups(it)
532                                        }
533                                       
534                                        // save subjects
535                                        flow.subjects.each() {
[278]536                                                if (!it.save(flush:true)) {
[275]537                                                        this.appendErrors(it, flash.errors)
538                                                        throw new Exception('error saving subject')
539                                                }
540                                                println "saved subject "+it
541
542                                                // add this subject to the study
543                                                flow.study.addToSubjects(it)
544                                        }
545
546                                        // save study
[278]547                                        if (!flow.study.save(flush:true)) {
[275]548                                                this.appendErrors(flow.study, flash.errors)
549                                                throw new Exception('error saving study')
550                                        }
551                                        println "saved study "+flow.study+" (id: "+flow.study.id+")"
552
[279]553                                        // commit transaction
554                                        println "commit"
555                                        transaction.commit()
556                                        success()
[275]557                                } catch (Exception e) {
558                                        // rollback
[279]559                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.errors)
560
[280]561                                        // stacktrace in flash scope
562                                        flash.debug = e.getStackTrace()
[279]563
[275]564                                        println "rollback"
565                                        transaction.rollback()
566                                        error()
567                                }
568                        }
569                        on("error").to "error"
570                        on(Exception).to "error"
571                        on("success").to "done"
[195]572                }
573
[275]574                // error storing data
575                error {
576                        render(view: "_error")
577                        onRender {
578                                flow.page = 6
579                        }
580                        on("next").to "save"
581                        on("previous").to "events"
582                }
583
[195]584                // render page three
585                done {
586                        render(view: "_done")
587                        onRender {
[275]588                                flow.page = 7
[195]589                        }
590                        on("previous") {
591                                // TODO
[213]592                        }.to "confirm"
[195]593                }
[101]594        }
[103]595
596        /**
[195]597         * re-usable code for handling study form data in a web flow
598         * @param Map LocalAttributeMap (the flow scope)
599         * @param Map localAttributeMap (the flash scope)
600         * @param Map GrailsParameterMap (the flow parameters = form data)
601         * @returns boolean
602         */
603        def handleStudy(flow, flash, params) {
604                // create study instance if we have none
605                if (!flow.study) flow.study = new Study();
606
607                // create date instance from date string?
608                // @see WizardTagLibrary::dateElement{...}
609                if (params.get('startDate')) {
610                        params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
[213]611                } else {
612                        params.remove('startDate')
[195]613                }
614
615                // if a template is selected, get template instance
[246]616                def template = params.remove('template')
617                if (template instanceof String && template.size() > 0) {
618                        params.template = Template.findByName(template)
619                } else if (template instanceof Template) {
620                        params.template = template
[195]621                }
622
623                // update study instance with parameters
[296]624                params.each() { key, value ->
[195]625                        if (flow.study.hasProperty(key)) {
626                                flow.study.setProperty(key, value);
627                        }
628                }
629
[296]630                // walk through template fields
[326]631                if (params.template) {
[332]632                        params.template.fields.each() { field ->
[335]633                                flow.study.setFieldValue(field.name, params.get(field.escapedName()))
[296]634                        }
635                }
636
[195]637                // validate study
638                if (flow.study.validate()) {
639                        return true
640                } else {
641                        // validation failed, feedback errors
[252]642                        flash.errors = [:]
[195]643                        this.appendErrors(flow.study, flash.errors)
644                        return false
645                }
646        }
647
648        /**
[209]649         * re-usable code for handling eventDescription form data in a web flow
650         * @param Map LocalAttributeMap (the flow scope)
651         * @param Map localAttributeMap (the flash scope)
652         * @param Map GrailsParameterMap (the flow parameters = form data)
653         * @returns boolean
654         */
655        def handleEventDescriptions(flow, flash, params) {
[252]656                def names = [:]
[213]657                def errors = false
658                def id = 0
[209]659
660                flow.eventDescriptions.each() {
[216]661                        it.name = params.get('eventDescription_' + id + '_name')
662                        it.description = params.get('eventDescription_' + id + '_description')
[246]663                        it.protocol = Protocol.findByName(params.get('eventDescription_' + id + '_protocol'))
[238]664                        //it.classification = Term.findByName(params.get('eventDescription_' + id + '_classification'))
[216]665                        it.isSamplingEvent = (params.containsKey('eventDescription_' + id + '_isSamplingEvent'))
[209]666
667                        // validate eventDescription
668                        if (!it.validate()) {
669                                errors = true
[213]670                                this.appendErrors(it, flash.errors, 'eventDescription_' + id + '_')
[209]671                        }
672
673                        id++
674                }
[213]675
[238]676                return !errors
[209]677        }
678
679        /**
[238]680         * re-usable code for handling event grouping in a web flow
681         * @param Map LocalAttributeMap (the flow scope)
682         * @param Map localAttributeMap (the flash scope)
683         * @param Map GrailsParameterMap (the flow parameters = form data)
684         * @returns boolean
685         */
686        def handleEventGrouping(flow, flash, params) {
687                // walk through eventGroups
688                def g = 0
689                flow.eventGroups.each() {
690                        def e = 0
691                        def eventGroup = it
692
693                        // reset events
694                        eventGroup.events = new HashSet()
695
696                        // walk through events
697                        flow.events.each() {
698                                if (params.get('event_' + e + '_group_' + g) == 'on') {
699                                        eventGroup.addToEvents(it)
700                                }
701                                e++
702                        }
703                        g++
704                }
705        }
706
707        /**
[181]708         * re-usable code for handling subject form data in a web flow
[192]709         * @param Map LocalAttributeMap (the flow scope)
710         * @param Map localAttributeMap (the flash scope)
711         * @param Map GrailsParameterMap (the flow parameters = form data)
[181]712         * @returns boolean
713         */
714        def handleSubjects(flow, flash, params) {
[252]715                def names = [:];
[192]716                def errors = false;
717                def id = 0;
[189]718
[238]719                // iterate through subject templates
720                flow.subjectTemplates.each() {
721                        def subjectTemplate = it.getValue().template
722                        def templateFields      = subjectTemplate.fields
[181]723
[238]724                        // iterate through subjects
725                        it.getValue().subjects.each() { subjectId ->
726                                flow.subjects[ subjectId ].name = params.get('subject_' + subjectId + '_name')
727                                flow.subjects[ subjectId ].species = Term.findByName(params.get('subject_' + subjectId + '_species'))
[189]728
[238]729                                // remember name and check for duplicates
730                                if (!names[ flow.subjects[ subjectId ].name ]) {
731                                        names[ flow.subjects[ subjectId ].name ] = [count: 1, first: 'subject_' + subjectId + '_name', firstId: subjectId]
732                                } else {
733                                        // duplicate name found, set error flag
734                                        names[ flow.subjects[ subjectId ].name ]['count']++
[189]735
[238]736                                        // second occurence?
737                                        if (names[ flow.subjects[ subjectId ].name ]['count'] == 2) {
738                                                // yeah, also mention the first
739                                                // occurrence in the error message
740                                                this.appendErrorMap(name: 'The subject name needs to be unique!', flash.errors, 'subject_' + names[ flow.subjects[ subjectId ].name ]['firstId'] + '_')
741                                        }
[181]742
[238]743                                        // add to error map
744                                        this.appendErrorMap([name: 'The subject name needs to be unique!'], flash.errors, 'subject_' + subjectId + '_')
745                                        errors = true
746                                }
[189]747
[238]748                                // iterate through template fields
749                                templateFields.each() { subjectField ->
[335]750                                        flow.subjects[ subjectId ].setFieldValue(
751                                                subjectField.name,
752                                                params.get( 'subject_' + subjectId + '_' + subjectField.escapedName() )
753                                        )
[181]754                                }
755
[238]756                                // validate subject
757                                if (!flow.subjects[ subjectId ].validate()) {
758                                        errors = true
[332]759                                        this.appendErrors(flow.subjects[ subjectId ], flash.errors, 'subject_' + subjectId + '_')
[238]760                                }
[181]761                        }
762                }
[192]763
764                return !errors
[181]765        }
766
767        /**
[209]768         * return the object from a map of objects by searching for a name
[216]769         * @param String name
770         * @param Map map of objects
[209]771         * @return Object
772         */
773        def getObjectByName(name, map) {
774                def result = null
775                map.each() {
776                        if (it.name == name) {
777                                result = it
778                        }
779                }
780
781                return result
782        }
783
784        /**
[103]785         * transform domain class validation errors into a human readable
786         * linked hash map
787         * @param object validated domain class
788         * @returns object  linkedHashMap
789         */
790        def getHumanReadableErrors(object) {
[252]791                def errors = [:]
[103]792                object.errors.getAllErrors().each() {
793                        errors[it.getArguments()[0]] = it.getDefaultMessage()
794                }
795
796                return errors
797        }
798
799        /**
800         * append errors of a particular object to a map
801         * @param object
802         * @param map linkedHashMap
803         * @void
804         */
805        def appendErrors(object, map) {
806                this.appendErrorMap(this.getHumanReadableErrors(object), map)
807        }
[216]808
[213]809        def appendErrors(object, map, prepend) {
810                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
811        }
[103]812
813        /**
814         * append errors of one map to another map
815         * @param map linkedHashMap
816         * @param map linkedHashMap
817         * @void
818         */
819        def appendErrorMap(map, mapToExtend) {
820                map.each() {key, value ->
[213]821                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
[103]822                }
823        }
[216]824
[213]825        def appendErrorMap(map, mapToExtend, prepend) {
826                map.each() {key, value ->
827                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
828                }
829        }
[183]830}
Note: See TracBrowser for help on using the repository browser.