Skip to content

Commit

Permalink
Merge pull request #80 from Gizra/79-message-alter
Browse files Browse the repository at this point in the history
Allow altering of message entities.
  • Loading branch information
jhedstrom authored Mar 16, 2017
2 parents 9da6795 + 749d952 commit bab7b1d
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 36 deletions.
37 changes: 25 additions & 12 deletions message_subscribe.api.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
*/

use Drupal\message\MessageInterface;
use Drupal\message_subscribe\Subscribers\DeliveryCandidate;
use Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface;

/**
* Allow modules to add user IDs that need to be notified.
Expand All @@ -25,30 +27,28 @@
* value. According to this context this function will retrieve the
* related subscribers.
*
* @return array
* Array keyed with the user ID and the value:
* @return \Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface[]|array
* Array of delivery candidate objects keyed with the user ID, or an array of
* arrays with the value (array usage is deprecated and will be removed in
* 2.0):
* - "flags": Array with the flag names that resulted with including
* the user.
* - "notifiers": Array with the Message notifier name plugins.
*/
function hook_message_subscribe_get_subscribers(MessageInterface $message, array $subscribe_options = [], array $context = []) {
return [
2 => [
'flags' => ['subscribe_node'],
'notifiers' => ['sms'],
],
7 => [
'flags' => ['subscribe_og', 'subscribe_user'],
'notifiers' => ['sms', 'email'],
],
2 => new DeliveryCandidate(['subscribe_node'], ['sms'], 2),
7 => new DeliveryCandidate(['subscribe_og', 'subscribe_user'], ['sms', 'email'], 7),
];
}

/**
* Alter the subscribers list.
*
* @param array &$uids
* The array of UIDs as defined by `hook_message_subscribe_get_subscribers()`.
* @param \Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface[]|array &$uids
* The array of delivery candidates as defined by
* `hook_message_subscribe_get_subscribers()`. This can also be an array of
* arrays, but is deprecated.
* @param array $values
* A keyed array of values containing:
* - 'context' - The context array.
Expand All @@ -60,6 +60,19 @@ function hook_message_subscribe_get_subscribers_alter(array &$uids, array $value

}

/**
* Alter the message entity immediately before it is sent.
*
* @param \Drupal\message\MessageInterface $message
* The message entity to be sent. This already has the recipient set as the
* message owner.
* @param \Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface $delivery_candidate
* A delivery candidate object.
*/
function hook_message_subscribe_message_alter(MessageInterface $message, DeliveryCandidateInterface $delivery_candidate) {

}

/**
* @} End of "addtogroup hooks".
*/
17 changes: 13 additions & 4 deletions src/Subscribers.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
use Drupal\message\MessageInterface;
use Drupal\message_notify\MessageNotifier;
use Drupal\message_subscribe\Exception\MessageSubscribeException;
use Drupal\message_subscribe\Subscribers\DeliveryCandidate;
use Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface;
use Drupal\og\MembershipManagerInterface;
use Drupal\user\EntityOwnerInterface;

Expand Down Expand Up @@ -179,20 +181,27 @@ public function sendMessage(EntityInterface $entity, MessageInterface $message,
return;
}

