. * @copyright 2010 Free Software Foundation, Inc * * @category GNUSocial * @package StatusNet * @author Shashi Gowda * @copyright 2009, 2010, StatusNet, Inc. * @copyright 2010, Free Software Foundation, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 * @link http://daisycha.in */ if (!defined('STATUSNET')) { exit(1); } # Abstract class for social-objects require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; class SocialObject extends Memcached_DataObject { var $slug=null; # used in cache key # save a new object static function saveNew($args) { # save everything, add a # Notice entry too. # call Notice::saveNew with options # like replies, groups and tags. # and, cache blowing action. } function delete() { # delete me and my associated Notice # more cache blowing action parent::delete(); } # make an atom entry function asAtomEntry() { } # make a json object function asJson() { } # return an array for Schema::ensureTable to define the table static function tableDef() { return array(); } # give out a stream, and cache it! static function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0) { Notice::stream($fn, $args, $cachekey, $offset, $limit, $since_id, $max_id); } # try to fetch public stream from the cache if it is there # or hit the DB, notice objects FIXME: make this return both # notices and social-objects function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0) { $ids = self::stream(array($this, '_publicStreamDirect'), array(), 'public:'.self::$slug, $offset, $limit, $since_id, $max_id); return self::getStreamByIds($ids); } # fetch public stream from the db and # return the ids of the notices # see also: Notice::_publicStreamDirect function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $max_id=0) { # make the code look nice :) $table = $this->__table; $id = $table.'.id'; $notice = new Notice(); $this->joinAdd(); $this->joinAdd($notice); # join notice table $this->selectAdd(); // clears it $this->selectAdd($id.' as id'); $this->orderBy($id.' DESC'); if (!is_null($offset)) { $this->limit($offset, $limit); } if (common_config('public', 'localonly')) { $this->whereAdd('notice.is_local = ' . Notice::LOCAL_PUBLIC); } else { # -1 == blacklisted, -2 == gateway (i.e. Twitter) $this->whereAdd('notice.is_local !='. Notice::LOCAL_NONPUBLIC); $this->whereAdd('notice.is_local !='. Notice::GATEWAY); } if ($since_id != 0) { $this->whereAdd($id. ' > ' . $since_id); } if ($max_id != 0) { $this->whereAdd($id. ' <= ' . $max_id); } $ids = array(); if ($this->find()) { while ($this->fetch()) { $ids[] = $this->id; } } $this->free(); $this = NULL; return $ids; } # get all social-objects by user function userStream($user, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { // XXX: I'm not sure this is going to be any faster. It probably isn't. $ids = self::stream(array($user, '_userSreamDirect'), array($user), 'profile:'.$this->slug.':notice_ids:' . $user->id, $offset, $limit, $since_id, $max_id); return self::getStreamByIds($ids); } # some scary, scary (hacked) upstream code follows. function _userStreamDirect($user, $offset, $limit, $since_id, $max_id) { $table = $this->__table; $id = $table.'.id'; $notice = new Notice(); // Temporary hack until notice_profile_id_idx is updated // to (profile_id, id) instead of (profile_id, created, id). // It's been falling back to PRIMARY instead, which is really // very inefficient for a profile that hasn't posted in a few // months. Even though forcing the index will cause a filesort, // it's usually going to be better. if (common_config('db', 'type') == 'mysql') { $index = ''; $query = # join me "select $id as id from notice join $table on ($id = notice.id) ". "force index (notice_profile_id_idx) ". "where notice.profile_id=" . $notice->escape($user->id); if ($since_id != 0) { $query .= " and $id > $since_id"; } if ($max_id != 0) { $query .= " and $id < $max_id"; } $query .= " order by $id DESC"; if (!is_null($offset)) { $query .= " LIMIT $limit OFFSET $offset"; } $this->query($query); } else { $index = ''; $notice->profile_id = $user->id; $this->joinAdd(); $this->joinAdd($notice); $this->selectAdd(); $this->selectAdd("$id as id"); if ($since_id != 0) { $this->whereAdd("$id > $since_id"); } if ($max_id != 0) { $this->whereAdd("$id <= $max_id"); } $this->orderBy("$id DESC"); if (!is_null($offset)) { $this->limit($offset, $limit); } $this->find(); } $ids = array(); while ($this->fetch()) { $ids[] = $this->id; } return $ids; } # get all social-objects in the group function groupStream($group, $offset, $limit, $since_id=null, $max_id=null) { $ids = self::stream(array($this, '_groupStreamDirect'), array($group), 'user_group:'.$this->slug.':notice_ids:' . $group->id, $offset, $limit, $since_id, $max_id); return self::getStreamByIds($ids); } function _groupStreamDirect($group, $offset, $limit, $since_id, $max_id) { $table = $this->__table; $inbox = new Group_inbox(); $inbox->group_id = $group->id; $inbox->joinAdd(); $inbox->joinAdd($this); $inbox->selectAdd(); $inbox->selectAdd('group_inbox.notice_id as id'); if ($since_id != 0) { $inbox->whereAdd('group_inbox.notice_id > ' . $since_id); } if ($max_id != 0) { $inbox->whereAdd('group_inbox.notice_id <= ' . $max_id); } $inbox->orderBy('group_inbox.notice_id DESC'); if (!is_null($offset)) { $inbox->limit($offset, $limit); } $ids = array(); if ($inbox->find()) { while ($inbox->fetch()) { $ids[] = $inbox->notice_id; } } return $ids; } # param: array of ids # returns: array($notices, $social_objects) # an example on how to use this: # # list($notices, $objects) = SocialObject::getStreamByIds($ids); # while($notices->fetch()) { # $obj = $objects[$notices->id]; # if(!empty($obj)) { # # now use $notices and $obj, # # they are associated. # } # } # static function getStreamByIds($ids, $classname=null) { $notices = Notice::getSteamByIds($ids); $objects = array(); if(empty($classname) && function_exists('get_called_class')) { $classname = get_called_class(); # works in php 5.3 + } $cache = common_memcache(); # don't put array wrapper around $objects # keep the id as key if (!empty($cache)) { $objects = array(); foreach ($ids as $id) { $n = $classname::staticGet('id', $id); if (!empty($n)) { $objects[$id] = $n; } } return array($notices, $objects); } else { $object = new $classname(); if (empty($ids)) { return array($notices, array()); } $objects->whereAdd('id in (' . implode(', ', $ids) . ')'); $objects->find(); $objects = array(); while ($object->fetch()) { $objects[$notice->id] = clone($object); } # just return the $objects array, we can then use $notices->id # each time to get the object associated return new array($notices, $objects); } } }