/[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 1 - (show annotations)
Fri Dec 5 18:34:18 2003 UTC (20 years, 4 months ago) by dpavlin
File size: 19107 byte(s)
Initial revision

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

  ViewVC Help
Powered by ViewVC 1.1.26