function getNotices() { // @fixme there should be a common func for this if (common_config('db', 'type') == 'pgsql') { if (!empty($this->out->tag)) { $tag = pg_escape_string($this->out->tag); } } else { if (!empty($this->out->tag)) { $tag = mysql_escape_string($this->out->tag); } } $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $cutoff = sprintf("fave.modified > '%s'", common_sql_date(time() - common_config('popular', 'cutoff'))); $qry = "SELECT notice.*, {$weightexpr} as weight "; if (isset($tag)) { $qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' . "WHERE {$cutoff} and notice.id = notice_tag.notice_id and '{$tag}' = notice_tag.tag"; } else { $qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . "WHERE {$cutoff}"; } $qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . 'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.reply_to,notice.is_local,notice.source,notice.conversation, ' . 'notice.lat,notice.lon,location_id,location_ns,notice.repeat_of' . ' ORDER BY weight DESC'; $offset = 0; $limit = NOTICES_PER_SECTION + 1; $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; $notice = Memcached_DataObject::cachedQuery('Notice', $qry, 1200); return $notice; }
/** * Delete a Consumer and related tokens and nonces * * XXX: Should this happen in an OAuthDataStore instead? * */ function delete() { // XXX: Is there any reason NOT to do this kind of cleanup? $this->_deleteTokens(); $this->_deleteNonces(); parent::delete(); }
function getProfiles() { $featured_nicks = common_config('nickname', 'featured'); if (!$featured_nicks) { return null; } $quoted = array(); foreach ($featured_nicks as $nick) { $quoted[] = "'{$nick}'"; } $table = "user"; if (common_config('db', 'quote_identifiers')) { $table = '"' . $table . '"'; } $qry = 'SELECT profile.* ' . 'FROM profile JOIN ' . $table . ' on profile.id = ' . $table . '.id ' . 'WHERE ' . $table . '.nickname in (' . implode(',', $quoted) . ') ' . 'ORDER BY profile.created DESC '; $limit = PROFILES_PER_SECTION + 1; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $profile = Memcached_DataObject::cachedQuery('Profile', $qry, 6 * 3600); return $profile; }
function getTags() { $profile = Profile::current(); $keypart = sprintf('Inbox:notice_tag:%d:%d', $this->user->id, $profile->id); $tag = Memcached_DataObject::cacheGet($keypart); if ($tag === false) { $stream = new InboxNoticeStream($this->user, $profile); $ids = $stream->getNoticeIds(0, Inbox::MAX_NOTICES, null, null); if (empty($ids)) { $tag = array(); } else { $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); // @fixme should we use the cutoff too? Doesn't help with indexing per-user. $qry = 'SELECT notice_tag.tag, ' . $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'WHERE notice.id in (' . implode(',', $ids) . ')' . 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $t = new Notice_tag(); $t->query($qry); $tag = array(); while ($t->fetch()) { $tag[] = clone $t; } } Memcached_DataObject::cacheSet($keypart, $tag, 3600); } return new ArrayWrapper($tag); }
function delete() { $f = File::staticGet('id', $this->file_id); if (!empty($f)) { $f->blowCache(); } return parent::delete(); }
/** * Wrapper for record insertion to update related caches */ function insert() { $result = parent::insert(); if ($result) { self::blow('reply:stream:%d', $this->profile_id); } return $result; }
function getNotices($offset, $limit, $sinceId = null, $maxId = null) { $all = Memcached_DataObject::listGet('Notice', 'conversation', array($this->id)); $notices = $all[$this->id]; // Re-order in reverse-chron usort($notices, array('RawConversationNoticeStream', '_reverseChron')); // FIXME: handle since and max $wanted = array_slice($notices, $offset, $limit); return new ArrayWrapper($wanted); }
/** * Get the attachments for a particlar notice. * * @param int $post_id * @return array of File objects */ static function getAttachments($post_id) { $file = new File(); $query = "select file.* from file join file_to_post on (file_id = file.id) where post_id = " . $file->escape($post_id); $file = Memcached_DataObject::cachedQuery('File', $query); $att = array(); while ($file->fetch()) { $att[] = clone $file; } return $att; }
function getProfiles() { $qry = 'SELECT profile.*, count(*) as value ' . 'FROM profile JOIN notice ON profile.id = notice.profile_id ' . (common_config('public', 'localonly') ? 'WHERE is_local = 1 ' : '') . 'GROUP BY profile.id,nickname,fullname,profileurl,homepage,bio,location,profile.created,profile.modified,textsearch ' . 'ORDER BY value DESC '; $limit = PROFILES_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $profile = Memcached_DataObject::cachedQuery('Profile', $qry, 6 * 3600); return $profile; }
function getTags() { $qry = $this->query(); $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $profile_tag = Memcached_DataObject::cachedQuery('Profile_tag', sprintf($qry, $this->out->user->id)); return $profile_tag; }
function prefill($notices) { // XXX: this should probably only be in the scoping one. Notice::fillGroups($notices); Notice::fillReplies($notices); if (common_config('notice', 'hidespam')) { $profiles = Notice::getProfiles($notices); foreach ($profiles as $profile) { $pids[] = $profile->id; } Memcached_DataObject::pivotGet('Profile_role', 'profile_id', $pids, array('role' => Profile_role::SILENCED)); } }
function getPeopletags() { $qry = 'SELECT profile_list.*, subscriber_count as value ' . 'FROM profile_list WHERE profile_list.private = false ' . 'ORDER BY value DESC '; $limit = PEOPLETAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $peopletag = Memcached_DataObject::cachedQuery('Profile_list', $qry, 3600); return $peopletag; }
function getGroups() { $qry = 'SELECT user_group.*, count(*) as value ' . 'FROM user_group JOIN group_member ' . 'ON user_group.id = group_member.group_id ' . 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' . 'ORDER BY value DESC '; $limit = GROUPS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $group = Memcached_DataObject::cachedQuery('User_group', $qry, 3600); return $group; }
function getTags() { $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); // @fixme should we use the cutoff too? Doesn't help with indexing per-user. $qry = 'SELECT notice_tag.tag, ' . $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'WHERE notice.profile_id = %d ' . 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, $this->user->id), 3600); return $tag; }
function getTags() { if (common_config('db', 'type') == 'pgsql') { $weightexpr = 'sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; } else { $weightexpr = 'sum(exp(-(now() - notice_tag.created) / %s))'; } $qry = 'SELECT notice_tag.tag, ' . $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'JOIN group_inbox on group_inbox.notice_id = notice.id ' . 'WHERE group_inbox.group_id = %d ' . 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, common_config('tag', 'dropoff'), $this->group->id), 3600); return $tag; }
function delete() { $this->blowCaches(true); $this->blowFavesCache(true); $this->blowSubsCache(true); $this->query('BEGIN'); $related = array('Reply', 'Fave', 'Notice_tag', 'Group_inbox', 'Queue_item'); if (common_config('inboxes', 'enabled')) { $related[] = 'Notice_inbox'; } foreach ($related as $cls) { $inst = new $cls(); $inst->notice_id = $this->id; $inst->delete(); } $result = parent::delete(); $this->query('COMMIT'); }
function getNotices() { if (common_config('db', 'type') == 'pgsql') { $weightexpr = 'sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; } else { $weightexpr = 'sum(exp(-(now() - fave.modified) / %s))'; } $qry = 'SELECT notice.*, ' . $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . 'GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . 'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.reply_to,notice.is_local,notice.source ' . 'ORDER BY weight DESC'; $offset = 0; $limit = NOTICES_PER_SECTION + 1; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $notice = Memcached_DataObject::cachedQuery('Notice', sprintf($qry, common_config('popular', 'dropoff')), 1200); return $notice; }
/** * Content area * * Shows the list of popular notices * * @return void */ function showContent() { $groupId = intval($this->group->id); $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $cutoff = sprintf("fave.modified > '%s'", common_sql_date(time() - common_config('popular', 'cutoff'))); $qry = 'SELECT notice.*, ' . $weightexpr . ' as weight ' . 'FROM notice ' . "JOIN group_inbox ON notice.id = group_inbox.notice_id " . 'JOIN fave ON notice.id = fave.notice_id ' . "WHERE {$cutoff} AND group_id = {$groupId} " . 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' . 'ORDER BY weight DESC'; $offset = ($this->page - 1) * NOTICES_PER_PAGE; $limit = NOTICES_PER_PAGE + 1; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $notice = Memcached_DataObject::cachedQuery('Notice', $qry, 600); $nl = new NoticeList($notice, $this); $cnt = $nl->show(); if ($cnt == 0) { //$this->showEmptyList(); } $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->page, 'groupfavorited', array('nickname' => $this->group->nickname)); }
function getTags() { $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); // @fixme should we use the cutoff too? Doesn't help with indexing per-group. $names = $this->group->getAliases(); $names = array_merge(array($this->group->nickname), $names); // XXX This is dumb. $quoted = array(); foreach ($names as $name) { $quoted[] = "'{$name}'"; } $namestring = implode(',', $quoted); $qry = 'SELECT notice_tag.tag, ' . $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'JOIN group_inbox on group_inbox.notice_id = notice.id ' . 'WHERE group_inbox.group_id = %d ' . 'AND notice_tag.tag not in (%s) ' . 'GROUP BY notice_tag.tag ' . 'ORDER BY weight DESC '; $limit = TAGS_PER_SECTION; $offset = 0; if (common_config('db', 'type') == 'pgsql') { $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; } else { $qry .= ' LIMIT ' . $offset . ', ' . $limit; } $tag = Memcached_DataObject::cachedQuery('Notice_tag', sprintf($qry, $this->group->id, $namestring), 3600); return $tag; }
/** * Save a mapping between a remote Yammer and local imported user. * * @param integer $user_id ID of the status in StatusNet * @param integer $orig_id ID of the notice in Yammer * * @return Yammer_common new object for this value */ protected static function doRecord($class, $field, $orig_id, $local_id) { $map = parent::staticGet($class, 'id', $orig_id); if (!empty($map)) { return $map; } $map = parent::staticGet($class, $field, $local_id); if (!empty($map)) { return $map; } common_debug("Mapping Yammer {$field} {$orig_id} to local {$field} {$local_id}"); $map = new $class(); $map->id = $orig_id; $map->{$field} = $local_id; $map->created = common_sql_now(); $map->insert(); return $map; }
function staticGet($k, $v = NULL) { return Memcached_DataObject::staticGet('File', $k, $v); }
function staticGet($k, $v = NULL) { return Memcached_DataObject::staticGet('Related_group', $k, $v); }
function &pkeyGet($kv) { return Memcached_DataObject::pkeyGet('Notice_tag', $kv); }
function getNotices($offset, $limit, $sinceId, $maxId) { $all = array(); do { $ids = $this->getNoticeIds($offset, $limit, $sinceId, $maxId); $notices = Memcached_DataObject::pivotGet('Notice', 'id', $ids); // By default, takes out false values $notices = array_filter($notices); $all = array_merge($all, $notices); if (count($notices < count($ids))) { $offset += $limit; $limit -= count($notices); } } while (count($notices) < count($ids) && count($ids) > 0); return new ArrayWrapper($all); }
/** * Handle cascading deletion, on the model of notice and profile. * * This should handle freeing up cached entries for the group's * id, nickname, URI, and aliases. There may be other areas that * are not de-cached in the UI, including the sidebar lists on * GroupsAction */ function delete() { if ($this->id) { // Safe to delete in bulk for now $related = array('Group_inbox', 'Group_block', 'Group_member', 'Related_group'); Event::handle('UserGroupDeleteRelated', array($this, &$related)); foreach ($related as $cls) { $inst = new $cls(); $inst->group_id = $this->id; if ($inst->find()) { while ($inst->fetch()) { $dup = clone $inst; $dup->delete(); } } } // And related groups in the other direction... $inst = new Related_group(); $inst->related_group_id = $this->id; $inst->delete(); // Aliases and the local_group entry need to be cleared explicitly // or we'll miss clearing some cache keys; that can make it hard // to create a new group with one of those names or aliases. $this->setAliases(array()); $local = Local_group::staticGet('group_id', $this->id); if ($local) { $local->delete(); } // blow the cached ids self::blow('user_group:notice_ids:%d', $this->id); } else { common_log(LOG_WARN, "Ambiguous user_group->delete(); skipping related tables."); } parent::delete(); }
/** * Save this keypair into the database. * * Overloads default insert behavior to encode the live key objects * as a flat string for storage. * * @return mixed */ function insert() { $this->keypair = $this->toString(); return parent::insert(); }
/** * Get a single object with multiple keys * * @param array $kv Map of key-value pairs * * @return User_flag_profile found object or null */ function pkeyGet($kv) { return Memcached_DataObject::pkeyGet('User_flag_profile', $kv); }
function staticGet($k, $v = null) { return Memcached_DataObject::staticGet('Notice_inbox', $k, $v); }
static function cachedQuery($cls, $qry, $expiry = 3600) { $c = Memcached_DataObject::memcache(); if (!$c) { $inst = new $cls(); $inst->query($qry); return $inst; } $key_part = Cache::keyize($cls) . ':' . md5($qry); $ckey = Cache::key($key_part); $stored = $c->get($ckey); if ($stored !== false) { return new ArrayWrapper($stored); } $inst = new $cls(); $inst->query($qry); $cached = array(); while ($inst->fetch()) { $cached[] = clone $inst; } $inst->free(); $c->set($ckey, $cached, Cache::COMPRESSED, $expiry); return new ArrayWrapper($cached); }
function staticGet($k, $v = null) { return Memcached_DataObject::staticGet('Invitation', $k, $v); }