/** * Generate OKAPI changelog entries. This method will call $feeder_method OKAPI * service with the following parameters: array($feeder_keys_param => implode('|', $key_values), * 'fields' => $fields). Then it will generate the changelog, based on the result. * This looks pretty much the same for various object types, that's why it's here. * * If $use_cache is true, then all the dictionaries from $feeder_method will be also * kept in OKAPI cache, for future comparison. * * In normal mode, update the changelog and don't return anything. * In fulldump mode, return the generated changelog entries *instead* of * updating it. */ private static function generate_changelog_entries($feeder_method, $object_type, $feeder_keys_param, $key_name, $key_values, $fields, $fulldump_mode, $use_cache, $cache_timeout = 86400) { # Retrieve the previous versions of all objects from OKAPI cache. if ($use_cache) { $cache_keys1 = array(); $cache_keys2 = array(); foreach ($key_values as $key) { $cache_keys1[] = 'clog#' . $object_type . '#' . $key; } foreach ($key_values as $key) { $cache_keys2[] = 'clogmd5#' . $object_type . '#' . $key; } $cached_values1 = Cache::get_many($cache_keys1); $cached_values2 = Cache::get_many($cache_keys2); if (!$fulldump_mode) { Cache::delete_many($cache_keys1); Cache::delete_many($cache_keys2); } unset($cache_keys1); unset($cache_keys2); } # Get the current values for objects. Compare them with their previous versions # and generate changelog entries. require_once $GLOBALS['rootpath'] . 'okapi/service_runner.php'; $current_values = OkapiServiceRunner::call($feeder_method, new OkapiInternalRequest(new OkapiInternalConsumer(), null, array($feeder_keys_param => implode("|", $key_values), 'fields' => $fields, 'attribution_append' => 'static'))); $entries = array(); foreach ($current_values as $key => $object) { if ($object !== null) { # Currently, the object exists. if ($use_cache) { # First, compare the cached hash. The hash has much longer lifetime # than the actual cached object. $cached_md5 = $cached_values2['clogmd5#' . $object_type . '#' . $key]; $current_md5 = md5(serialize($object)); if ($cached_md5 == $current_md5) { # The object was not changed since it was last replaced. continue; } $diff = self::get_diff($cached_values1['clog#' . $object_type . '#' . $key], $object); if (count($diff) == 0) { # Md5 differs, but diff does not. Weird, but it can happen # (e.g. just after the md5 extension was introduced, or if # md5 somehow expired before the actual object did). continue; } } $entries[] = array('object_type' => $object_type, 'object_key' => array($key_name => $key), 'change_type' => 'replace', 'data' => $use_cache ? $diff : $object); if ($use_cache) { # Save the last-published state of the object, for future comparison. $cached_values2['clogmd5#' . $object_type . '#' . $key] = $current_md5; $cached_values1['clog#' . $object_type . '#' . $key] = $object; } } else { # Currently, the object does not exist. if ($use_cache && $cached_values1['clog#' . $object_type . '#' . $key] === false) { # No need to delete, we have already published its deletion. continue; } $entries[] = array('object_type' => $object_type, 'object_key' => array($key_name => $key), 'change_type' => 'delete'); if ($use_cache) { # Cache the fact, that the object was deleted. $cached_values2['clogmd5#' . $object_type . '#' . $key] = false; $cached_values1['clog#' . $object_type . '#' . $key] = false; } } } if ($fulldump_mode) { return $entries; } else { # Save the entries to the clog table. if (count($entries) > 0) { $data_values = array(); foreach ($entries as $entry) { $data_values[] = gzdeflate(serialize($entry)); } Db::execute("\n insert into okapi_clog (data)\n values ('" . implode("'),('", array_map('mysql_real_escape_string', $data_values)) . "');\n "); } # Update the values kept in OKAPI cache. if ($use_cache) { Cache::set_many($cached_values1, $cache_timeout); Cache::set_many($cached_values2, null); # make it persistent } } }
/** Same as `cache_get`, but it works on multiple keys at once. */ public static function get_many($keys) { $prefixed_keys = array(); foreach ($keys as $key) { $prefixed_keys[] = "facade#" . $key; } $prefixed_result = Cache::get_many($prefixed_keys); $result = array(); foreach ($prefixed_result as $prefixed_key => &$value_ref) { $result[substr($prefixed_key, 7)] =& $value_ref; } return $result; }