diff options
Diffstat (limited to 'plugins/SocialObject/SocialObject.php')
-rw-r--r-- | plugins/SocialObject/SocialObject.php | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/plugins/SocialObject/SocialObject.php b/plugins/SocialObject/SocialObject.php new file mode 100644 index 000000000..2d740c836 --- /dev/null +++ b/plugins/SocialObject/SocialObject.php @@ -0,0 +1,324 @@ +<?php +/** + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2008, 2009, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +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); + } + } +} |