Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
system_integrity_fix_sort_orders.php
1 <?php
28 error_reporting(E_ALL);
29 ini_set('memory_limit', '1024M');
30 if ((php_sapi_name() != 'cli')) {
31  trigger_error("You can only run this script from the command line\n", E_USER_ERROR);
32 }
33 
34 $SYSTEM_ROOT = (isset($_SERVER['argv'][1])) ? $_SERVER['argv'][1] : '';
35 if (empty($SYSTEM_ROOT)) {
36  echo "ERROR: You need to supply the path to the System Root as the first argument\n";
37  exit();
38 }
39 
40 if (!is_dir($SYSTEM_ROOT) || !is_readable($SYSTEM_ROOT.'/core/include/init.inc')) {
41  echo "ERROR: Path provided doesn't point to a Matrix installation's System Root. Please provide correct path and try again.\n";
42  exit();
43 }
44 
45 require_once $SYSTEM_ROOT.'/core/include/init.inc';
46 
47 // check the number of arguments
48 if (count($argv) !== 3) {
49  echo 'Usage: system_integrity_fix_sort_orders.php <SYSTEM_ROOT> <PARENT ASSET ID>'."\n";
50  die;
51 }
52 
53 $parentid = $_SERVER['argv'][2];
54 $parent =& $GLOBALS['SQ_SYSTEM']->am->getAsset($parentid);
55 if (is_null($parent)) {
56  echo "ERROR: Unable to retrieve that asset.\n";
57  exit();
58 }//end if
59 
60 $root_user =& $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('root_user');
61 
62 if (!$GLOBALS['SQ_SYSTEM']->setCurrentUser($root_user)) {
63  echo "ERROR: Failed login as root user\n";
64  exit();
65 }
66 
67 // connect to the DB
68 $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
69 
70 $todo = Array($parentid);
71 $done = Array();
72 
73 echo "\n".'---BEGIN---'."\n";
74 
75 $success = sortAssets($todo, $done);
76 
77 echo "\n".'---COMPLETED---'."\n";
78 
79 // restore the Database connection
80 $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
81 
82 
94 function sortAssets($todo, $done)
95 {
96  if (!empty($todo)) {
97 
98  $parentid = array_shift($todo);
99 
100  // order by existing sort_order
101  // only concerned with TYPE_1 and TYPE_2
102  // retrieve minorids as well because we need them for the recursive behaviour implemented towards the end of this routine
103  $sql = 'SELECT linkid, minorid
104  FROM sq_ast_lnk
105  WHERE majorid = :parentid
106  AND link_type IN ('.MatrixDAL::quote(SQ_LINK_TYPE_1).', '.MatrixDAL::quote(SQ_LINK_TYPE_2).')
107  ORDER BY sort_order ASC';
108  try {
109  $query = MatrixDAL::preparePdoQuery($sql);
110  MatrixDAL::bindValueToPdo($query, 'parentid', $parentid);
111  $results = MatrixDAL::executePdoAssoc($query);
112  } catch (Exception $e) {
113  throw new Exception('Unable to get linkids for parent: '.$parentid.' due to database error: '.$e->getMessage());
114  }
115 
116  echo "\n".'- Updating the sort order for kids of: #'.$parentid.'...';
117 
118  // separate results
119  $childids = $linkids = Array();
120  foreach ($results as $row) {
121  // linkids used to update the sort_order
122  $linkids[] = $row['linkid'];
123  // childids used to look for more parents
124  $childids[] = $row['minorid'];
125  }
126 
127  if (!empty($linkids)) {
128  // there is a limit to CASE statement size in Oracle, that limits it to
129  // 127 WHEN-THEN pairs (in theory), so limit to 127 at a time on Oracle
130  $db_type = MatrixDAL::getDbType();
131  if ($db_type == 'oci') {
132  $chunk_size = 127;
133  } else {
134  $chunk_size = 500;
135  }
136 
137  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
138  foreach (array_chunk($linkids, $chunk_size, TRUE) as $chunk) {
139  $cases = '';
140  foreach ($chunk as $i => $linkid) {
141  $cases .= 'WHEN (linkid = '.$linkid.') THEN '.$i.' ';
142  }
143  $sql = 'UPDATE sq_ast_lnk
144  SET sort_order = CASE '.$cases.' ELSE sort_order END
145  WHERE linkid IN ('.implode(', ', $chunk).')';
146  try {
147  $result = MatrixDAL::executeSql($sql);
148  } catch (Exception $e) {
149  throw new Exception('Unable to update sort_order for parent: '.$parentid.' due to database error: '.$e->getMessage());
150  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
151  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
152  }
153  }
154  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
155  }
156 
157  // ensure we do not update this parent again
158  if (!in_array($parentid, $done)) {
159  $done[] = $parentid;
160  }
161 
162  echo ' [done]';
163 
164  // check each child of the parent to see if the parent is a grandparent (i.e. parent's children have children)
165  // only examining 1 level deep at a time
166  if (!empty($childids)) {
167  echo "\n\t".'- Searching immediate children of: #'.$parentid.' for branches';
168  foreach ($childids as $assetid) {
169  // check we have not processed it yet
170  if (!in_array($assetid, $done)) {
171  // these are the kids that we have already sorted
172  // check to see if they are parents as well
173  // shadow asset links are ignored
174  $sql = 'SELECT minorid
175  FROM sq_ast_lnk
176  WHERE majorid = :assetid';
177  try {
178  $query = MatrixDAL::preparePdoQuery($sql);
179  MatrixDAL::bindValueToPdo($query, 'assetid', $assetid);
180  $children = MatrixDAL::executePdoAssoc($query);
181  } catch (Exception $e) {
182  throw new Exception('Unable to check children of parent: '.$parentid.' due to database error: '.$e->getMessage());
183  }
184 
185  if ((!empty($children)) && count($children) > 1) {
186  // we have a potential new parent
187  // check that the returned children contain at least one TYPE 1 or 2 linked asset
188  // e.g. asset could just be tagged with a thesaurus term (shadow link), meaning it is not a valid parent
189  $valid = FALSE;
190  foreach ($children as $grandchild) {
191  $link = $GLOBALS['SQ_SYSTEM']->am->getLink($grandchild['minorid'], NULL, '', TRUE, NULL, 'minor');
192  if (!empty($link) && (($link['link_type'] == SQ_LINK_TYPE_1) || ($link['link_type'] == SQ_LINK_TYPE_2))) {
193  $valid = TRUE;
194  break;
195  }
196  }
197 
198  if ($valid) {
199  echo "\n\t\t#".$assetid.' is a parent with kids that will be sorted';
200  $todo[] = $assetid;
201  }
202  }
203  }
204  }
205  }
206 
207  echo "\n".'* '.count($todo).' items left to process'."\n";
208  echo '* Using '.round((memory_get_usage()/1048576), 2).' MB'."\n";
209 
210  sortAssets($todo, $done);
211 
212  } else {
213  // there are no more items to process
214  return TRUE;
215  }
216 }
217 
218 
219 ?>