/** determine if any of the ancestors or $node_id itself is already expired * * This climbs the tree upward, starting at $node_id, to see if any nodes * are expired. If an expired node is detected, TRUE is returned. * If none of the nodes are expired, then FALSE is returned. * * Note that this routine looks strictly at the expiry property, it is very * well possible that a node is under embargo, see {@link is_under_embargo()}. * * Also note that this routine currently also tries to 'fix' the node database * when a circular reference is detected. This doesn't really belong here, but * for the time being it is convenient to have this auto-repair mechanism here. * The node that is fixed is the section we are looking at after MAXIMUM_ITERATIONS * tries, which is not necessarily the node we started with. * * @param int $node_id * @param array &$tree family tree * @return bool TRUE if any ancestor (or node_id) is expired, otherwise FALSE * @todo this function also 'repairs' circular references. This should move to a separate * tree-repair function but for the time being it is "convenient" to have automatic repairs... * @uses $DB */ function is_expired($node_id, &$tree) { global $DB; $tries = MAXIMUM_ITERATIONS; $now = strftime('%Y-%m-%d %T'); $node_id = intval($node_id); for ($next_id = $node_id; $next_id != 0 && --$tries > 0; $next_id = $tree[$next_id]['parent_id']) { if ($tree[$next_id]['record']['expiry'] < $now) { return TRUE; } } if ($tries <= 0) { // circular reference detected, try to fix it // insert offending node before first node at the top level // this becomes visible the _next_ time the tree is read from the database $first_id = $tree[0]['first_child_id']; $sort_order = $first_id != 0 ? intval($tree[$first_id]['record']['sort_order']) - 10 : 10; $fields = array('parent_id' => $next_id, 'sort_order' => $sort_order); $where = array('node_id' => $next_id); $sql = db_update_sql('nodes', $fields, $where); $parent_id = intval($tree[$node_id]['parent_id']); logger("is_expired(): circular reference '{$node_id}' (parent '{$parent_id}') fixed with '{$sql}'", WLOG_DEBUG); $DB->exec($sql); } return FALSE; }
/** update one or more fields in a table * * @param string the name of the table to update (without prefix) * @param array an associative array with fieldnames and fieldvalues * @param mixed a single clause or an array with fieldnames => values ((without the WHERE keyword) * @return bool|int FALSE on failure or the number of affected rows * @uses db_update_sql() */ function db_update($tablename, $fields, $where = '') { global $DB; return $DB->exec(db_update_sql($tablename, $fields, $where)); }