/[libdata]/trunk/admin/include/scribe_fix.php
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/admin/include/scribe_fix.php

Parent Directory Parent Directory | Revision Log Revision Log


Revision 72 - (show annotations)
Thu Mar 18 20:33:37 2004 UTC (20 years, 1 month ago) by dpavlin
File size: 17997 byte(s)
changes made in version 2.00

1 <?php
2 /**********************************************************
3 Function Library: scribe_fix.php
4 Original Author: Paul Bramscher <brams006@umn.edu>
5 Last Modified: 03.16.2004
6 ***********************************************************
7 Comments:
8 This library brings together CourseLib/PageScribe page
9 debugging and fixing algorithms.
10 ***********************************************************
11 Table of Contents:
12 errorTrap
13 genCalc
14 isOrphan
15 purgeOrphans
16 purgeRelationships
17 scribeFix
18 updateGenerations
19 updateOrders
20 updateOrphans
21 **********************************************************/
22
23 /**********************************************************
24 Function: errorTrap
25 Author: Paul Bramscher
26 Last Modified: 03.04.2004
27 ***********************************************************
28 Purpose:
29 Debugger available for CLPS system, to check for various
30 sorts of page integrity. If page_debug in the page table
31 is equal to 1, then this function is useful to call from
32 scribe.phtml automatically. Otherwise, it's called
33 manually from the DBA console.
34 **********************************************************/
35 function errorTrap($page_id){
36
37 // Fetch title
38 $page_title = lookupField("page", "page_id", $page_id, "page_title");
39
40 // Overall status
41 $passed = 1;
42
43 printf("<center>\n");
44 printf("<table width=\"90%%\" class=\"backLight\" border=\"1\">\n");
45 printf("<tr><td class=\"cellPlain\">Debug Data: %s (ID# %d)</td></tr>\n", $page_title, $page_id);
46 printf("<tr><td><br>\n");
47
48 /***********************
49 ** Basic Element Data **
50 ***********************/
51
52 printf("<b>Element Data:</b><br>\n");
53
54 // Distinct orders
55 $sql = "SELECT DISTINCT element_order FROM element WHERE page_id ="
56 . $page_id;
57 $rs = xx_tryquery($sql);
58 $num_orders = xx_num_rows($rs);
59 printf("Unique orders: %d<br>\n", $num_orders);
60
61 // Number of rows (should be the same)
62 $sql = "SELECT element_id FROM element WHERE page_id = "
63 . $page_id;
64 $rs = xx_tryquery($sql);
65 $num_rows = xx_num_rows($rs);
66 printf("Number of rows: %d<BR>\n", $num_rows);
67
68 // Smallest order (if rows present, should be 1)
69 $sql = "SELECT MIN(element_order) as min_order FROM element WHERE page_id = "
70 . $page_id;
71 $rs = xx_tryquery($sql);
72 $row = xx_fetch_array ($rs, xx_ASSOC);
73 $min_order = $row["min_order"];
74 printf("First order: %d<br>\n", $min_order);
75
76 // Largest order (should equal distinct rows and number of rows
77 $sql = "SELECT MAX(element_order) as max_order FROM element WHERE page_id = "
78 . $page_id;
79 $rs = xx_tryquery($sql);
80 $row = xx_fetch_array ($rs, xx_ASSOC);
81 $max_order = $row["max_order"];
82 printf("Last order: %d<br><br>\n", $max_order);
83
84 /************************************
85 ** Child-to-Parent reference check **
86 ************************************/
87
88 printf("<b>Child-to-Parent reference check:</b><br>\n");
89 $c1_sql = "SELECT element_id, parent_id, element_order, indent_level FROM element WHERE page_id = "
90 . $page_id
91 . " AND parent_id > 0 ORDER BY element_order";
92 $c1_rs = xx_tryquery($c1_sql);
93
94 while ($c1_row = xx_fetch_array ($c1_rs, xx_ASSOC)) {
95 $parent_id = $c1_row["parent_id"];
96 $indent_level = $c1_row["indent_level"];
97 $element_id = $c1_row["element_id"];
98 $element_order = $c1_row["element_order"];
99
100 // For each row returned, hunt for the parent
101 $c2_sql ="SELECT element_id, element_order, indent_level FROM element WHERE element_id = "
102 . $parent_id;
103 $c2_rs = xx_tryquery($c2_sql);
104 $c2_row = xx_fetch_array ($c2_rs, xx_ASSOC);
105 $c2_indent_level = $c2_row["indent_level"];
106 $c2_element_id = $c2_row["element_id"];
107 $c2_element_order = $c2_row["element_order"];
108
109 if (!($c2_element_id > 0)) {
110 $passed = 0;
111 printf("Failed. child element #%d tried to reference non-existent element #%d as parent.<br>\n", $element_id, $parent_id);
112 }
113
114 if (!($c2_element_order < $element_order)) {
115 $passed = 0;
116 printf("Failed. child element #%d tried to reference later-occuring element #%d as parent.<br>\n", $element_id, $parent_id);
117 }
118
119 if (!($c2_indent_level == ($indent_level - 1))) {
120 $passed = 0;
121 printf("Failed. child element #%d is not exactly one generation older than parent element #%d.<br>\n", $element_id, $parent_id);
122 }
123
124 }
125 if ($passed == 1) printf("Passed.<br>\n");
126 printf("<BR>\n");
127
128 /*************************
129 ** Order integrity test **
130 *************************/
131
132 printf("<b>Order integrity test:</b><br>\n");
133 printf("Order uniqueness check: ");
134 if ($num_orders == $num_rows) printf("Passed");
135 else {
136 printf("Failed");
137 $passed = 0;
138 }
139 printf("<BR>\n");
140
141 printf("Order start at 1 check: ");
142 if ($num_rows > 0) {
143 if ($min_order == 1) printf("Passed");
144 else {
145 printf("Failed");
146 $passed = 0;
147 }
148 }
149 else printf("(Empty page)");
150 printf("<br>\n");
151
152 printf("Order max %d check: ", $num_rows);
153 if ($num_rows == $num_orders && $num_rows == $max_order) printf ("passed");
154 else {
155 printf("Failed");
156 $passed = 0;
157 }
158 printf("<br><br>\n");
159
160 /***********************************************************************
161 * Compare given indent level with the calculated/traversed equivalent. *
162 ***********************************************************************/
163
164 printf("<b>Generation traversal tests:</b><br> ");
165 $passed_gen = 1;
166 $sql = "SELECT
167 element_id,
168 parent_id,
169 indent_level
170 FROM
171 element
172 WHERE page_id = "
173 . $page_id
174 . " ORDER BY element_order";
175
176 $rs = xx_tryquery($sql);
177
178 while ($row = xx_fetch_array ($rs, xx_ASSOC)) {
179 $element_id = $row["element_id"];
180 $indent_level = $row["indent_level"];
181 $parent_id = $row["parent_id"];
182 $gen_level = 0;
183
184 // Call the generational calculator for each element
185 $gen_level = genCalc($element_id, $gen_level, $page_id, $parent_id);
186
187 if ($gen_level != $indent_level) {
188 printf("Failed. Element ID#%d reported generation of %d, but calculated at %d.<BR>\n", $element_id, $indent_level, $gen_level);
189 $passed = 0;
190 $passed_gen = 0;
191 }
192
193 // printf("Given indent was %s, gen calc. was %s<BR>", $indent_level, $gen_level);
194
195 }
196 if ($passed_gen == 1) printf("Passed.<br>\n");
197 else printf("Failed one or more generation calculations.<br>\n");
198
199 printf("<br>\n");
200
201 printf("<b>Final Summary:</b><br>");
202 if ($passed == 1) printf("This page appears to be bug-free.");
203 else printf("This page failed one or more tests.");
204
205 // Close the table
206 printf("<br><br></td></tr></table>\n");
207
208 printf("</center>\n");
209
210 return $passed;
211
212 }
213
214
215 /**********************************************************
216 Function: genCalc
217 Author: Paul Bramscher
218 Last Modified: 03.04.2004
219 ***********************************************************
220 Purpose:
221 Recursively calculate the traversable generational level of
222 the given element id. If this figure is not equal to its
223 indent level, then there's an error. The fix algorithm
224 will update the indent_level value in the elements table
225 with the calculated value determined here.
226 **********************************************************/
227 function genCalc($element_id, $gen_level, $page_id, $parent_id) {
228
229 // If there is a parent to probe
230 if ($parent_id > 0) {
231
232 // See if the parent actually exists
233 $sql = "SELECT element_id, parent_id
234 FROM element
235 WHERE element_id = "
236 . $parent_id
237 . " AND page_id = "
238 . $page_id;
239
240 $rs = xx_tryquery($sql);
241 $row = xx_fetch_array ($rs, xx_ASSOC);
242 $probe_parent_id = $row["parent_id"];
243 $probe_element_id = $row["parent_id"];
244
245 // See if the probed element has any parents to probe further
246 if ($probe_element_id > 0) {
247 return 1 + genCalc($probe_element_id, $gen_level, $page_id, $probe_parent_id);
248
249 }
250
251 // No more parents
252 return 1;
253
254 }
255
256 return 0;
257
258 }
259
260
261 /**********************************************************
262 Function: isOrphan
263 Author: Paul Bramscher
264 Last Modified: 03.04.2004
265 ***********************************************************
266 Purpose:
267 Determines if the supplied PageScribe/CourseLib element is
268 an orphaned type element. To be a valid child, a parent must
269 (a) exist, (b) appear earlier in the order of elements
270 1-N on a page, and (c) appear only once. If any criteria
271 fails, the element is said to be orphaned, a bastard or
272 otherwise of problematic ancestry.
273 **********************************************************/
274 function isOrphan($element_id, $element_order, $page_id, $parent_id) {
275
276 //Initialize
277 $orphan = 0;
278
279 if ($parent_id > 0) {
280
281 // First determine if the parent exists.
282 $sql = "SELECT count(*) as par_found
283 FROM element
284 WHERE page_id = "
285 . $page_id
286 . " AND element_id = "
287 . $parent_id
288 . " AND element_order < "
289 . $element_order;
290
291 // testing
292 // printf("orphan probe sql was: %s ", $sql);
293
294 $rs = xx_tryquery($sql);
295 $row = xx_fetch_array ($rs, xx_ASSOC);
296 $par_found = $row["par_found"];
297
298 // Should have only one match. If none (or multiple) set to 0.
299 if ($par_found == 1) $orphan = 0;
300 else $orphan = 1;
301
302 // Output
303 if ($orphan == 1) printf("Found orphan: ID#%d.<br>\n", $element_id);
304
305 }
306
307 return $orphan;
308 }
309
310
311 /**********************************************************
312 Function: purgeOrphans
313 Author: Paul Bramscher
314 Last Modified: 03.04.2004
315 ***********************************************************
316 Purpose:
317 Purges and orphans found on the page.
318 **********************************************************/
319 function purgeOrphans($page_id) {
320
321 printf("<b>Method #2 Delete fostered children and their descendants</b><br><br>\n");
322 printf("<b>Messages:</b><br>\n");
323
324 // Walk through all elements on the page
325 $sql = "SELECT
326 element_id,
327 element_order,
328 parent_id
329 FROM element
330 WHERE page_id = "
331 . $page_id
332 . " ORDER BY element_order";
333
334 $rs = xx_tryquery($sql);
335
336 while ($row = xx_fetch_array ($rs, xx_ASSOC)) {
337 $element_id = $row["element_id"];
338 $element_order = $row["element_order"];
339 $parent_id = $row["parent_id"];
340
341 /* If an orphan, delete it and its first generation.
342 Recall some Egyptian/Biblical curse here.*/
343
344 if ($parent_id > 0 && isOrphan($element_id, $element_order, $page_id, $parent_id)) {
345
346 $sub_sql = "DELETE FROM element
347 WHERE page_id = "
348 . $page_id
349 . " AND element_id = "
350 . $element_id
351 . " AND parent_id = "
352 . $parent_id;
353 if (xx_tryquery ($sub_sql)) printf("Element %d was an orphan. Deleted it.<br>\n", $element_id);
354
355 } // delete all elements which are orphaned
356
357 } // for all elements with parents specified, check if they are orphaned
358
359 } // end purgeOrphans
360
361
362 /**********************************************************
363 Function: purgeRelationships
364 Author: Paul Bramscher
365 Last Modified: 03.04.2004
366 ***********************************************************
367 Purpose:
368 Purges all parent-child relationships on the page, and
369 reduces all elements to root-level elements. Highly
370 destructive, but virtually guaranteed to fix a page.
371 **********************************************************/
372
373 function purgeRelationships($page_id) {
374
375 printf("<b>Method #3 Purge all parent-child relationships!</b><br><br>\n");
376 printf("<b>Messages:</b><br>\n");
377
378 $sql = "UPDATE element
379 SET parent_id = 0, indent_level = 0
380 WHERE page_id = "
381 . $page_id;
382 if (xx_tryquery ($sql)) printf("Purged all!<br>\n");
383
384 } // end purgeRelationships
385
386
387 /**********************************************************
388 Function: scribeFix
389 Author: Paul Bramscher
390 Last Modified: 10.28.2003
391 ***********************************************************
392 Purpose:
393 Fixes a broken PageScribe/CourseLib page based on best
394 guess. Methods:
395 (1) Attach foster children (and their descendants)
396 to most likely parent: first previous parent.
397 (2) Delete foster children (and their descendants).
398 (3) Delete all parent-child relationships, and convert all
399 elements to root-level (guaranteed fix).
400
401 Required steps, automatically followed after any method:
402 (a) First element is 1, Nth element must be N
403 (b) Fill in any "holes" in the element order.
404 (c) Clean up all indent levels.
405 **********************************************************/
406 function scribeFix($method, $page_id){
407
408 printf("<center>\n");
409 printf("<table width=\"90%%\" class=\"backLight\" border=\"1\">\n");
410 printf("<tr><td class=\"cellPlain\">Page Fix Dialog (ID# %d)</td></tr>\n", $page_id);
411 printf("<tr><td><br>\n");
412
413 switch ($method) {
414
415 // Update orphans
416 case 1: updateOrphans($page_id);
417 break;
418
419 // Purge orphans
420 case 2: purgeOrphans($page_id);
421 break;
422
423 // Purge all parent-child relationships
424 case 3: purgeRelationships($page_id);
425 break;
426
427 default:
428 break;
429
430 }
431
432 // Required cleanup, regardless of fix methodology
433 updateOrders($page_id);
434 updateGenerations($page_id);
435
436 printf("<br>Done. Re-run the debugger against this page to determine success: <a href=\"scribe_debug.phtml?page_id=%d\">Debug Page ID#%d</a><br><br>", $page_id, $page_id);
437 printf("</td></tr></table></center>\n");
438
439
440 } // end scribeFix
441
442
443 /**********************************************************
444 Function: updateGenerations
445 Author: Paul Bramscher
446 Last Modified: 03.04.2004
447 ***********************************************************
448 Purpose:
449 Walks through a page and compares calculated generation with
450 reported indent level. When a discrepancy is found, fix it
451 according to the calculated generation.
452 **********************************************************/
453 function updateGenerations($page_id) {
454
455 printf("<br><b>Analyzing generational structure:</b><br>\n");
456
457 // Initialize
458 $passed_gen = 1;
459 $element_count = 0;
460
461 // Load all elements on the page
462 $sql = "SELECT
463 element_id,
464 parent_id,
465 indent_level
466 FROM
467 element
468 WHERE page_id = "
469 . $page_id
470 . " ORDER BY element_order";
471
472 $rs = xx_tryquery($sql);
473
474 while ($row = xx_fetch_array ($rs, xx_ASSOC)) {
475 $element_id = $row["element_id"];
476 $indent_level = $row["indent_level"];
477 $parent_id = $row["parent_id"];
478
479 // Initialize
480 $gen_level = 0;
481
482 // Call the generational calculator for each element
483 $gen_level = genCalc($element_id, $gen_level, $page_id, $parent_id);
484
485 // A discrepancy was founnd
486 if ($gen_level != $indent_level) {
487
488 // MArk as failed
489 $passed_gen = 0;
490
491 // Reset the indent levels
492 $sub_sql = "UPDATE element
493 SET indent_level = "
494 . $gen_level
495 . " WHERE page_id = "
496 . $page_id
497 . " AND element_id = "
498 . $element_id;
499 if (xx_tryquery ($sub_sql)) printf("Element #%d reported generation of %d, but calculated at %d. Fixed.<br>\n", $element_id, $indent_level, $gen_level);
500
501 } // if there is a discrepancy with calculated generation level
502
503 } // for all elements, calculate and fix (if needed) their indents
504
505 if ($passed_gen == 1) printf("No generational errors found.<br>\n");
506
507 } // end updateGenerations
508
509
510 /**********************************************************
511 Function: updateOrders
512 Author: Paul Bramscher
513 Last Modified: 03.04.2004
514 ***********************************************************
515 Purpose:
516 Walks through a page and compares calculated order with
517 reported order. When a discrepancy is found, fix it
518 according to the calculated order.
519 **********************************************************/
520 function updateOrders($page_id) {
521
522 printf("<br><b>Analyzing cardinal orders:</b><br>\n");
523
524 // Initialize
525 $passed_card = 1;
526 $element_count = 0;
527
528 // Cycle through all elements on the page
529 $sql = "SELECT
530 element_id,
531 element_order
532 FROM
533 element
534 WHERE page_id = "
535 . $page_id
536 . " ORDER BY element_order";
537
538 $rs = xx_tryquery($sql);
539
540 while ($row = xx_fetch_array ($rs, xx_ASSOC)) {
541 $element_id = $row["element_id"];
542 $element_order = $row["element_order"];
543
544 // Increment row counter
545 $element_count++;
546
547 // If there's an order problem, do this
548 if ($element_count != $element_order) {
549
550 // Mark as failed
551 $passed_card = 0;
552
553 // Reset the order
554 $sub_sql = "UPDATE element
555 SET element_order = "
556 . $element_count
557 . " WHERE page_id = "
558 . $page_id
559 . " AND element_id = "
560 . $element_id;
561 if (xx_tryquery ($sub_sql)) printf("Row #%d reported cardinal order of %d, but calculated at %d. Fixed.<br>\n", $element_count, $element_order, $element_count);
562
563 } // if an order discrepancy was found
564
565 } // for all elements, check their orders and fix (if needed)
566
567 // If no problems found
568 if ($passed_card == 1) printf("No cardinal order errors found.<br>\n");
569
570 } // end updateOrders
571
572
573 /**********************************************************
574 Function: updateOrphans
575 Author: Paul Bramscher
576 Last Modified: 03.04.2004
577 ***********************************************************
578 Purpose:
579 Walks through a page and hunts for orphaned/bastard
580 children. Hunts for most likely parent and attaches the
581 child to it.
582 **********************************************************/
583 function updateOrphans($page_id) {
584
585 // Initialize
586 $passed_orphan = 1;
587
588 printf("<b>Method #1 Attach orphans to a foster parent</b><br><br>\n");
589 printf("<b>Messages:</b><br>\n");
590
591 $sql = "SELECT
592 element_id,
593 element_order,
594 parent_id,
595 indent_level
596 FROM element
597 WHERE page_id = "
598 . $page_id
599 . " ORDER BY element_order";
600
601 $rs = xx_tryquery($sql);
602
603 while ($row = xx_fetch_array ($rs, xx_ASSOC)) {
604 $element_id = $row["element_id"];
605 $element_order = $row["element_order"];
606 $parent_id = $row["parent_id"];
607 $indent_level = $row["indent_level"];
608
609 $new_parent_id = parentProbe($page_id, $element_order, $indent_level);
610 $orphaned = 0;
611 $orphaned = isOrphan($element_id, $element_order, $page_id, $parent_id);
612
613 // Hunt for most likely parent, and assign to it instead.
614 if ($parent_id > 0 && $orphaned == 1) {
615
616 // Mark as failed
617 $passed_orphan = 0;
618
619 $sub_sql = "UPDATE element
620 SET parent_id = "
621 . $new_parent_id
622 . " WHERE page_id = "
623 . $page_id
624 . " AND element_id = "
625 . $element_id;
626 if (xx_tryquery ($sub_sql)) printf("Element #%d orphaned. Reassigned to parent #%d<br>\n", $element_id, $new_parent_id);
627
628 } // reassign problematic elements
629
630 } // for all elements with a problematic ancestry, find a most likely parent
631
632 if ($passed_orphan == 1) printf("No orphans found.<br>\n");
633
634 } // end updateOrphans
635 ?>

  ViewVC Help
Powered by ViewVC 1.1.26