Сайт-визитка

от 14 000 рублей

Каталог

от 19 000 рублей

Магазин

от 30 000 рублей

Создадим ленту активности с помощью Message

На сайтах с социальным уклоном нередко возникает необходимость создать ленту событий, состоящую из сообщений о том, что пользователь что-то прокомментировал, лайкнул, создал и т.д. Назовем эту ленту — лентой активности.

Создать ее достаточно нетрудно с помощью модуля Message и сейчас мы покажем, как.

Установим модуль message, пройдем в его настройки (admin/structure/messages). Нажмем Add message type.

В этом примере мы создаем сообщение, которое появится если пользователь лайкнет материал (для лайков мы конечно используем модуль Flag). На данном экране помимо названия сообщения мы можем ввести его текст. Текст сообщения поддерживает HTML и токены, к нему мы еще вернемся.

Сообщения в модуле Message — это сущности, со всеми вытекающими из этого полезностями, такими как добавление полей. Нажмем на вкладку Manage Fields:

Мы добавили к данному типу сообщений всего 2 поля типа Entity Reference. Первое поле — это ссылка на материал, который понравился пользователю, а второе — ссылка на сущность флага, через которую реализованы лайки. Собственно, этих двух полей нам достаточно, чтобы сформировать нормальное сообщение в ленту активности.

Сформировать сообщение можно с помощью модуля Rules, но гораздо нагляднее и, откровенно говоря, проще — написать код. Поскольку мы генерируем сообщение всякий раз, когда пользователь лайкнет материал с помощью флага, прицепимся к событию флага, то есть к hook_flag_flag():

function mymodule_flag_flag($flag, $entity_id, $account, $flagging) {
  $message = message_create('new_like_node');
  $w = entity_metadata_wrapper('message', $message);
  $w->field_liked_node_reference->set($entity_id);
  $w->field_flag_reference->set($flagging);
  $w->save();
}

Вот так просто. Мы создаем новую сущность-сообщение с помощью message_create(), а затем заполняем два добавленных нами поля — ссылку на понравившийся материал и ссылку на флаг. Ссылка на материал нужна, чтобы получить доступ к полям материала при генерации текста сообщения, а ссылка на флаг — чтобы удалить сообщение, если пользователь передумал и материал ему больше не нравится.

Именно таким образом, с помощью компактного кода и вызова нужных хуков, можно быстро поднять довольно насыщенную событиями ленту активности.

Но, очевидно, чтобы сообщения отображались - нужно создать и саму ленту. Сделать это элементарно с помощью Views:

  1. Создается новое представление, отображающее сообщения.
  2. В связях (которые relationships) добавляется обязательная связь Сообщение: пользователь uid. Через эту связь мы получим доступ к полям пользователя, для которого сгенерировано сообщение.
  3. В полях (fields) добавляем имя и изображение пользователя (через связь), а также timestamp (т.е. время создания) и Render message (Get text).
  4. В остальном представление делается как обычно.

В результате созданная лента активности будет состоять из полей примерно как на первой иллюстрации к этой заметке. То есть будет выведено имя пользователя, его аватара, дата и время создания сообщения и его текст. Вот на этом тексте мы остановимся подробнее.

Как было показано на скриншоте ранее, текст сообщения задается в поле Message text на странице редактирования типа сообщения. Текст, как видно из того же скриншота, поддерживает токены. Причем, если развернуть доступные токены, то в них окажется и доступ к полям материала, который лайкнул пользователь. Этот доступ, конечно, получается благодаря тому, что при создании сообщения мы сохраняем ссылку на лайкнутый материал.

Следует отметить, что поле текста сообщения хоть и поддерживает токены и форматы ввода, но не позволяет получить быстрый доступ к объекту сообщения ($message), если выбрать формат ввода PHP Filter. Можно спорить, хорошо это или плохо, но здесь мы просто примем это как данность. Мы все равно можем сгенерировать красивый текст сообщения с помощью токенов. В приведенном примере текст сообщения введен такой:

Нравится [message:smart_title]

[message:smart_title] — это созданный нами токен для «умного» вывода заголовка лайкнутого материала. Используем код создания этого токена для иллюстрации:

function mymodule_messages_token_info() {
  $tokens['smart_title'] = array(
    'name' => t("Smart title"),
    'description' => t("Title with node type which will become a link if title is empty."),
  );

  return array(
    'tokens' => array('message' => $tokens),
  );
}

function mymodule_messages_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  if ($type == 'message' && !empty($data['message'])) {
    $message = $data['message'];
    foreach ($tokens as $name => $original) {
      if ($name == 'smart_title') {
        $w = entity_metadata_wrapper('message', $message);
        $node_title = $w->field_liked_node_reference->title->value(array('sanitize' => TRUE));
        $nid = $w->field_liked_node_reference->getIdentifier();
        $type = mb_strtolower(node_type_get_name($w->field_liked_node_reference->type->value()));
        if ($node_title != '') {
          $link = $type . ' ' . l($node_title, 'node/' . $nid);
        } else {
          $link = l($type, 'node/' . $nid);
        }
        $replacements[$original] = $link;
      }
    }
  }
  return $replacements;
}

Данный токен вставляет после слова «Нравится» не просто заголовок материала, а тип материала и заголовок ссылкой. Если же у материала отсутствует заголовок, ссылкой становится тип материала. Таким образом можно вывести как «Нравится заметка в блог «Всем привет!», так и «Нравится фотография», и не потерять при этом ссылку.

Напоследок приведем код, с помощью которого сообщение удаляется в том случае, если пользователю больше не нравится материал и он снял лайк:

function mymodule_flag_unflag($flag, $entity_id, $account, $flagging) {
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'message');
  $query->fieldCondition('field_flag_reference', 'target_id', $flagging->flagging_id);
  $result = $query->execute();
  $message_ids = array_keys($result['message']);
  if (!empty($message_ids)) {
    message_delete_multiple($message_ids);
  }
}

Спасибо за внимание.