foreach ($uids as $uid => $values) {
foreach ($uids as $uid => $delivery_candidate) {
// Array usage is deprecated, but supported until 2.0.
if (!$delivery_candidate instanceof DeliveryCandidateInterface) {
$delivery_candidate += ['notifiers' => []];
$delivery_candidate = new DeliveryCandidate($delivery_candidate['flags'], $delivery_candidate['notifiers'], $uid);
}

$last_uid = $uid;
// Clone the message in case it will need to be saved, it won't
// overwrite the existing one.
$cloned_message = $message->createDuplicate();
// Push a copy of the original message into the new one.
$cloned_message->original = $message;
// Set the owner to this user.
$cloned_message->setOwnerId($uid);
$cloned_message->setOwnerId($delivery_candidate->getAccountId());

$values += ['notifiers' => []];
// Allow modules to alter the message for the specific user.
$this->moduleHandler->alter('message_subscribe_message', $cloned_message, $delivery_candidate);

// Send the message using the required notifiers.
foreach (array_unique($values['notifiers']) as $notifier_name) {
foreach ($delivery_candidate->getNotifiers() as $notifier_name) {
$options = !empty($notify_options[$notifier_name]) ? $notify_options[$notifier_name] : [];
$options += [
'save on fail' => FALSE,
Expand Down
92 changes: 92 additions & 0 deletions src/Subscribers/DeliveryCandidate.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php

namespace Drupal\message_subscribe\Subscribers;

/**
* A delivery candidate implementation.
*/
class DeliveryCandidate implements DeliveryCandidateInterface {

/**
* An array of flag IDs that triggered the notification.
*
* @var string[]
*/
protected $flags;

/**
* An array of notifier IDs for delivery.
*
* @var string[]
*/
protected $notifiers;

/**
* The delivery candidate account ID.
*
* @var int
*/
protected $uid;

/**
* Constructs the delivery candidate.
*
* @param string[] $flags
* An array of flag IDs.
* @param string[] $notifiers
* An array of notifier IDs.
* @param int $uid
* The delivery candidate account ID.
*/
public function __construct(array $flags, array $notifiers, $uid) {
$this->flags = $flags;
$this->notifiers = $notifiers;
$this->uid = $uid;
}

/**
* {@inheritdoc}
*/
public function getFlags() {
return array_unique($this->flags);
}

/**
* {@inheritdoc}
*/
public function setFlags(array $flag_ids) {
$this->flags = $flag_ids;
return $this;
}

/**
* {@inheritdoc}
*/
public function getNotifiers() {
return array_unique($this->notifiers);
}

/**
* {@inheritdoc}
*/
public function setNotifiers(array $notifier_ids) {
$this->notifiers = $notifier_ids;
return $this;
}

/**
* {@inheritdoc}
*/
public function getAccountId() {
return $this->uid;
}

/**
* {@inheritdoc}
*/
public function setAccountId($uid) {
$this->uid = $uid;
return $this;
}

}
67 changes: 67 additions & 0 deletions src/Subscribers/DeliveryCandidateInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Drupal\message_subscribe\Subscribers;

/**
* Defines a subscription delivery candidate interface.
*/
interface DeliveryCandidateInterface {

/**
* Get the flags that triggered the subscription.
*
* @return string[]
* An array of subscription flag IDs that triggered the notification.
*/
public function getFlags();

/**
* Sets the flags.
*
* @param array $flag_ids
* An array of flag IDs.
*
* @return static
* Return the object.
*/
public function setFlags(array $flag_ids);

/**
* Get the notifier IDs.
*
* @return string[]
* An array of message notifier plugin IDs.
*/
public function getNotifiers();

/**
* Sets the notifier IDs.
*
* @param string[] $notifier_ids
* An array of notifier IDs.
*
* @return static
* Return the object.
*/
public function setNotifiers(array $notifier_ids);

/**
* Gets the account ID of the recipient.
*
* @return int
* The user ID for the delivery.
*/
public function getAccountId();

/**
* Sets the account ID.
*
* @param int $uid
* The account ID of the delivery candidate.
*
* @return static
* Return the object.
*/
public function setAccountId($uid);

}
32 changes: 21 additions & 11 deletions tests/modules/message_subscribe_test/message_subscribe_test.module
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/

use Drupal\message\MessageInterface;
use Drupal\message_subscribe\Subscribers\DeliveryCandidate;
use Drupal\message_subscribe\Subscribers\DeliveryCandidateInterface;

/**
* Implements hook_message_subscribe_get_subscribers().
Expand All @@ -16,10 +18,7 @@ function message_subscribe_test_message_subscribe_get_subscribers(MessageInterfa

// Add user 4.
return [
4 => [
'flags' => ['foo_flag'],
'notifiers' => ['sms'],
],
4 => new DeliveryCandidate(['foo_flag'], ['email'], 4),
];
}

Expand All @@ -30,12 +29,23 @@ function message_subscribe_test_message_subscribe_get_subscribers_alter(array &$
// Set state variable.
\Drupal::state('message_subscribe_test')->set('alter_hook_called', TRUE);

// Add non-existent user 10001.
$uids[10001] = [
'flags' => ['bar_flag'],
'notifiers' => ['email'],
];
if (!\Drupal::state('message_subscribe_test')->get('disable_subscribers_alter', FALSE)) {
// Add non-existent user 10001. Using an array here until array support
// is removed in 2.0.
$uids[10001] = [
'flags' => ['bar_flag'],
'notifiers' => ['email'],
];

// Remove user 2.
unset($uids[2]);
}
}

// Remove user 2.
unset($uids[2]);
/**
* Implements hook_message_subscribe_message_alter().
*/
function message_subscribe_test_message_subscribe_message_alter(MessageInterface $message, DeliveryCandidateInterface $delivery_candidate) {
$calls = \Drupal::state('message_subscribe_test')->get('message_alter_hook_called', 0);
\Drupal::state('message_subscribe_test')->set('message_alter_hook_called', $calls + 1);
}
2 changes: 1 addition & 1 deletion tests/src/Kernel/QueueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function testQueue() {
}

// Assert message was saved and added to queue.
$uids = array_fill(1, 10, []);
$uids = array_fill(1, 10, ['flags' => [], 'notifiers' => []]);
$subscribe_options = [
'uids' => $uids,
'skip context' => TRUE,
Expand Down
14 changes: 10 additions & 4 deletions tests/src/Kernel/SubscribersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\message\Entity\Message;
use Drupal\message_subscribe\Subscribers\DeliveryCandidate;

/**
* Test getting subscribes from context.
Expand Down Expand Up @@ -311,15 +312,20 @@ public function testHooks() {
$this->assertTrue(\Drupal::state('message_subscribe_test')->get('hook_called'));
$this->assertTrue(\Drupal::state('message_subscribe_test')->get('alter_hook_called'));
$this->assertEquals([
4 => [
'flags' => ['foo_flag'],
'notifiers' => ['sms'],
],
4 => new DeliveryCandidate(['foo_flag'], ['email'], 4),
10001 => [
'flags' => ['bar_flag'],
'notifiers' => ['email'],
],
], $uids);

// Disable the test module from adding a fake user.
\Drupal::state('message_subscribe_test')->set('disable_subscribers_alter', TRUE);

// Send a message and verify the message alter hook is called (should be
// called once for each subscriber, so 2 times).
$this->messageSubscribers->sendMessage($node, $message, [], ['entity access' => FALSE]);
$this->assertEquals(2, \Drupal::state('message_subscribe_test')->get('message_alter_hook_called', FALSE));
}

/**
Expand Down
11 changes: 7 additions & 4 deletions tests/src/Unit/SubscribersTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ public function testSendMessage() {
$module_handler->getImplementations(Argument::any())->willReturn(['foo']);
$module_handler->alter('message_subscribe_get_subscribers', Argument::any(), Argument::any())
->shouldBeCalled();
$module_handler->alter('message_subscribe_message', Argument::any(), Argument::any())
->shouldBeCalled();
$this->moduleHandler = $module_handler->reveal();

// Mock query.
Expand Down Expand Up @@ -216,10 +218,11 @@ public function testSendMessage() {
*/
function foo_message_subscribe_get_subscribers() {
return [
1 => [],
2 => [],
4 => [],
7 => [],
// Verify arrays are still supported until 2.0.
1 => ['flags' => [], 'notifiers' => []],
2 => ['flags' => [], 'notifiers' => []],
4 => ['flags' => [], 'notifiers' => []],
7 => ['flags' => [], 'notifiers' => []],
];
}

Expand Down

0 comments on commit bab7b1d

Please sign in to comment.