Skip to content

Commit

Permalink
feat(inbox): improve inbox layout and queries
Browse files Browse the repository at this point in the history
Better querying for unread messages that exlude message owner
Adds sent messages a single tab in the inbox
  • Loading branch information
hypeJunction committed Sep 22, 2016
1 parent ef1a52a commit 5edee82
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 127 deletions.
1 change: 0 additions & 1 deletion actions/messages/load.php
Expand Up @@ -11,7 +11,6 @@
->setDirection(Inbox::DIRECTION_ALL)
->displayThreaded(false);


$count = $inbox->getCount();
$messages = $inbox->getMessages();
$unread = Inbox::countUnread($user);
Expand Down
96 changes: 68 additions & 28 deletions classes/hypeJunction/Inbox/Inbox.php
Expand Up @@ -68,7 +68,7 @@ public function __construct() {
* @param array $options Additional options to pass to the getter
* @return int
*/
public static function countUnread(ElggUser $user, $msgType = '', array $options = array()) {
public static function countUnread(ElggUser $user, $msgType = '', array $options = []) {
$instance = new Inbox();
$instance->setOwner($user)->setMessageType($msgType)->setReadStatus(false);
return $instance->getCount($options);
Expand Down Expand Up @@ -163,7 +163,11 @@ public function isDisplayThreaded() {
* @return Inbox
*/
public function setDirection($direction = '') {
if (in_array($direction, array(self::DIRECTION_ALL, self::DIRECTION_SENT, self::DIRECTION_RECEIVED))) {
if (in_array($direction, [
self::DIRECTION_ALL,
self::DIRECTION_SENT,
self::DIRECTION_RECEIVED
])) {
$this->direction = $direction;
}
return $this;
Expand All @@ -183,7 +187,7 @@ public function getDirection() {
* @param array $options Additional options to pass to the getter
* @return Message[]
*/
public function getMessages(array $options = array()) {
public function getMessages(array $options = []) {
$options = $this->getFilterOptions($options);
return elgg_get_entities($options);
}
Expand All @@ -194,7 +198,7 @@ public function getMessages(array $options = array()) {
* @param array $options Additional options to pass to the getter
* @return int
*/
public function getCount(array $options = array()) {
public function getCount(array $options = []) {
if ($this->threaded) {
$options = $this->getFilterOptions($options);
$options['selects'][] = 'COUNT(DISTINCT md_msgHash.value_id) AS total';
Expand All @@ -219,43 +223,88 @@ public static function getCountCallback($row) {
* @param array $options Default options
* @return array
*/
public function getFilterOptions($options = array()) {
public function getFilterOptions($options = []) {

if (!is_array($options)) {
$options = array();
$options = [];
}

$options['types'] = 'object';
$options['subtypes'] = Message::SUBTYPE;
$options['owner_guids'] = sanitize_int($this->owner->guid);
$options['owner_guids'] = $this->owner->guid;

$metastrings = [
$this->owner->guid,
'readYet',
$this->readYet,
'msgType',
$this->msgType,
'msgHash',
'toId',
'fromId',
];

$metastrings = array($this->owner->guid, 'readYet', $this->readYet, 'msgType', $this->msgType, 'msgHash', 'toId', 'fromId');
$map = $this->getMetaMap($metastrings);

$options['joins']['md_msgHash'] = "JOIN {$this->dbprefix}metadata md_msgHash ON e.guid = md_msgHash.entity_guid";
$options['joins']['md_msgHash'] = "
JOIN {$this->dbprefix}metadata md_msgHash
ON e.guid = md_msgHash.entity_guid
";
$options['wheres'][] = "md_msgHash.name_id = {$map['msgHash']}";

$direction = $this->getDirection();
if ($direction == self::DIRECTION_SENT) {
$options['joins']['md_fromId'] = "JOIN {$this->dbprefix}metadata md_fromId ON e.guid = md_fromId.entity_guid";
$options['wheres'][] = "md_fromId.name_id = {$map['fromId']} AND md_fromId.value_id = {$map[$this->owner->guid]}";
$options['joins']['md_fromId'] = "
JOIN {$this->dbprefix}metadata md_fromId
ON e.guid = md_fromId.entity_guid
";
$options['wheres'][] = "
md_fromId.name_id = {$map['fromId']}
AND md_fromId.value_id = {$map[$this->owner->guid]}
";
} else if ($direction == self::DIRECTION_RECEIVED) {
$options['joins']['md_toId'] = "JOIN {$this->dbprefix}metadata md_toId ON e.guid = md_toId.entity_guid";
$options['wheres'][] = "md_toId.name_id = {$map['toId']} AND md_toId.value_id = {$map[$this->owner->guid]}";
$options['joins']['md_toId'] = "
JOIN {$this->dbprefix}metadata md_toId
ON e.guid = md_toId.entity_guid
";
$options['wheres'][] = "
md_toId.name_id = {$map['toId']}
AND md_toId.value_id = {$map[$this->owner->guid]}
";
} else if ($this->threaded) {
$options['selects'][] = 'MAX(e.guid) as lastMsg';
$options['group_by'] = "md_msgHash.value_id";
$options['order_by'] = 'MAX(e.guid) DESC';
}

if ($this->msgType) {
$options['joins']['md_msgType'] = "JOIN {$this->dbprefix}metadata md_msgType ON e.guid = md_msgType.entity_guid";
$options['wheres'][] = "md_msgType.name_id = {$map['msgType']} AND md_msgType.value_id = {$map[$this->msgType]}";
$options['joins']['md_msgType'] = "
JOIN {$this->dbprefix}metadata md_msgType
ON e.guid = md_msgType.entity_guid
";
$options['wheres'][] = "
md_msgType.name_id = {$map['msgType']}
AND md_msgType.value_id = {$map[$this->msgType]}
";
}

if (!is_null($this->readYet)) {
$options['joins']['md_readYet'] = "JOIN {$this->dbprefix}metadata md_readYet ON e.guid = md_readYet.entity_guid";
$options['wheres'][] = "md_readYet.name_id = {$map['readYet']} AND md_readYet.value_id = {$map[$this->readYet]}";
$options['joins']['md_readYet'] = "
JOIN {$this->dbprefix}metadata md_readYet
ON e.guid = md_readYet.entity_guid
";
$options['wheres'][] = "
md_readYet.name_id = {$map['readYet']}
AND md_readYet.value_id = {$map[$this->readYet]}
";
$options['joins']['md_fromId'] = "
JOIN {$this->dbprefix}metadata md_fromId
ON e.guid = md_fromId.entity_guid
";
$options['wheres'][] = "
md_fromId.name_id = {$map['fromId']}
AND md_fromId.value_id != {$map[$this->owner->guid]}
";
}

return $options;
Expand All @@ -267,17 +316,8 @@ public function getFilterOptions($options = array()) {
* @param array $metastrings An array of metastrings
* @return array
*/
private static function getMetaMap($metastrings = array()) {
$map = array();
foreach ($metastrings as $metastring) {
if (isset(self::$matamap) && in_array(self::$metamap[$metastring])) {
$map[$metastring] = self::$metamap[$metastring];
} else {
$id = elgg_get_metastring_id($metastring);
self::$metamap[$metastring] = $map[$metastring] = $id;
}
}
return $map;
private static function getMetaMap($metastrings = []) {
return elgg_get_metastring_map($metastrings);
}

}
2 changes: 2 additions & 0 deletions classes/hypeJunction/Inbox/Router.php
Expand Up @@ -118,6 +118,8 @@ public static function resolvePageOwner($hook, $type, $return, $params) {
case 'incoming' :
case 'outbox' :
case 'outgoing' :
case 'sent' :
case 'received' :
$username = array_shift($segments);
if ($username) {
$user = get_user_by_username($username);
Expand Down
92 changes: 72 additions & 20 deletions classes/hypeJunction/Inbox/Thread.php
Expand Up @@ -9,9 +9,10 @@
class Thread {

protected $message;
private $dbprefix;

const LIMIT = 10;

/**
* Construct a magic thread
* @param Message $message Message entity
Expand All @@ -21,6 +22,7 @@ public function __construct(Message $message) {
throw new InvalidArgumentException(get_class() . ' expects an instance of ' . get_class(new Message));
}
$this->message = $message;
$this->dbprefix = elgg_get_config('dbprefix');
}

/**
Expand All @@ -33,13 +35,27 @@ public function getFilterOptions(array $options = array()) {
$options['types'] = Message::TYPE;
$options['subtypes'] = Message::SUBTYPE;
$options['owner_guids'] = $this->message->owner_guid;
$options['metadata_name_value_pairs'][] = array(
'name' => 'msgHash',
'value' => $this->message->getHash(),
);

if (!isset($options['order_by'])) {
$options['order_by'] = 'e.guid ASC';
}

$hash = $this->message->getHash();

$map = elgg_get_metastring_map([
'msgHash',
$hash,
]);

$options['joins']['md_msgHash'] = "
JOIN {$this->dbprefix}metadata md_msgHash
ON e.guid = md_msgHash.entity_guid
";
$options['wheres'][] = "
md_msgHash.name_id = {$map['msgHash']}
AND md_msgHash.value_id = {$map[$hash]}
";

return $options;
}

Expand All @@ -64,7 +80,8 @@ public function getOffset($limit = self::LIMIT) {
* @return Message[]|false
*/
public function getMessages(array $options = array()) {
return elgg_get_entities_from_metadata($this->getFilterOptions($options));
$options = $this->getFilterOptions($options);
return elgg_get_entities_from_attributes($options);
}

/**
Expand All @@ -74,10 +91,34 @@ public function getMessages(array $options = array()) {
* @return Message[]
*/
public function getUnreadMessages(array $options = array()) {
$options['metadata_name_value_pairs'][] = array(
'name' => 'readYet',
'value' => false,
);

$map = elgg_get_metastring_map([
'readYet',
0,
'fromId',
$this->message->owner_guid,
]);

// Check if message was read
$options['joins']['md_readYet'] = "
JOIN {$this->dbprefix}metadata md_readYet
ON e.guid = md_readYet.entity_guid
";
$options['wheres'][] = "
md_readYet.name_id = {$map['readYet']}
AND md_readYet.value_id = {$map[0]}
";

// Exclude messages sent by the viewer
$options['joins']['md_fromId'] = "
JOIN {$this->dbprefix}metadata md_fromId
ON e.guid = md_fromId.entity_guid
";
$options['wheres'][] = "
md_fromId.name_id = {$map['fromId']}
AND md_fromId.value_id != {$map[$this->message->owner_guid]}
";

return $this->getMessages($options);
}

Expand Down Expand Up @@ -159,7 +200,7 @@ public function delete($recursive = true) {
* @param array $options Getter options
* @return ElggBatch
*/
public function getAll($getter = 'elgg_get_entities_from_metadata', $options = array()) {
public function getAll($getter = 'elgg_get_entities_from_attributes', $options = array()) {
$options['limit'] = 0;
$options = $this->getFilterOptions($options);
return new ElggBatch($getter, $options);
Expand All @@ -174,7 +215,7 @@ public function getAll($getter = 'elgg_get_entities_from_metadata', $options = a
public function getMessagesBefore(array $options = array()) {
$options['wheres'][] = "e.guid < {$this->message->guid}";
$options['order_by'] = 'e.guid DESC';
$messages = elgg_get_entities_from_metadata($this->getFilterOptions($options));
$messages = elgg_get_entities_from_attributes($this->getFilterOptions($options));
if (is_array($messages)) {
return array_reverse($messages);
}
Expand All @@ -189,7 +230,7 @@ public function getMessagesBefore(array $options = array()) {
*/
public function getMessagesAfter(array $options = array()) {
$options['wheres'][] = "e.guid > {$this->message->guid}";
return elgg_get_entities_from_metadata($this->getFilterOptions($options));
return elgg_get_entities_from_attributes($this->getFilterOptions($options));
}

/**
Expand All @@ -200,16 +241,27 @@ public function getMessagesAfter(array $options = array()) {
*/
public function getAttachmentsFilterOptions(array $options = array()) {

$dbprefix = elgg_get_config('dbprefix');
$hash = $this->message->getHash();
$map = elgg_get_metastring_map([
'msgHash',
$hash,
]);

$msn = elgg_get_metastring_id('msgHash');
$msv = elgg_get_metastring_id($this->message->getHash());
$options['joins']['md_msgHash'] = "
JOIN {$this->dbprefix}metadata md_msgHash
ON e.guid = md_msgHash.entity_guid
";
$options['wheres'][] = "
md_msgHash.name_id = {$map['msgHash']}
AND md_msgHash.value_id = {$map[$hash]}
";

$options['joins'][] = "JOIN {$dbprefix}entity_relationships er ON er.guid_two = e.guid";
$options['joins'][] = "JOIN {$dbprefix}metadata md ON er.guid_one = md.entity_guid";
$options['wheres'][] = "er.relationship = 'attached'";
$options['wheres'][] = "md.name_id = $msn AND md.value_id = $msv";
$options['joins']['er_attached'] = "
JOIN {$this->dbprefix}entity_relationships er_attached
ON er_attached.guid_two = e.guid
";

$options['joins'][] = "er_attached.relationship = 'attached'";
return $options;
}

Expand Down
14 changes: 11 additions & 3 deletions sass/framework/inbox.scss
Expand Up @@ -123,10 +123,9 @@
}
}

.inbox-unread-count {
.elgg-menu-topbar .inbox-unread-count {
color: white;
background-color: red;

position: absolute;
text-align: center;
top: 2px;
Expand All @@ -137,10 +136,19 @@
line-height: 16px;
font-size: 10px;
font-weight: bold;

@include border-radius(10px);
}

.elgg-menu-filter .inbox-unread-count {
padding: 2px 4px;
background: #999;
margin-left: 5px;
color: #fff;
font-weight: bold;
font-size: 12px;
vertical-align: middle;
@include border-radius(3px);
}

.inbox-messages .elgg-pagination {
display: none;
Expand Down
1 change: 0 additions & 1 deletion views/default/forms/messages/inbox.php
Expand Up @@ -21,7 +21,6 @@
//->setDirection(Inbox::DIRECTION_RECEIVED)
->displayThreaded($threaded);


$count = $inbox->getCount();
$messages = $inbox->getMessages(array(
'limit' => $limit,
Expand Down
2 changes: 1 addition & 1 deletion views/default/forms/messages/sent.php
Expand Up @@ -36,8 +36,8 @@
);

elgg_push_context('inbox-form');
echo elgg_view('framework/inbox/list', $params);
echo elgg_view('framework/inbox/controls/inbox', $params);
echo elgg_view('framework/inbox/list', $params);
echo elgg_view('input/submit', array(
'class' => 'hidden',
));
Expand Down

0 comments on commit 5edee82

Please sign in to comment.