class HeartbeatActivity in Heartbeat 7
Same name and namespace in other branches
- 6.4 includes/heartbeatactivity.inc \HeartbeatActivity
- 6.3 includes/heartbeatactivity.inc \HeartbeatActivity
Class defines an activity message object
Hierarchy
- class \HeartbeatActivity extends \stdClass
Expanded class hierarchy of HeartbeatActivity
File
- includes/
heartbeatactivity.inc, line 12 - HeartbeatActivity object Defines one heartbeat activity object.
View source
class HeartbeatActivity extends stdClass {
// DB fields
public $uaid = 0;
public $message_id = '';
public $uid = 0;
public $uid_access = TRUE;
public $uid_target = 0;
public $nid = 0;
public $cid = 0;
public $nid_access = TRUE;
public $nid_target = 0;
public $nid_target_access = TRUE;
public $in_group = 0;
public $timestamp = 0;
public $language = 'en';
public $message = '';
public $message_concat = '';
public $access = HEARTBEAT_PUBLIC_TO_ALL;
public $variables = array();
public $attachments = array();
public $additions = NULL;
public $index = NULL;
public $buttons = array();
public $classes = '';
// User object of the uid, being the actor of activity
public $actor = NULL;
// Template composite
public $template = '';
// Global properties on message base
public $show_time = 0;
public $count = 0;
// count for same instance
public $target_count = 0;
// count for same instance that is merged by target
public $show_message_times = 1;
public $show_message_times_grouped = 1;
public $delete_access = FALSE;
public $actor_access = FALSE;
// Template variables
public $name = 'heartbeatactivity';
public $type = 'heartbeatactivity';
public $streamname = '';
public $view_mode = 'full';
public $content = array();
//public $_vars = NULL;
/**
* constructor
* @param $data Array or Object with fields that can match this object
* Data for the message, some are converted.
* It's possible to give a sql-result set as data which will
* adapt to a heartbeatActivity object.
* @param $template HeartbeatMessageTemplate
* holds the template data.
*/
function __construct($data, HeartbeatMessageTemplate $template) {
//$this->_vars = new stdClass();
$this->template = $template;
$this->additions = new stdClass();
$this->message_id = $this->template->message_id;
if (is_object($data)) {
$data = (array) $data;
}
if (isset($data['uaid'])) {
$this->uaid = $data['uaid'];
}
if (isset($data['count'])) {
$this->count = $data['count'];
}
$this->timestamp = isset($data['timestamp']) ? $data['timestamp'] : $_SERVER['REQUEST_TIME'];
$this
->set_actor($data);
if (isset($data['uid_target'])) {
$this->uid_target = $data['uid_target'];
}
if (isset($data['nid'])) {
$this->nid = $data['nid'];
}
if (isset($data['nid_target'])) {
$this->nid_target = $data['nid_target'];
}
if (isset($data['cid'])) {
$this->cid = $data['cid'];
}
if (isset($data['in_group'])) {
$this->in_group = $data['in_group'];
}
if (isset($data['variables'])) {
$this
->set_variables($data['variables']);
}
if (isset($data['extra']['duplicate'])) {
$this->variables['duplicate'] = $data['extra']['duplicate'];
}
// Check access on the buttons and put their state onto the object
$this
->set_delete_access();
// Add buttons. Other modules can still add or remove buttons
// using the available entity hooks.
$this
->add_buttons();
// Set the access for this message.
$this
->setAccess($data);
// Build the runtime activity message.
$this
->rebuild_message();
foreach ($data as $key => $value) {
if (strpos($key, 'field_') === 0) {
$this->{$key} = $value;
}
}
}
/**
* Set the actor on the activity.
*/
public function set_actor($data) {
if (isset($data['actor'])) {
$this->actor = $data['actor'];
}
elseif (!empty($data['name']) && !empty($data['created'])) {
$this->actor = new stdClass();
$this->actor->uid = $data['uid'];
$this->actor->name = $data['name'];
$this->actor->mail = $data['mail'];
$this->actor->theme = $data['theme'];
$this->actor->signature = $data['signature'];
$this->actor->signature_format = $data['signature_format'];
$this->actor->created = $data['created'];
$this->actor->access = $data['users_access'];
$this->actor->login = $data['login'];
$this->actor->status = $data['status'];
$this->actor->timezone = $data['timezone'];
$this->actor->language = $data['language'];
$this->actor->picture = $data['picture'];
$this->actor->init = $data['init'];
$this->actor->data = unserialize($data['data']);
}
else {
$this->actor = user_load(isset($data['uid']) ? $data['uid'] : $GLOBALS['user']->uid);
}
$this->uid = $this->actor->uid;
}
/**
* setAccess().
*/
public function setAccess($raw_data) {
// By default, we always use the logged "access".
$this->access = HEARTBEAT_PUBLIC_TO_ALL;
// In most cases (hopefully), the property at the time the activity
// occurred will be set and gets priority. This value is calculated
// from template access, user profile privacy or custom access.
if (isset($raw_data['access'])) {
$this->access = (int) $raw_data['access'];
}
// If the actor of the message has set this type of message, inherit.
if (isset($raw_data['access_status']) && $raw_data['access_status'] <= $this->access) {
$this->access = (int) $raw_data['access_status'];
}
// If for some reason what so ever, the template restriction had been changed
// into some lower permission than calculated, lower down the access.
if ((int) $this->template->perms < $this->access) {
$this->access = (int) $this->template->perms;
}
}
/**
* isPrivate().
*/
public function isPrivate() {
return $this->access === HEARTBEAT_PRIVATE;
}
/**
* hasAccess().
*
* @param Object $account
* The User object to check access for.
* @param HeartbeatStream $heartbeatStream
* Optional heartbeat stream object where the account object is the viewer.
*
*/
public function hasAccess($account, $heartbeatStream = NULL) {
// Case user1 is not related to userA and userB. UserA and UserB are related.
// user1 views site activity.
if (isset($heartbeatStream)) {
$account = $heartbeatStream
->getViewer();
}
else {
$heartbeatStream = heartbeat_stream('singleactivity');
}
$access_activity_profiles = user_access('access heartbeat activity profiles', $account);
$access_profiles = user_access('access user profiles', $account);
// Remove messages set private by site administrator
// and remove messages set private by user profile setting.
if ($this
->isPrivate() && $account->uid != $this->actor->uid) {
$heartbeatStream
->addError('Activity message #' . $this->uaid . ' is filtered from display because it is a private message.');
return FALSE;
}
// Replace user links with their name if no access.
if ($access_activity_profiles) {
if (!$access_profiles) {
// TODO Think of a superb way to divide message templates into parts, bound to properties.
// For now, let's try to keep the problem to a minimum.
// Do some tricks to try and solve the problem of profile access from generated links.
if (isset($this->variables['!username'])) {
$this->message = str_replace($this->variables['!username'], $this->actor->name, $this->message);
}
elseif (isset($this->variables['!user'])) {
$this->message = str_replace($this->variables['!user'], $this->actor->name, $this->message);
}
else {
$link = l($this->actor->name, 'user/' . $this->actor->uid);
$this->message = preg_replace("|{$link}|", $this->actor->name, $this->message);
}
}
}
return TRUE;
}
/*
* Rebuild the message with given candidate variables
*/
public function rebuild_message($concat = FALSE) {
$template_message = $concat ? $this->template->message_concat : $this->template->message;
//$this->message = strtr($template_message, $this->variables);
$this->message = t($template_message, $this->variables);
return $this->message;
}
/*
* Rebuild the message with given candidate variables
*/
public function create_grouped_message($candidates, $max_items_to_group = 5) {
global $base_url;
$message_template = $this
->rebuild_message(TRUE);
$message_extension = '';
$message_template = str_replace("%times%", $this->target_count, $message_template);
$message_template = str_replace("%count%", $this->target_count, $message_template);
// Prepare the merged factors from the stored messages
$merged_string = '';
$remains = array();
$target = $this->template->concat_args['group_target'];
$beat = 'beat-item-' . $this->uaid;
$unique = $candidates['variables'];
$count = $candidates['count'];
//count($candidates['variables']);
// Limit the number of displayed (grouped) messages by message
// or left as default global configuration
if (!empty($this->template->concat_args['group_num_max'])) {
$max_items_to_group = $this->template->concat_args['group_num_max'];
}
// Reduce the variables for substitution to the maximum
// Add the remains by keeping the others plus the last one,
// in case the total exceeds the max group setting.
if ($count > $max_items_to_group) {
$count = $max_items_to_group;
$unique = array_slice($unique, 0, $count);
$remains = array_slice($candidates['variables'], $count - 1);
}
// Replacement of placeholder with group targets
// If there is a match for %variable%
// Try to replace the variable with the group_target variables
if (preg_match_all("|\\%(.*)\\%(.*)|U", $message_template, $matches)) {
if (count($remains) > 0) {
$hidden_remains = '<ul id="' . $beat . '_remaining_wrapper" style="display: none;">';
foreach ($remains as $remain) {
$key = isset($remain["@" . $target]) ? $remain["@" . $target] : (isset($remain["!" . $target]) ? $remain["!" . $target] : $remain["%" . $target]);
$hidden_remains .= '<li>' . $key . '</li>';
}
$hidden_remains .= '</ul>';
}
$placeholder = $matches[1][0];
$i = 1;
foreach ($unique as $stored_variables) {
// limit them to the value given by the group variable setting
if (isset($stored_variables["!" . $target])) {
if ($i == 1) {
$merged_string .= $stored_variables["!" . $target];
}
elseif ($i < $count && $count > 2) {
$merged_string .= $this->template->concat_args['merge_separator'];
$merged_string .= $stored_variables["!" . $target];
}
elseif ($i == $count || $count == 2) {
$merged_string .= ' ' . $this->template->concat_args['merge_end_separator'];
if (count($remains) >= 1 && $hidden_remains != '') {
$attributes = array(
'attributes' => array(
'id' => $beat . '_remaining',
'class' => array(
'beat-remaining',
),
),
'absolute' => TRUE,
'fragment' => $beat,
);
$merged_string .= l(t('@num more', array(
'@num' => count($remains),
)), $base_url . request_uri(), $attributes);
$message_extension .= $hidden_remains;
}
else {
$merged_string .= $stored_variables["!" . $target];
}
}
}
$i++;
}
$message_template = str_replace("%" . $placeholder . "%", $merged_string, $message_template);
if (isset($message_extension)) {
$message_template .= $message_extension;
}
}
$this->message = $message_template;
}
/**
* Public function to save activity to database
* @param array raw argument to enforce as is (pre-renderd)
*/
public function save($raw_args = array()) {
if (!empty($this->nid)) {
// if a user selected a language, then we follow i19n
$node = node_load($this->nid);
if (!empty($node->language)) {
return $this
->_save($raw_args, $node->language);
}
}
return $this
->_save($raw_args);
}
/**
* Sets the variables array
* Data variables are stored in an array to use them to build real variables.
* this means that when activity message objects get merged, the variables
* will be filled with variables components from all instances.
*/
public function set_variables($variables = NULL) {
if (!empty($variables)) {
if (is_string($variables)) {
$this->variables = heartbeat_decode_message_variables($variables);
}
elseif (is_array($variables)) {
$this->variables = $variables;
}
}
}
/**
* Add buttons to the activity message.
*/
protected function add_buttons() {
// Internal button.
if ($this->delete_access || $this->actor_access) {
heartbeat_ctools_modal_prepare();
drupal_add_library('system', 'drupal.ajax');
$link = l(t('Delete'), 'heartbeat/nojs/activity/delete/' . $this->uaid, array(
'query' => array(
'destination' => $_GET['q'],
),
'html' => TRUE,
'attributes' => array(
'class' => array(
'use-ajax',
'ctools-modal-ctools-heartbeat-style',
),
'title' => t('Delete'),
),
));
$button = '<span class="hover-delete">' . $link . '</span>';
//$button = '<span class="hover-delete">' . ctools_modal_text_button(t('Delete'), 'heartbeat/nojs/activity/delete/' . $this->uaid, t('Delete'), 'ctools-modal-ctools-heartbeat-style') . '</span>';
$this
->add_button($button);
}
}
/**
* Add button to the activity message.
*/
public function add_button($button) {
$this->buttons[] = $button;
}
/**
* add_attachment().
*/
public function add_attachment($attachment) {
$this->attachments[] = $attachment;
}
/**
* add_plugin().
*/
public function add_plugin($pluginId, iHeartbeatPlugin $plugin) {
if (!isset($this->additions->plugins)) {
$this->additions->plugins = array();
}
$this->additions->plugins[$pluginId] = $plugin;
}
/**
* remove_plugin().
*/
public function remove_plugin($pluginId) {
unset($this->additions->plugins[$pluginId]);
}
/**
* Save activity log
*
* @param array $raw_args
* All variables as key => value.
* @param Object $lang
* Optional lang_code.
*/
private function _save($raw_args = array(), $lang = '') {
// Rebuild arguments with tokens
$args = $this
->rebuild_arguments($raw_args);
return $this
->log_message($args, $lang);
}
/**
* Logs a heartbeat message
* @param string language optional
*
*/
private function log_message($args, $lang = '') {
if (empty($lang)) {
$lang = $GLOBALS['language']->language;
}
// Checks if there should be logging what so ever.
if (empty($this->message)) {
watchdog('heartbeat', 'Error in logging user activity: it is not possible to log empty message', array(), WATCHDOG_ERROR);
return FALSE;
}
// Rewrite access if the user has configured the access state of this message type.
$heartbeat_user_templates = heartbeat_user_templates_load($this->uid);
if (!empty($heartbeat_user_templates) && isset($heartbeat_user_templates[$this->message_id])) {
$this->access = $heartbeat_user_templates[$this->message_id]->status;
}
// Prepare extra variables (hardcoded for node for now)
// TODO think of a cleaner sollution.
if ($this->nid > 0 && ($node = node_load($this->nid))) {
$this->variables['node_type'] = $node->type;
$this->variables['node_status'] = $node->status;
$this->variables['node_uid'] = $node->uid;
}
if ($this->nid_target > 0 && ($node = node_load($this->nid_target))) {
$this->variables['node_target_type'] = $node->type;
$this->variables['node_target_status'] = $node->status;
$this->variables['node_target_uid'] = $node->uid;
}
// Log relational message to user activity
$last_id = db_insert('heartbeat_activity')
->fields(array(
'message_id',
'nid',
'uid',
'nid_target',
'uid_target',
'cid',
'access',
'timestamp',
'language',
'variables',
'in_group',
))
->values(array(
'message_id' => $this->message_id,
'nid' => $this->nid,
'uid' => $this->uid,
'nid_target' => $this->nid_target,
'uid_target' => $this->uid_target,
'cid' => $this->cid,
'access' => $this->access,
'timestamp' => $this->timestamp,
'language' => $lang,
'in_group' => $this->in_group,
'variables' => heartbeat_encode_message_variables($this->variables),
))
->execute();
// Add the uaid.
$this->uaid = $last_id;
// Allow modules to respond to the save of a heartbeat activity message.
module_invoke_all('heartbeat_activity_save', $this);
return $last_id ? $last_id : 0;
}
/**
* protected function to set the delete access for the message.
*/
protected function set_delete_access() {
$this->delete_access = user_access('admin heartbeat delete all');
$this->actor_access = $this->delete_access || $this->uid == $GLOBALS['user']->uid && user_access('admin heartbeat delete own');
}
/**
* Rebuild the arguments for variables
* to share within this object
*
* @param array $raw_input of arguments
*/
private function rebuild_arguments($raw_input) {
$args = array();
// Rebuild arguments with language tokens
foreach ($this->variables as $key => $value) {
$value = filter_xss($value);
// Leave $key[0] == "!" asis
if ($key[0] != "@" || $key[0] != "!") {
continue;
// bad argument
}
$oldkey = $key;
// if argument is prefilled, override
if (isset($raw_input[$oldkey])) {
$args[$key] = $raw_input[$oldkey];
continue;
}
// Argument gets the value as in variables
$args[$key] = $value;
}
return $args;
}
}