/** * Subscribe to the stream's messages<br/> * If options are not given check the subscription templates: * 1. exact stream name and exact user id * 2. generic stream name and exact user id * 3. exact stream name and generic user * 4. generic stream name and generic user * default is to subscribe to ALL messages. * If options supplied - skip templates and use options<br/><br/> * Using subscribe if subscription is already active will modify existing * subscription - change type(s) or modify notifications * @method subscribe * @param $options=array() {array} * @param {array} [$options.types] array of message types, if this is empty then subscribes to all types * @param {integer} [$options.notifications=0] limit number of notifications, 0 means no limit * @param {datetime} [$options.untilTime=null] time limit, if any for subscription * @param {datetime} [$options.readyTime] time from which user is ready to receive notifications again * @param {string} [$options.userId] the user subscribing to the stream. Defaults to the logged in user. * @param {array} [$options.deliver=array('to'=>'default')] under "to" key, named the field under Streams/rules/deliver config, which will contain the names of destinations, which can include "email", "mobile", "email+pending", "mobile+pending" * @param {boolean} [$options.skipRules] if true, do not attempt to create rules * @param {boolean} [$options.skipAccess] if true, skip access check for whether user can subscribe * @return {Streams_Subscription|false} */ function subscribe($options = array()) { $stream = $this->fetchAsUser($options, $userId, $user); if (empty($options['skipAccess']) and !$stream->testReadLevel('messages')) { if (!$stream->testReadLevel('see')) { throw new Streams_Exception_NoSuchStream(); } throw new Users_Exception_NotAuthorized(); } // first make user a participant $stream->join(array("userId" => $userId, "subscribed" => true, "noVisit" => true, "skipAccess" => Q::ifset($options, 'skipAccess', false))); // check for 'messages' level $s = new Streams_Subscription(); $s->publisherId = $stream->publisherId; $s->streamName = $stream->name; $s->ofUserId = $userId; $s->retrieve(); $type = null; if ($template = $stream->getSubscriptionTemplate('Streams_Subscription', $userId, $type)) { $filter = json_decode($template->filter, true); } else { $filter = array('types' => array(), 'notifications' => 0); } if (isset($options['types'])) { $filter['types'] = !empty($options['types']) ? $options['types'] : $filter['types']; } if (isset($options['notifications'])) { $filter['notifications'] = $options['notifications']; } $s->filter = Q::json_encode($filter); if (isset($options['untilTime'])) { $s->untilTime = $options['untilTime']; } else { if ($type > 0 and $template and $template->duration > 0) { $s->untilTime = date("c", time() + $template->duration); } } if (!$s->save(true)) { return false; } if (empty($options['skipRules'])) { // Now let's handle rules $type2 = null; $template = $stream->getSubscriptionTemplate('Streams_Rule', $userId, $type2); $ruleSuccess = true; if ($type2 !== 0) { $rule = new Streams_Rule(); $rule->ofUserId = $userId; $rule->publisherId = $stream->publisherId; $rule->streamName = $stream->name; if (empty($template) and $rule->retrieve()) { $ruleSuccess = false; } else { $rule->readyTime = isset($options['readyTime']) ? $options['readyTime'] : new Db_Expression('CURRENT_TIMESTAMP'); $rule->filter = !empty($template->filter) ? $template->filter : '{"types":[],"labels":[]}'; $rule->relevance = !empty($template->relevance) ? $template->relevance : 1; $rule->deliver = !empty($template->deliver) ? $template->deliver : Q::json_encode(Q::ifset($options, 'deliver', array('to' => 'default'))); $ruleSuccess = !!$rule->save(); } } } // skip error testing for rule save BUT inform node. // Node can notify user to check the rules Q_Utils::sendToNode(array("Q/method" => "Streams/Stream/subscribe", "subscription" => Q::json_encode($s->toArray()), "stream" => Q::json_encode($stream->toArray()), "success" => Q::json_encode($ruleSuccess))); // Post Streams/subscribe message to the stream $stream->post($userId, array('type' => 'Streams/subscribe'), true); // Now post Streams/subscribed message to Streams/participating Streams_Message::post($userId, $userId, 'Streams/participating', array('type' => 'Streams/subscribed', 'instructions' => Q::json_encode(array('publisherId' => $stream->publisherId, 'streamName' => $stream->name))), true); return $s; }