Wiki source code of EOF-Using EOF-Validation

Version 9.1 by Pascal Robert on 2011/10/04 15:07

Show last authors
1 == Overview ==
2
3 [[http://developer.apple.com/legacy/mac/library/#documentation/WebObjects/Enterprise_Objects/BusinessLogic/BusinessLogic.html]]
4
5 {{color value="#000000"}}
6 {*}Jerry W. Walker{*}
7 {{/color}}
8
9 WO and EOF have an incredible array of validation mechanisms. Here are some notes you might find helpful:
10
11 * User interface:
12 ** prevent/discourage user from entering inappropriate data
13 * Formatters:
14 ** formatting
15 *** Only accepts data with valid format
16 ** type coercion
17 *** bad type raises exception
18 ** simple validation
19 *** raises exception and ignores value
20 *** must be different from current value or not assigned
21 *** WOComponent's validationFailedWithException(Throwable t, Object value, String keyPath)
22 **** Called when an Enterprise Object or formatter failed validation during an assignment.
23 **** The default implementation ignores the error.
24 **** Subclassers can override to resolve the error.
25 * Model
26 ** attribute constraints
27 *** checks for:
28 **** allows null
29 **** string length
30 **** numeric precision
31 **** relationship integrity
32 *** checks these before going to DB
33 ** relationship integrity constraints
34 *** optionality
35 **** for both to-one & to-many
36 *** delete rule
37 **** if source deleted, then what
38 *** ownership, owned object is:
39 **** deleted if relationship broken
40 **** created if relationship added
41 *** delete rules (if user tries to delete relationship source):
42 **** cascade - delete all destination objects too
43 **** nullify - nullify back references
44 **** deny - prohibit delete if there are destination objects
45 **** nothing - delete and ignore destination objects
46 * EO
47 ** property-level (or key-level) validation
48 *** called when a value changes
49 *** default methods in superclass check model based constraints
50 *** can be overridden for custom validation
51 *** called BEFORE EO's properties have changed
52 *** validation methods throw exception on failure
53 **** validateValueForKey("weight") triggers: public <type> validateWeight(Object newWeight) throws NSValidation.ValidationException {
54 ** object-level validation
55 *** called when saving insert/delete/update changes
56 **** public void validateForInsert() throws NSValidation.ValidationException
57 **** public void validateForUpdate() throws NSValidation.ValidationException
58 **** public void validateForDelete() throws NSValidation.ValidationException
59 *** all above in superclass by default call:
60 **** public void validateForSave() throws NSValidation.ValidationException
61 *** super's implementation calls key-level validation
62 *** called AFTER EO's properties have changed
63 ** validation performed when:
64 *** form values are pushed into EO attributes through bindings
65 *** saving changes in the editing context
66 *** called programmatically
67
68 == Checking for validation problems before calling saveChanges ==
69
70 You might want to display validation problems/exceptions before you try to insert/update an EO by calling saveChanges. To get the exceptions, in your component, override validationFailedWithException, with something like this:
71
72 {{code}}
73
74 public void validationFailedWithException(Throwable exception, Object value, String keyPath) {
75 super.validationFailedWithException(exception, value, keyPath);
76 session().addError(exception.getMessage());
77 }
78
79 {{/code}}
80
81 And in Session:
82
83 {{code}}
84
85 private NSMutableArray<String> _errors;
86
87 public NSArray<String> errors() {
88 return _errors.immutableClone();
89 }
90
91 public void setErrors(NSArray<String> errors) {
92 this._errors = errors.mutableClone();
93 }
94
95 public void addError(String error) {
96 _errors.addObject(error);
97 }
98
99 public boolean haveErrors() {
100 return ((_errors != null) && (_errors.count() > 0))? true: false;
101 }
102
103 @Override
104 public void awake() {
105 super.awake();
106 _errors = new NSMutableArray<String>();
107 }
108
109 {{/code}}
110
111 And before calling saveChanges on the editing context:
112
113 {{code}}
114
115 if (session().haveErrors()) {
116 return null;
117 }
118 ...
119 ec.saveChanges();
120
121 {{/code}}
122
123 == Changing an EO after Validation ==
124
125 Question: I would like to make a change to an EO after it has validated but before it has saved to the graph/DB. Is this possible?
126
127 === Chuck Hill ===
128
129 You don't want to do this, you should not want to do this, and the frameworks will fight you tooth and nail if you try. validateForSave is the gatekeeper for the object store. Its job is to ensure that nothing gets saved unless it has validated it. Modifying the object graph after validateForSave() finished would violate its very reason for existence.
130
131 As I see it, you have three options:
132
133 1. Do it in the component
134 1. Do it in the EO
135 1. Do it in another object
136
137 I agree that the component might not be the place to do this and I also don't like to have my EOs call saveChanges(). You might want to think of the third option, having some sort of ShiftManager object that is responsible for overseeing the closing and opening of shifts. It can provide information to the page on what is valid and what options there are and it can handle the two phase save.
138
139 Before I did that, I would consider some other options. Here are some ideas that might spark some of your own:
140
141 * Defer reseting the cash box balance until the //start// of the next shift. The last time I was a cashier (thankfully long ago) that is how it worked. You handed in your cash tray and discrepancy notes, the boss shook his head and muttered. He then recorded all that information. For the next worker, he then restocked the cash drawer. Often that did not happen until the next morning.
142
143 * Add a method to Shift like this:
144
145 {{code}}
146
147 public void close() throws ValidationException {
148 validateForSave();
149 cashBox().resetBalance();
150 }
151
152 {{/code}}
153
154 and in your component
155
156 {{code}}
157
158 try {
159 shift().close();
160 ec().saveChanges();
161 } catch (ValidationException v) {
162 // do the right thing
163 } catch (EOGeneralAdaptorException e) {
164 // do the right thing
165 }
166
167 {{/code}}
168
169 * I had another one, but it has slipped my mind. :-)