handleConditional.php
13.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
<?php
require_once("../../../config/dmsDefaults.php");
require_once(KT_DIR . "/presentation/Html.inc");
require_once(KT_LIB_DIR . "/templating/templating.inc.php");
require_once(KT_LIB_DIR . "/documentmanagement/DocumentFieldSet.inc");
require_once(KT_LIB_DIR . "/documentmanagement/DocumentField.inc");
require_once(KT_LIB_DIR . "/documentmanagement/MDCondition.inc");
require_once(KT_LIB_DIR . "/database/dbutil.inc");
require_once(KT_LIB_DIR . "/util/ktutil.inc");
require_once(KT_LIB_DIR . "/dispatcher.inc.php");
$sectionName = "Administration";
require_once(KT_DIR . "/presentation/webpageTemplate.inc");
class HandleConditionalDispatcher extends KTDispatcher {
function do_main() {
global $default;
$fieldset_id = KTUtil::arrayGet($_REQUEST, 'fieldset_id');
$active_fields = KTUtil::arrayGet($_REQUEST, 'fields');
if (empty($fieldset_id)) {
return 'invalid fieldset_id';
}
$fieldsToRender = array(); // contains "name" => rows.
$oFieldSet = DocumentFieldSet::get($fieldset_id);
if (empty($active_fields)) {
$res = $this->getMasterFieldInfo($oFieldSet);
$fieldsToRender[$oFieldSet->getMasterField()] = $res;
} else {
// urgh. we use this to generate our list of things to extract from the input.
$pairings = array();
foreach ($active_fields as $field_id) {
$current = KTUtil::arrayGet($_REQUEST, 'conditional_field_'.$field_id);
if ($current === null) {
return 'invalid input sequence.';
}
else {
$pairings[$field_id] = $current;
}
}
$res = $this->validatePath($oFieldSet, $pairings, true);
if ($res === true) {
return 'validated input.';
}
else if ($res === false) {
return 'invalid input';
}
// quick collation process.
foreach ($res as $aRow) {
$fieldsToRender[$aRow["document_field_id"]][] = $aRow;
}
}
$default->log->debug('validatePath: results '.print_r($fieldsToRender,true));
$oTemplating = new KTTemplating;
$oTemplate = $oTemplating->loadTemplate("ktcore/handle_conditional");
$aTemplateData = array(
"fieldset" => $oFieldSet->getId(),
"oldfields" => $pairings,
"fieldsToRender" => $fieldsToRender,
);
return $oTemplate->render($aTemplateData);
}
function handleOutput($data) {
print $data;
}
function getMasterFieldInfo($oFieldSet) {
global $default;
$masterField = $oFieldSet->getMasterField();
$sQuery = "SELECT md_cond.document_field_id AS document_field_id, md_cond.metadata_lookup_id AS val, md_lookup.name AS name FROM $default->md_condition_table AS md_cond LEFT JOIN $default->md_condition_chain_table AS md_chain ON (md_cond.id = md_chain.child_condition) LEFT JOIN $default->metadata_table AS md_lookup ON (md_cond.metadata_lookup_id = md_lookup.id) WHERE md_cond.document_field_id = ? ";
return DBUtil::getResultArray(array($sQuery, array($masterField)));
}
// either returns the set of pathid's for the input,
// or false (FIXME: should be PEAR::raiseError)
function validatePath($oFieldSet, $aPairings, $bPartial) {
/* An explanation of what happens below, since NBM's comment was "Put that crack-pipe back in the freezer."
*
* $aPairings are the inputs we were handed. Within these, there are 3
* important things:
* 1. we have a limited set of document_fields within the $oFieldSet.
* 2. one of these fields is the "master field" - the _ONLY_ one without
* any parent conditions.
* 3. some fields may get passed _out_ as <input type="hidden" name="conditional_field_x" value="-1" />
* which indicates that there is NO VALUE for that field (again, saved in the db as "-1" so we don't go mad.
*
* We essentially have 3 stacks: inputs, parent_conditions, free_field_ids
*
* $bPartial indicates what we need to do once we've run out of inputs to validate: either fail (if we don't have coverage, and its not partial)
* or return the possible next choices.
*
* We start with the master-field, and get its entry in the table. If it isn't there, fail.
* i. push its field onto the "parent_conditions" stack, and remove the field_id from the "option_fields".
* ii. remove its entry from the inputs.
* While we have inputs ->
* find any matches that have a (field_id, lookup_id) in the input set, and parent_condition in the parent_conditions stack.
* if no values found, FAIL - invalid input (we can't match what we've been given).
* otherwise ->
* remove them from the input stack, push their id's onto the parent_condition stack, and remove their field_id's from the field_id stack.
* If $bPartial == true ->
* get anything which has a parent_condition in the parent_condition set, and a field_id in the free_field_id's set -> this will give you
* the next set of "inputs" - (column, lookup) pairs with parent-rules that have been activated.
* If $bPartial == false and free_field_id's still has anything in it WE FAIL OUT.
*/
global $default;
$free_field_ids = array();
$parent_conditions = array();
$inputs = $aPairings; // please tell me this does a copy ...
// step 1: generate free_field_ids.
$childFields = DocumentField::getList('parent_fieldset = '.$oFieldSet->getId());
foreach ($childFields as $oField) {
$free_field_ids[$oField->getId()] = 1; // placeholder.
}
$master_field = $oFieldSet->getMasterField(); // this is the id of the master field.
if (!array_key_exists($master_field, $inputs)) {
return false; // no master field in the input.
}
// step 2: get the first parent, to get the ball rolling.
$sQuery = "SELECT * FROM $default->md_condition_table WHERE document_field_id = ? and metadata_lookup_id = ? ";
$aParams = array($master_field, $inputs[$master_field]);
$res = DBUtil::getOneResult(array($sQuery, $aParams));
if (PEAR::isError($res)) {
return false; // no value matched on the master field input, the rest MUST fail.
}
else {
unset($free_field_ids[$master_field]); // master is no longer free.
$rule_id = $res["id"];
$parent_conditions[$rule_id] = 1;
unset($inputs[$master_field]);
}
$default->log->debug('validatePath: parent_conditions '.print_r($parent_conditions,true));
while (count($inputs) != 0) { // we'll return out inside here if necessary.
// check for items in inputs, with parents in parent_conditions.
// $testStr = "";
// $testarr = array();
// for ($i=0; $i<3; $i++) {
// $testarr[] = "( ? )";
// }
// $testStr = "(".join(" OR ", $testarr).")";
// return $testStr;
// we need something like "parent_conditions IN (1,2,3) AND ((f=1 AND v=2) OR (f=2 AND v=5) OR (f=4 AND v=7))
$sParentClause = "md_chain.parent_condition IN (";
$aInputParts = array();
for ($i=0; $i<count($parent_conditions); $i++) {
if ($i == count($parent_conditions)-1) {
$sParentClause .= '?';
} else {
$sParentClause .= '? ,';
}
}
$sParentClause .= ')';
$aInputs = array();
foreach ($inputs as $fid => $lookid) {
$aInputs[] = $fid;
$aInputs[] = $lookid;
$aInputParts[] = '(md_cond.document_field_id = ? AND md_cond.metadata_lookup_id = ?)';
}
$sInputs = join(" OR ", $aInputParts);
$sInputs = '(' . $sInputs . ')';
$default->log->debug('validatePath: parent_conditions '.print_r($parent_conditions,true));
$sFieldClause = "md_cond.document_field_id IN (";
for ($i=0; $i<count($free_field_ids); $i++) {
if ($i == count($free_field_ids)-1) {
$sFieldClause .= '?';
} else {
$sFieldClause .= '? ,';
}
}
$sFieldClause .= ')';
$default->log->debug('validatePath: sParentClause '.print_r($sParentClause,true));
$sWhere = KTUtil::whereToString(array(array($sParentClause, array_keys($parent_conditions)), array($sInputs, $aInputs)));
$sQuery = "SELECT md_cond.id as rule_id, md_cond.document_field_id AS field_id FROM $default->md_condition_table AS md_cond LEFT JOIN $default->md_condition_chain_table AS md_chain ON (md_cond.id = md_chain.child_condition) WHERE ";
$default->log->debug('validatePath: '.print_r(array($sQuery . $sWhere[0], $sWhere[1]),true));
$res = DBUtil::getResultArray(array($sQuery . $sWhere[0], $sWhere[1]));
if (PEAR::isError($res)) {
return false;
}
// if there's anything is $res, its a match (must be - we can't have crossed chains.)
if (count($res) == 0) {
return false; // fail - no matches from inputs against parent_conditions.
} else {
// we must have a match - MAY have multiple matches.
foreach ($res as $aRow) {
$default->log->debug('validatePath: output_row '.print_r($aRow,true));
$parent_conditions[$aRow["rule_id"]] = 1; // add this as a possible parent condition.
unset($free_field_ids[$aRow["field_id"]]); // no longer free
unset($inputs[$aRow["field_id"]]); // no longer an un-processed input, so reduce the input-count.
}
}
}
// ok: we got this far, and have run out of inputs without running out of matches.
// IF we're looking for a partial match, and still have free fields, return the set of free-and-parent matches.
// OTHERWISE if we have free fields, fail
// finally, pass the input as valid.
if (($bPartial === true) and (count($free_field_ids) > 0)) {
// generate the set of matches for free_fields with appropriate parents.
// UNFORTUNATELY, there is no "nice" way to do this.
// Wax On. Wax Off.
$sParentClause = "md_chain.parent_condition IN (";
for ($i=0; $i<count($parent_conditions); $i++) {
if ($i == count($parent_conditions)-1) {
$sParentClause .= '?';
} else {
$sParentClause .= '? ,';
}
}
$sParentClause .= ')';
$default->log->debug('validatePath: parent_conditions '.print_r($parent_conditions,true));
$sFieldClause = "md_cond.document_field_id IN (";
for ($i=0; $i<count($free_field_ids); $i++) {
if ($i == count($free_field_ids)-1) {
$sFieldClause .= '?';
} else {
$sFieldClause .= '? ,';
}
}
$sFieldClause .= ')';
$default->log->debug('validatePath: sParentClause '.print_r($sParentClause,true));
$aWhere = KTUtil::whereToString(array(array($sParentClause, array_keys($parent_conditions)), array($sFieldClause,array_keys($free_field_ids))));
$sQuery = "SELECT md_cond.document_field_id AS document_field_id, md_cond.metadata_lookup_id AS val, md_lookup.name as name FROM $default->md_condition_table AS md_cond LEFT JOIN $default->md_condition_chain_table AS md_chain ON (md_cond.id = md_chain.child_condition) LEFT JOIN $default->metadata_table AS md_lookup ON (md_cond.metadata_lookup_id = md_lookup.id) WHERE ";
$default->log->debug('validatePath: sParentClause '.print_r(array($sQuery . $aWhere[0], $aWhere[1]), true));
$sOrderClause = " ORDER BY document_field_id ASC, name ASC";
return DBUtil::getResultArray(array($sQuery . $aWhere[0] . $sOrderClause, $aWhere[1])); // FIXME catch errors?
} else if (count($free_field_ids) != 0) {
return false; // incomplete - could actually catch this at the start.
} else {
return true; // note - this ALSO matches whenever $bPartial is true, but we have completed. UP THE STACK: true => valid and committable.
}
}
// FIXME: this need s to move into MDCondition.inc, or manageConditionalMetadata.php
// actually, this needs to die - its DEBUG only, really.
function do_createCondition() {
global $default;
$fieldset_id = KTUtil::arrayGet($_REQUEST, 'fieldset_id');
$parent_id = KTUtil::arrayGet($_REQUEST, 'parent_id');
$field_id = KTUtil::arrayGet($_REQUEST, 'field_id');
$lookup_id = KTUtil::arrayGet($_REQUEST, 'lookup_id');
$resObj = MDConditionNode::createFromArray(array(
"iFieldId" => $field_id,
"iLookupId" => $lookup_id,
));
$default->log->debug("CREATE_CONDITION_DEBUG: ".print_r($resObj,true));
$resObj2 = MDConditionChain::createFromArray(array(
"iParentCondition" => $parent_id, // may be null.
"iChildCondition" => $resObj->getId(),
));
$default->log->debug("CREATE_CONDITION_DEBUG: ".print_r($resObj2,true));
}
}
$oDispatcher = new HandleConditionalDispatcher();
$oDispatcher->dispatch();
?>