Merge branch '1.0.x' into testing
This commit is contained in:
commit
7d214953e3
|
@ -44,7 +44,7 @@ class Fave extends Memcached_DataObject
|
|||
common_log_db_error($fave, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
self::blow('fave:by_notice:%d', $fave->notice_id);
|
||||
self::blow('fave:list:notice_id:%d', $fave->notice_id);
|
||||
|
||||
Event::handle('EndFavorNotice', array($profile, $notice));
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class Fave extends Memcached_DataObject
|
|||
if (Event::handle('StartDisfavorNotice', array($profile, $notice, &$result))) {
|
||||
|
||||
$result = parent::delete();
|
||||
self::blow('fave:by_notice:%d', $this->notice_id);
|
||||
self::blow('fave:list:notice_id:%d', $this->notice_id);
|
||||
|
||||
if ($result) {
|
||||
Event::handle('EndDisfavorNotice', array($profile, $notice));
|
||||
|
@ -156,31 +156,4 @@ class Fave extends Memcached_DataObject
|
|||
|
||||
return $fav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab a list of profile who have favored this notice.
|
||||
*
|
||||
* @return ArrayWrapper masquerading as a Fave
|
||||
*/
|
||||
static function byNotice($noticeId)
|
||||
{
|
||||
$c = self::memcache();
|
||||
$key = Cache::key('fave:by_notice:' . $noticeId);
|
||||
|
||||
$wrapper = $c->get($key);
|
||||
if (!$wrapper) {
|
||||
// @fixme caching & scalability!
|
||||
$fave = new Fave();
|
||||
$fave->notice_id = $noticeId;
|
||||
$fave->find();
|
||||
|
||||
$list = array();
|
||||
while ($fave->fetch()) {
|
||||
$list[] = clone($fave);
|
||||
}
|
||||
$wrapper = new ArrayWrapper($list);
|
||||
$c->set($key, $wrapper);
|
||||
}
|
||||
return $wrapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,23 +55,6 @@ class File extends Memcached_DataObject
|
|||
return 'http://www.facebook.com/login.php' === $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a new file record.
|
||||
*
|
||||
|
|
|
@ -157,6 +157,44 @@ class Memcached_DataObject extends Safe_DataObject
|
|||
return $result;
|
||||
}
|
||||
|
||||
function listGet($cls, $keyCol, $keyVals)
|
||||
{
|
||||
$result = array_fill_keys($keyVals, array());
|
||||
|
||||
$toFetch = array();
|
||||
|
||||
foreach ($keyVals as $keyVal) {
|
||||
$l = self::cacheGet(sprintf("%s:list:%s:%s", $cls, $keyCol, $keyVal));
|
||||
if ($l !== false) {
|
||||
$result[$keyVal] = $l;
|
||||
} else {
|
||||
$toFetch[] = $keyVal;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($toFetch) > 0) {
|
||||
$i = DB_DataObject::factory($cls);
|
||||
if (empty($i)) {
|
||||
throw new Exception(_('Cannot instantiate class ' . $cls));
|
||||
}
|
||||
$i->whereAddIn($keyCol, $toFetch, $i->columnType($keyCol));
|
||||
if ($i->find()) {
|
||||
while ($i->fetch()) {
|
||||
$copy = clone($i);
|
||||
$copy->encache();
|
||||
$result[$i->$keyCol][] = $copy;
|
||||
}
|
||||
}
|
||||
foreach ($toFetch as $keyVal)
|
||||
{
|
||||
self::cacheSet(sprintf("%s:list:%s:%s", $cls, $keyCol, $keyVal),
|
||||
$result[$keyVal]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function columnType($columnName)
|
||||
{
|
||||
$keys = $this->table();
|
||||
|
|
|
@ -755,62 +755,33 @@ class Notice extends Memcached_DataObject
|
|||
return true;
|
||||
}
|
||||
|
||||
function getUploadedAttachment() {
|
||||
$post = clone $this;
|
||||
$query = 'select file.url as up, file.id as i from file join file_to_post on file.id = file_id where post_id=' . $post->escape($post->id) . ' and url like "%/notice/%/file"';
|
||||
$post->query($query);
|
||||
$post->fetch();
|
||||
if (empty($post->up) || empty($post->i)) {
|
||||
$ret = false;
|
||||
} else {
|
||||
$ret = array($post->up, $post->i);
|
||||
}
|
||||
$post->free();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function hasAttachments() {
|
||||
$post = clone $this;
|
||||
$query = "select count(file_id) as n_attachments from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $post->escape($post->id);
|
||||
$post->query($query);
|
||||
$post->fetch();
|
||||
$n_attachments = intval($post->n_attachments);
|
||||
$post->free();
|
||||
return $n_attachments;
|
||||
}
|
||||
protected $_attachments = -1;
|
||||
|
||||
function attachments() {
|
||||
|
||||
$keypart = sprintf('notice:file_ids:%d', $this->id);
|
||||
if ($this->_attachments != -1) {
|
||||
return $this->_attachments;
|
||||
}
|
||||
|
||||
$idstr = self::cacheGet($keypart);
|
||||
$f2ps = Memcached_DataObject::listGet('File_to_post', 'post_id', array($this->id));
|
||||
|
||||
if ($idstr !== false) {
|
||||
$ids = explode(',', $idstr);
|
||||
} else {
|
||||
$ids = array();
|
||||
$f2p = new File_to_post;
|
||||
$f2p->post_id = $this->id;
|
||||
if ($f2p->find()) {
|
||||
while ($f2p->fetch()) {
|
||||
|
||||
foreach ($f2ps[$this->id] as $f2p) {
|
||||
$ids[] = $f2p->file_id;
|
||||
}
|
||||
}
|
||||
self::cacheSet($keypart, implode(',', $ids));
|
||||
|
||||
$files = Memcached_DataObject::multiGet('File', 'id', $ids);
|
||||
|
||||
$this->_attachments = $files->fetchAll();
|
||||
|
||||
return $this->_attachments;
|
||||
}
|
||||
|
||||
$att = array();
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$f = File::staticGet('id', $id);
|
||||
if (!empty($f)) {
|
||||
$att[] = clone($f);
|
||||
function _setAttachments($attachments)
|
||||
{
|
||||
$this->_attachments = $attachments;
|
||||
}
|
||||
}
|
||||
|
||||
return $att;
|
||||
}
|
||||
|
||||
|
||||
function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
|
@ -1332,6 +1303,8 @@ class Notice extends Memcached_DataObject
|
|||
return $reply;
|
||||
}
|
||||
|
||||
protected $_replies = -1;
|
||||
|
||||
/**
|
||||
* Pull the complete list of @-reply targets for this notice.
|
||||
*
|
||||
|
@ -1339,31 +1312,28 @@ class Notice extends Memcached_DataObject
|
|||
*/
|
||||
function getReplies()
|
||||
{
|
||||
$keypart = sprintf('notice:reply_ids:%d', $this->id);
|
||||
if ($this->_replies != -1) {
|
||||
return $this->_replies;
|
||||
}
|
||||
|
||||
$idstr = self::cacheGet($keypart);
|
||||
$replyMap = Memcached_DataObject::listGet('Reply', 'notice_id', array($this->id));
|
||||
|
||||
if ($idstr !== false) {
|
||||
$ids = explode(',', $idstr);
|
||||
} else {
|
||||
$ids = array();
|
||||
|
||||
$reply = new Reply();
|
||||
$reply->selectAdd();
|
||||
$reply->selectAdd('profile_id');
|
||||
$reply->notice_id = $this->id;
|
||||
|
||||
if ($reply->find()) {
|
||||
while($reply->fetch()) {
|
||||
foreach ($replyMap[$this->id] as $reply) {
|
||||
$ids[] = $reply->profile_id;
|
||||
}
|
||||
}
|
||||
self::cacheSet($keypart, implode(',', $ids));
|
||||
}
|
||||
|
||||
$this->_replies = $ids;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function _setReplies($replies)
|
||||
{
|
||||
$this->_replies = $replies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull the complete list of @-reply targets for this notice.
|
||||
*
|
||||
|
@ -1408,6 +1378,9 @@ class Notice extends Memcached_DataObject
|
|||
*
|
||||
* @return array of Group objects
|
||||
*/
|
||||
|
||||
protected $_groups = -1;
|
||||
|
||||
function getGroups()
|
||||
{
|
||||
// Don't save groups for repeats
|
||||
|
@ -1416,30 +1389,30 @@ class Notice extends Memcached_DataObject
|
|||
return array();
|
||||
}
|
||||
|
||||
if ($this->_groups != -1)
|
||||
{
|
||||
return $this->_groups;
|
||||
}
|
||||
|
||||
$gis = Memcached_DataObject::listGet('Group_inbox', 'notice_id', array($this->id));
|
||||
|
||||
$ids = array();
|
||||
|
||||
$keypart = sprintf('notice:groups:%d', $this->id);
|
||||
|
||||
$idstr = self::cacheGet($keypart);
|
||||
|
||||
if ($idstr !== false) {
|
||||
$ids = explode(',', $idstr);
|
||||
} else {
|
||||
$gi = new Group_inbox();
|
||||
|
||||
$gi->selectAdd();
|
||||
$gi->selectAdd('group_id');
|
||||
|
||||
$gi->notice_id = $this->id;
|
||||
|
||||
$ids = $gi->fetchAll('group_id');
|
||||
|
||||
self::cacheSet($keypart, implode(',', $ids));
|
||||
foreach ($gis[$this->id] as $gi)
|
||||
{
|
||||
$ids[] = $gi->group_id;
|
||||
}
|
||||
|
||||
$groups = User_group::multiGet('id', $ids);
|
||||
|
||||
return $groups->fetchAll();
|
||||
$this->_groups = $groups->fetchAll();
|
||||
|
||||
return $this->_groups;
|
||||
}
|
||||
|
||||
function _setGroups($groups)
|
||||
{
|
||||
$this->_groups = $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2462,7 +2435,7 @@ class Notice extends Memcached_DataObject
|
|||
function __sleep()
|
||||
{
|
||||
$vars = parent::__sleep();
|
||||
$skip = array('_original', '_profile');
|
||||
$skip = array('_original', '_profile', '_groups', '_attachments', '_faves', '_replies');
|
||||
return array_diff($vars, $skip);
|
||||
}
|
||||
|
||||
|
@ -2503,4 +2476,120 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
return Memcached_DataObject::pivotGet('Profile', 'id', $ids);
|
||||
}
|
||||
|
||||
static function fillGroups(&$notices)
|
||||
{
|
||||
$ids = self::_idsOf($notices);
|
||||
|
||||
$gis = Memcached_DataObject::listGet('Group_inbox', 'notice_id', $ids);
|
||||
|
||||
$gids = array();
|
||||
|
||||
foreach ($gis as $id => $gi)
|
||||
{
|
||||
foreach ($gi as $g)
|
||||
{
|
||||
$gids[] = $g->group_id;
|
||||
}
|
||||
}
|
||||
|
||||
$gids = array_unique($gids);
|
||||
|
||||
$group = Memcached_DataObject::pivotGet('User_group', 'id', $gids);
|
||||
|
||||
foreach ($notices as $notice)
|
||||
{
|
||||
$grps = array();
|
||||
$gi = $gis[$notice->id];
|
||||
foreach ($gi as $g) {
|
||||
$grps[] = $group[$g->group_id];
|
||||
}
|
||||
$notice->_setGroups($grps);
|
||||
}
|
||||
}
|
||||
|
||||
static function _idsOf(&$notices)
|
||||
{
|
||||
$ids = array();
|
||||
foreach ($notices as $notice) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
$ids = array_unique($ids);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
static function fillAttachments(&$notices)
|
||||
{
|
||||
$ids = self::_idsOf($notices);
|
||||
|
||||
$f2pMap = Memcached_DataObject::listGet('File_to_post', 'post_id', $ids);
|
||||
|
||||
$fileIds = array();
|
||||
|
||||
foreach ($f2pMap as $noticeId => $f2ps) {
|
||||
foreach ($f2ps as $f2p) {
|
||||
$fileIds[] = $f2p->file_id;
|
||||
}
|
||||
}
|
||||
|
||||
$fileIds = array_unique($fileIds);
|
||||
|
||||
$fileMap = Memcached_DataObject::pivotGet('File', 'id', $fileIds);
|
||||
|
||||
foreach ($notices as $notice)
|
||||
{
|
||||
$files = array();
|
||||
$f2ps = $f2pMap[$notice->id];
|
||||
foreach ($f2ps as $f2p) {
|
||||
$files[] = $fileMap[$f2p->file_id];
|
||||
}
|
||||
$notice->_setAttachments($files);
|
||||
}
|
||||
}
|
||||
|
||||
protected $_faves = -1;
|
||||
|
||||
/**
|
||||
* All faves of this notice
|
||||
*
|
||||
* @return array Array of Fave objects
|
||||
*/
|
||||
|
||||
function getFaves()
|
||||
{
|
||||
if ($this->_faves != -1) {
|
||||
return $this->_faves;
|
||||
}
|
||||
$faveMap = Memcached_DataObject::listGet('Fave', 'notice_id', array($noticeId));
|
||||
$this->_faves = $faveMap[$noticeId];
|
||||
return $this->_faves;
|
||||
}
|
||||
|
||||
function _setFaves($faves)
|
||||
{
|
||||
$this->_faves = $faves;
|
||||
}
|
||||
|
||||
static function fillFaves(&$notices)
|
||||
{
|
||||
$ids = self::_idsOf($notices);
|
||||
$faveMap = Memcached_DataObject::listGet('Fave', 'notice_id', $ids);
|
||||
foreach ($notices as $notice) {
|
||||
$notice->_setFaves($faveMap[$notice->id]);
|
||||
}
|
||||
}
|
||||
|
||||
static function fillReplies(&$notices)
|
||||
{
|
||||
$ids = self::_idsOf($notices);
|
||||
$replyMap = Memcached_DataObject::listGet('Reply', 'notice_id', $ids);
|
||||
foreach ($notices as $notice) {
|
||||
$replies = $replyMap[$notice->id];
|
||||
$ids = array();
|
||||
foreach ($replies as $reply) {
|
||||
$ids[] = $reply->profile_id;
|
||||
}
|
||||
$notice->_setReplies($ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ class AttachmentList extends Widget
|
|||
*/
|
||||
function show()
|
||||
{
|
||||
$att = File::getAttachments($this->notice->id);
|
||||
$att = $this->notice->attachments();
|
||||
if (empty($att)) return 0;
|
||||
$this->showListStart();
|
||||
|
||||
|
|
|
@ -81,9 +81,16 @@ abstract class FilteringNoticeStream extends NoticeStream
|
|||
break;
|
||||
}
|
||||
|
||||
while ($raw->fetch()) {
|
||||
if ($this->filter($raw)) {
|
||||
$filtered[] = clone($raw);
|
||||
$notices = $raw->fetchAll();
|
||||
|
||||
// XXX: this should probably only be in the scoping one.
|
||||
|
||||
Notice::fillGroups($notices);
|
||||
Notice::fillReplies($notices);
|
||||
|
||||
foreach ($notices as $notice) {
|
||||
if ($this->filter($notice)) {
|
||||
$filtered[] = $notice;
|
||||
if (count($filtered) >= $total) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -124,6 +124,10 @@ class NoticeList extends Widget
|
|||
|
||||
static function prefill(&$notices, $avatarSize=AVATAR_STREAM_SIZE)
|
||||
{
|
||||
// Prefill attachments
|
||||
Notice::fillAttachments($notices);
|
||||
// Prefill attachments
|
||||
Notice::fillFaves($notices);
|
||||
// Prefill the profiles
|
||||
$profiles = Notice::fillProfiles($notices);
|
||||
// Prefill the avatars
|
||||
|
|
|
@ -470,9 +470,9 @@ class ThreadedNoticeListFavesItem extends NoticeListActorsItem
|
|||
{
|
||||
function getProfiles()
|
||||
{
|
||||
$fave = Fave::byNotice($this->notice->id);
|
||||
$faves = $this->notice->getFaves();
|
||||
$profiles = array();
|
||||
while ($fave->fetch()) {
|
||||
foreach ($faves as $fave) {
|
||||
$profiles[] = $fave->user_id;
|
||||
}
|
||||
return $profiles;
|
||||
|
|
|
@ -20,20 +20,31 @@
|
|||
|
||||
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
|
||||
|
||||
$shortoptions = 'u:n:b:g:j:t:x:z:';
|
||||
$longoptions = array('users=', 'notices=', 'subscriptions=', 'groups=', 'joins=', 'tags=', 'prefix=');
|
||||
$shortoptions = 'b:g:j:n:t:u:w:x:z:';
|
||||
$longoptions = array(
|
||||
'subscriptions=',
|
||||
'groups=',
|
||||
'joins=',
|
||||
'notices=',
|
||||
'tags=',
|
||||
'users=',
|
||||
'words=',
|
||||
'prefix=',
|
||||
'groupprefix'
|
||||
);
|
||||
|
||||
$helptext = <<<END_OF_CREATESIM_HELP
|
||||
Creates a lot of test users and notices to (loosely) simulate a real server.
|
||||
|
||||
-u --users Number of users (default 100)
|
||||
-n --notices Average notices per user (default 100)
|
||||
-b --subscriptions Average subscriptions per user (default no. users/20)
|
||||
-g --groups Number of groups (default 20)
|
||||
-j --joins Number of groups per user (default 5)
|
||||
-n --notices Average notices per user (default 100)
|
||||
-t --tags Number of distinct hash tags (default 10000)
|
||||
-x --prefix User name prefix (default 'testuser')
|
||||
-u --users Number of users (default 100)
|
||||
-w --words Words file (default '/usr/share/dict/words')
|
||||
-x --prefix User name prefix (default 'testuser')
|
||||
-z --groupprefix Group name prefix (default 'testgroup')
|
||||
|
||||
END_OF_CREATESIM_HELP;
|
||||
|
||||
|
@ -300,6 +311,8 @@ function main($usercount, $groupcount, $noticeavg, $subsavg, $joinsavg, $tagmax)
|
|||
}
|
||||
}
|
||||
|
||||
$defaultWordfile = '/usr/share/dict/words';
|
||||
|
||||
$usercount = (have_option('u', 'users')) ? get_option_value('u', 'users') : 100;
|
||||
$groupcount = (have_option('g', 'groups')) ? get_option_value('g', 'groups') : 20;
|
||||
$noticeavg = (have_option('n', 'notices')) ? get_option_value('n', 'notices') : 100;
|
||||
|
@ -308,11 +321,15 @@ $joinsavg = (have_option('j', 'joins')) ? get_option_value('j', 'joins') : 5;
|
|||
$tagmax = (have_option('t', 'tags')) ? get_option_value('t', 'tags') : 10000;
|
||||
$userprefix = (have_option('x', 'prefix')) ? get_option_value('x', 'prefix') : 'testuser';
|
||||
$groupprefix = (have_option('z', 'groupprefix')) ? get_option_value('z', 'groupprefix') : 'testgroup';
|
||||
$wordsfile = (have_option('w', 'words')) ? get_option_value('w', 'words') : '/usr/share/dict/words';
|
||||
$wordsfile = (have_option('w', 'words')) ? get_option_value('w', 'words') : $defaultWordfile;
|
||||
|
||||
if (is_readable($wordsfile)) {
|
||||
$words = file($wordsfile);
|
||||
} else {
|
||||
if ($wordsfile != $defaultWordfile) {
|
||||
// user specified words file couldn't be read
|
||||
throw new Exception("Couldn't read words file: {$wordfile}.");
|
||||
}
|
||||
$words = null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user