3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2010 StatusNet, Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Class for activity streams
23 * Includes faves, notices, and subscriptions.
25 * We extend atomusernoticefeed since it does some nice setup for us.
28 class UserActivityStream extends AtomUserNoticeFeed
30 public $activities = array();
32 const OUTPUT_STRING = 1;
34 public $outputMode = self::OUTPUT_STRING;
39 * @param boolean $indent
40 * @param boolean $outputMode: UserActivityStream::OUTPUT_STRING to return a string,
41 * or UserActivityStream::OUTPUT_RAW to go to raw output.
42 * Raw output mode will attempt to stream, keeping less
43 * data in memory but will leave $this->activities incomplete.
45 function __construct($user, $indent = true, $outputMode = UserActivityStream::OUTPUT_STRING)
47 parent::__construct($user, null, $indent);
49 $this->outputMode = $outputMode;
50 if ($this->outputMode == self::OUTPUT_STRING) {
51 // String buffering? Grab all the notices now.
52 $notices = $this->getNotices();
53 } elseif ($this->outputMode == self::OUTPUT_RAW) {
54 // Raw output... need to restructure from the stringer init.
55 $this->xw = new XMLWriter();
56 $this->xw->openURI('php://output');
57 if(is_null($indent)) {
58 $indent = common_config('site', 'indent');
60 $this->xw->setIndent($indent);
62 // We'll fetch notices later.
65 throw new Exception('Invalid outputMode provided to ' . __METHOD__);
68 // Assume that everything but notices is feasible
69 // to pull at once and work with in memory...
71 $subscriptions = $this->getSubscriptions();
72 $subscribers = $this->getSubscribers();
73 $groups = $this->getGroups();
74 $faves = $this->getFaves();
76 $objs = array_merge($subscriptions, $subscribers, $groups, $faves, $notices);
78 $subscriptions = null;
83 unset($subscriptions);
88 // Sort by create date
90 usort($objs, 'UserActivityStream::compareObject');
92 // We'll keep these around for later, and interleave them into
93 // the output stream with the user's notices.
99 * Interleave the pre-sorted subs/groups/faves with the user's
100 * notices, all in reverse chron order.
102 function renderEntries($format=Feed::ATOM, $handle=null)
107 foreach ($this->objs as $obj) {
109 $act = $obj->asActivity();
110 } catch (Exception $e) {
111 common_log(LOG_ERR, $e->getMessage());
117 if ($this->outputMode == self::OUTPUT_RAW && $start != $end) {
118 // In raw mode, we haven't pre-fetched notices.
119 // Grab the chunks of notices between other activities.
121 $notices = $this->getNoticesBetween($start, $end);
122 foreach ($notices as $noticeAct) {
124 $nact = $noticeAct->asActivity();
125 if ($format == Feed::ATOM) {
126 $nact->outputTo($this, false, false);
129 fwrite($handle, ",");
131 fwrite($handle, json_encode($nact->asArray()));
134 } catch (Exception $e) {
135 common_log(LOG_ERR, $e->getMessage());
141 } catch (Exception $e) {
142 common_log(LOG_ERR, $e->getMessage());
150 if ($format == Feed::ATOM) {
151 // Only show the author sub-element if it's different from default user
152 $act->outputTo($this, false, ($act->actor->id != $this->user->uri));
155 fwrite($handle, ",");
157 fwrite($handle, json_encode($act->asArray()));
160 } catch (Exception $e) {
161 common_log(LOG_ERR, $e->getMessage());
170 if ($this->outputMode == self::OUTPUT_RAW) {
171 // Grab anything after the last pre-sorted activity.
173 $notices = $this->getNoticesBetween(0, $end);
174 foreach ($notices as $noticeAct) {
176 $nact = $noticeAct->asActivity();
177 if ($format == Feed::ATOM) {
178 $nact->outputTo($this, false, false);
181 fwrite($handle, ",");
183 fwrite($handle, json_encode($nact->asArray()));
186 } catch (Exception $e) {
187 common_log(LOG_ERR, $e->getMessage());
191 } catch (Exception $e) {
192 common_log(LOG_ERR, $e->getMessage());
197 function compareObject($a, $b)
199 $ac = strtotime((empty($a->created)) ? $a->modified : $a->created);
200 $bc = strtotime((empty($b->created)) ? $b->modified : $b->created);
202 return (($ac == $bc) ? 0 : (($ac < $bc) ? 1 : -1));
205 function getSubscriptions()
209 $sub = new Subscription();
211 $sub->subscriber = $this->user->id;
214 while ($sub->fetch()) {
215 if ($sub->subscribed != $this->user->id) {
216 $subs[] = clone($sub);
224 function getSubscribers()
228 $sub = new Subscription();
230 $sub->subscribed = $this->user->id;
233 while ($sub->fetch()) {
234 if ($sub->subscriber != $this->user->id) {
235 $subs[] = clone($sub);
249 $fave->user_id = $this->user->id;
252 while ($fave->fetch()) {
253 $faves[] = clone($fave);
262 * @param int $start unix timestamp for earliest
263 * @param int $end unix timestamp for latest
264 * @return array of Notice objects
266 function getNoticesBetween($start=0, $end=0)
270 $notice = new Notice();
272 $notice->profile_id = $this->user->id;
275 $tsstart = common_sql_date($start);
276 $notice->whereAdd("created >= '$tsstart'");
279 $tsend = common_sql_date($end);
280 $notice->whereAdd("created < '$tsend'");
283 $notice->orderBy('created DESC');
285 if ($notice->find()) {
286 while ($notice->fetch()) {
287 $notices[] = clone($notice);
294 function getNotices()
296 return $this->getNoticesBetween();
303 $gm = new Group_member();
305 $gm->profile_id = $this->user->id;
308 while ($gm->fetch()) {
309 $groups[] = clone($gm);
316 function writeJSON($handle)
318 require_once INSTALLDIR.'/lib/activitystreamjsondocument.php';
319 fwrite($handle, '{"items": [');
320 $this->renderEntries(Feed::JSON, $handle);
321 fwrite($handle, ']');