/** * Create a new message thread * * @param string $senderUserId * Sender user identifier * @param string|string[] $recipient * Recipient list of user identifiers * @param string $subject * Optional thread name * * @return Thread * New thread */ public function createThread($senderUserId, $recipient, $subject = null) { $recipient = Misc::toArray($recipient); // Generate a unique time based identifier, note that this might // own some risks of conflicts, but very low. SHA-1 gives a 40 // character-long string, we have a database limit of 64 with the // Drupal backend, so this is acceptable $id = $senderUserId . ':' . sha1($senderUserId . implode(',', $recipient) . uniqid('', true)); $chan = $this->backend->createChannel($id, $subject); array_unshift($recipient, $senderUserId); // This is the only non-scalable part of the algorithm foreach ($recipient as $recipientId) { $this->backend->getSubscriber($this->getUserSubscriberId($recipientId))->subscribe($chan->getId()); } return new Thread($this, $chan); }
/** * Notify an action happened on a resource in an arbitrary channel * * @param string|string[] $chanId * @param string $resourceType * @param string|string[] $resourceId * @param string $action * @param array $data * Arbitrary data to send along * @param int $level * Arbitrary level, see Notification::LEVEL_* constants. This value is * purely arbitrary, it is up to the business layer to do something with * it. It does not alters the notification system behavior. * @param boolean $doExcludeCurrent * If set to false the current subscribers won't be excluded from the * current notification recipient list */ public function notifyChannel($chanId, $resourceType, $resourceId, $action, $data = [], $level = null, $doExcludeCurrent = true) { if (null === $level) { $level = NotificationInterface::LEVEL_INFO; } $chanIdList = Misc::toIterable($chanId); $data = ['data' => $data]; $data['id'] = Misc::toArray($resourceId); $type = $resourceType . ':' . $action; try { $exclude = []; if ($doExcludeCurrent && $this->currentSubscribers) { foreach ($this->currentSubscribers as $name) { // Using getSubscriptionIds() will avoid an odd number of // backend queries (at least for SQL backend). I do hope // that our current subscriber does not have thousands... $exclude = array_merge($exclude, $this->backend->getSubscriber($name)->getSubscriptionsIds()); } } $this->prepareNotification($type, $data, $level); // Channels are not automatically created // TODO Find a better a way, to filter out non-existing channels $this->backend->createChannels($chanIdList, true); $this->backend->send($chanIdList, $data, $type, null, $level, $exclude); } catch (ChannelDoesNotExistException $e) { // Nothing to do, no channel means no subscription } catch (Exception $e) { // Any other exception must be shutdown when in production mode if (!$this->silentMode) { throw $e; } } }
/** * Default constructor * * @param string $resourceType * @param scalar|scalar[] $resourceId * @param mixed $resource * @param scalar|scalar[] $userId * @param array $data */ public function __construct($resourceType, $resourceIdList, $userId = null, array $data = []) { parent::__construct(null, $data + ['uid' => $userId]); $this->resourceType = $resourceType; $this->resourceIdList = Misc::toArray($resourceIdList); }