Skip to content

Commit

Permalink
Merge pull request #6 from tuyakhov/slack_channel
Browse files Browse the repository at this point in the history
Add slack channel & after notification send event
  • Loading branch information
tuyakhov committed Jul 28, 2018
2 parents 3eb6ea0 + ced82e2 commit b5f9b2c
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 5 deletions.
21 changes: 20 additions & 1 deletion src/Notifier.php
Expand Up @@ -5,6 +5,7 @@

namespace tuyakhov\notifications;
use tuyakhov\notifications\channels\ChannelInterface;
use tuyakhov\notifications\events\NotificationEvent;
use yii\base\Component;
use yii\base\InvalidConfigException;

Expand Down Expand Up @@ -40,6 +41,11 @@
*/
class Notifier extends Component
{
/**
* @event NotificationEvent an event raised right after notification has been sent.
*/
const EVENT_AFTER_SEND = 'afterSend';

/**
* @var array defines available channels
* The syntax is like the following:
Expand All @@ -61,6 +67,7 @@ class Notifier extends Component
* @param array|NotifiableInterface $recipients the recipients that can receive given notifications.
* @param array|NotificationInterface $notifications the notification that should be delivered.
* @return void
* @throws InvalidConfigException
*/
public function send($recipients, $notifications)
{
Expand All @@ -87,7 +94,19 @@ public function send($recipients, $notifications)

$channels = array_intersect($channels, $notification->broadcastOn());
foreach ($channels as $channel) {
$this->getChannelInstance($channel)->send($recipient, $notification);
$channelInstance = $this->getChannelInstance($channel);
try {
\Yii::info("Sending notification " . get_class($notification) . " to " . get_class($recipient) . " via {$channel}", __METHOD__);
$response = $channelInstance->send($recipient, $notification);
} catch (\Exception $e) {
$response = $e;
}
$this->trigger(self::EVENT_AFTER_SEND, new NotificationEvent([
'notification' => $notification,
'recipient' => $recipient,
'channel' => $channel,
'response' => $response
]));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/channels/ActiveRecordChannel.php
Expand Up @@ -34,7 +34,7 @@ public function send(NotifiableInterface $recipient, NotificationInterface $noti
/** @var DatabaseMessage $message */
$message = $notification->exportFor('database');
list($notifiableType, $notifiableId) = $recipient->routeNotificationFor('database');
$this->model->insert(true, [
return $this->model->insert(true, [
'level' => $message->level,
'subject' => $message->subject,
'body' => $message->body,
Expand Down
6 changes: 6 additions & 0 deletions src/channels/ChannelInterface.php
Expand Up @@ -10,5 +10,11 @@

interface ChannelInterface
{
/**
* @param NotifiableInterface $recipient
* @param NotificationInterface $notification
* @return mixed channel response
* @throws \Exception
*/
public function send(NotifiableInterface $recipient, NotificationInterface $notification);
}
5 changes: 4 additions & 1 deletion src/channels/MailChannel.php
Expand Up @@ -25,6 +25,9 @@ class MailChannel extends Component implements ChannelInterface
*/
public $from;

/**
* @inheritdoc
*/
public function init()
{
parent::init();
Expand All @@ -37,7 +40,7 @@ public function send(NotifiableInterface $recipient, NotificationInterface $noti
* @var $message MailMessage
*/
$message = $notification->exportFor('mail');
$this->mailer->compose($message->view, $message->viewData)
return $this->mailer->compose($message->view, $message->viewData)
->setFrom(isset($message->from) ? $message->from : $this->from)
->setTo($recipient->routeNotificationFor('mail'))
->setSubject($message->subject)
Expand Down
57 changes: 57 additions & 0 deletions src/channels/SlackChannel.php
@@ -0,0 +1,57 @@
<?php
/**
* @copyright Anton Tuyakhov <atuyakhov@gmail.com>
*/

namespace tuyakhov\notifications\channels;


use tuyakhov\notifications\messages\SlackMessage;
use tuyakhov\notifications\NotifiableInterface;
use tuyakhov\notifications\NotificationInterface;
use yii\base\Component;
use yii\di\Instance;
use yii\helpers\ArrayHelper;
use yii\httpclient\Client;
use yii\httpclient\Response;

class SlackChannel extends Component implements ChannelInterface
{
/**
* @var Client|array|string
*/
public $httpClient;

/**
* @inheritdoc
*/
public function init()
{
parent::init();
if (!isset($this->httpClient)) {
$this->httpClient = [
'class' => Client::className(),
];
}
$this->httpClient = Instance::ensure($this->httpClient, Client::className());
}

/**
* @param NotifiableInterface $recipient
* @param NotificationInterface $notification
* @return Response
*/
public function send(NotifiableInterface $recipient, NotificationInterface $notification)
{
/** @var SlackMessage $message */
$message = $notification->exportFor('slack');
$webhookUrl = $recipient->routeNotificationFor('slack');
$text = "*{$message->subject}*\n{$message->body}";
return $this->httpClient->createRequest()
->setMethod('post')
->setUrl($webhookUrl)
->setData(ArrayHelper::merge(['text' => $text], $message->arguments))
->send();
}

}
2 changes: 1 addition & 1 deletion src/channels/TwilioChannel.php
Expand Up @@ -101,7 +101,7 @@ public function send(NotifiableInterface $recipient, NotificationInterface $noti
if (isset($message->mediaUrl)) {
$data['MedialUrl'] = $message->mediaUrl;
}
$this->httpClient
return $this->httpClient
->createRequest()
->setMethod('post')
->setUrl($this->getUri())
Expand Down
34 changes: 34 additions & 0 deletions src/events/NotificationEvent.php
@@ -0,0 +1,34 @@
<?php
/**
* @copyright Anton Tuyakhov <atuyakhov@gmail.com>
*/

namespace tuyakhov\notifications\events;


use tuyakhov\notifications\NotifiableInterface;
use tuyakhov\notifications\NotificationInterface;
use yii\base\Event;

class NotificationEvent extends Event
{
/**
* @var NotificationInterface
*/
public $notification;

/**
* @var NotifiableInterface
*/
public $recipient;

/**
* @var string
*/
public $channel;

/**
* @var mixed
*/
public $response;
}
22 changes: 22 additions & 0 deletions src/messages/SlackMessage.php
@@ -0,0 +1,22 @@
<?php
/**
* @copyright Anton Tuyakhov <atuyakhov@gmail.com>
*/

namespace tuyakhov\notifications\messages;


class SlackMessage extends AbstractMessage
{
/**
* @var array optional arguments
* @see https://api.slack.com/methods/chat.postMessage
* Example:
* [
* 'attachments' => [
* ['pretext' => 'pre-hello', 'text" => 'text-world']
* ]
* ]
*/
public $arguments = [];
}
12 changes: 11 additions & 1 deletion tests/NotifierTest.php
Expand Up @@ -4,6 +4,7 @@
*/
namespace tuyakhov\notifications\tests;

use tuyakhov\notifications\events\NotificationEvent;
use tuyakhov\notifications\Notifier;

class NotifierTest extends TestCase
Expand Down Expand Up @@ -38,7 +39,16 @@ public function testSend()
->expects($this->once())
->method('send')
->with($recipient, $notification);


$eventRaised = null;
$this->notifier->on(Notifier::EVENT_AFTER_SEND, function(NotificationEvent $event) use (&$eventRaised) {
$eventRaised = $event;
});

$this->notifier->send($recipient, $notification);
$this->assertNotEmpty($eventRaised);
$this->assertInstanceOf('tuyakhov\notifications\NotificationInterface', $eventRaised->notification);
$this->assertInstanceOf('tuyakhov\notifications\NotifiableInterface', $eventRaised->recipient);
$this->assertEquals('mockChannel', $eventRaised->channel);
}
}
48 changes: 48 additions & 0 deletions tests/SlackChannelTest.php
@@ -0,0 +1,48 @@
<?php
/**
* @copyright Anton Tuyakhov <atuyakhov@gmail.com>
*/

namespace tuyakhov\notifications\tests;


use tuyakhov\notifications\channels\SlackChannel;
use tuyakhov\notifications\messages\SlackMessage;
use yii\httpclient\Client;

class SlackChannelTest
{
public function testSend()
{
$recipient = $this->createMock('tuyakhov\notifications\NotifiableInterface');
$recipient->expects($this->once())
->method('routeNotificationFor')
->with('slack')
->willReturn('https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX');

$client = $this->createMock(Client::className());
$client->expects($this->once())
->method('send');
$client->method('createRequest')
->willReturn(\Yii::createObject([
'class' => Request::className(),
'client' => $client
]));

$channel = \Yii::createObject([
'class' => SlackChannel::className(),
'httpClient' => $client
]);

$notification = $this->createMock('tuyakhov\notifications\NotificationInterface');
$notification->expects($this->once())
->method('exportFor')
->with('slack')
->willReturn(\Yii::createObject([
'class' => SlackMessage::className(),
'body' => 'Test message body',
]));
$channel->send($recipient, $notification);

}
}

0 comments on commit b5f9b2c

Please sign in to comment.