1
0
mirror of https://github.com/flarum/core.git synced 2025-10-18 18:26:07 +02:00

More powerful/extensible notifications

- Notifications can be delivered in multiple ways (alert, email)
- Different notification types can implement interfaces to allow
themselves to be delivered in these various ways
- User preferences for each notification type/method combination are
automatically registered
This commit is contained in:
Toby Zerner
2015-03-28 15:43:31 +10:30
parent 49c3fa09e6
commit bc9be30a02
15 changed files with 292 additions and 43 deletions

View File

@@ -0,0 +1,35 @@
<?php namespace Flarum\Core\Notifications;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Flarum\Core\Models\User;
class NotificationServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot(Dispatcher $events)
{
$notifier = app('Flarum\Core\Notifications\Notifier');
$notifier->registerMethod('alert', 'Flarum\Core\Notifications\Senders\NotificationAlerter');
$notifier->registerMethod('email', 'Flarum\Core\Notifications\Senders\NotificationEmailer');
$notifier->registerType('Flarum\Core\Notifications\Types\DiscussionRenamedNotification', ['alert' => true]);
$events->subscribe('Flarum\Core\Handlers\Events\DiscussionRenamedNotifier');
}
public function register()
{
$this->app->bind(
'Flarum\Core\Repositories\NotificationRepositoryInterface',
'Flarum\Core\Repositories\EloquentNotificationRepository'
);
$this->app->singleton('Flarum\Core\Notifications\Notifier');
}
}

View File

@@ -0,0 +1,59 @@
<?php namespace Flarum\Core\Notifications;
use Flarum\Core\Notifications\Types\Notification;
use Flarum\Core\Models\Notification as NotificationModel;
use Flarum\Core\Models\User;
use Illuminate\Container\Container;
class Notifier
{
protected $methods = [];
protected $types = [];
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
public function send(Notification $notification)
{
foreach ($this->methods as $method => $sender) {
$sender = $this->container->make($sender);
if ($notification->getRecipient()->shouldNotify($notification::getType(), $method) && $sender->compatibleWith($notification)) {
$sender->send($notification);
}
}
}
public function registerMethod($name, $class)
{
$this->methods[$name] = $class;
}
public function registerType($class, $defaultPreferences = [])
{
$this->types[] = $class;
NotificationModel::registerType($class);
foreach ($this->methods as $method => $sender) {
$sender = $this->container->make($sender);
if ($sender->compatibleWith($class)) {
User::registerPreference(User::notificationPreferenceKey($class::getType(), $method), 'boolval', array_get($defaultPreferences, $method, false));
}
}
}
public function getMethods()
{
return $this->methods;
}
public function getTypes()
{
return $this->types;
}
}

View File

@@ -0,0 +1,25 @@
<?php namespace Flarum\Core\Notifications\Senders;
use Flarum\Core\Notifications\Types\Notification;
use Flarum\Core\Models\Notification as NotificationModel;
use ReflectionClass;
class NotificationAlerter implements NotificationSender
{
public function send(Notification $notification)
{
$model = NotificationModel::alert(
$notification->getRecipient()->id,
$notification::getType(),
$notification->getSender()->id,
$notification->getSubject()->id,
$notification->getAlertData()
);
$model->save();
}
public function compatibleWith($className)
{
return (new ReflectionClass($className))->implementsInterface('Flarum\Core\Notifications\Types\AlertableNotification');
}
}

View File

@@ -0,0 +1,29 @@
<?php namespace Flarum\Core\Notifications\Senders;
use Flarum\Core\Notifications\Types\Notification;
use Flarum\Core\Models\Forum;
use Illuminate\Mail\Mailer;
use ReflectionClass;
class NotificationEmailer implements NotificationSender
{
public function __construct(Mailer $mailer, Forum $forum)
{
$this->mailer = $mailer;
$this->forum = $forum;
}
public function send(Notification $notification)
{
$this->mailer->send($notification->getEmailView(), ['notification' => $notification], function ($message) use ($notification) {
$recipient = $notification->getRecipient();
$message->to($recipient->email, $recipient->username)
->subject('['.$this->forum->title.'] '.$notification->getEmailSubject());
});
}
public function compatibleWith($class)
{
return (new ReflectionClass($class))->implementsInterface('Flarum\Core\Notifications\Types\EmailableNotification');
}
}

View File

@@ -0,0 +1,10 @@
<?php namespace Flarum\Core\Notifications\Senders;
use Flarum\Core\Notifications\Types\Notification;
interface NotificationSender
{
public function send(Notification $notification);
public function compatibleWith($class);
}

View File

@@ -0,0 +1,8 @@
<?php namespace Flarum\Core\Notifications\Types;
interface AlertableNotification
{
public function getAlertData();
public static function getType();
}

View File

@@ -0,0 +1,42 @@
<?php namespace Flarum\Core\Notifications\Types;
use Flarum\Core\Models\User;
use Flarum\Core\Models\DiscussionRenamedPost;
class DiscussionRenamedNotification extends Notification implements AlertableNotification
{
public $post;
public $oldTitle;
public function __construct(User $recipient, User $sender, DiscussionRenamedPost $post, $oldTitle)
{
$this->post = $post;
$this->oldTitle = $oldTitle;
parent::__construct($recipient, $sender);
}
public function getSubject()
{
return $this->post->discussion;
}
public function getAlertData()
{
return [
'number' => $this->post->number,
'oldTitle' => $this->oldTitle
];
}
public static function getType()
{
return 'discussionRenamed';
}
public static function getSubjectModel()
{
return 'Flarum\Core\Models\Discussion';
}
}

View File

@@ -0,0 +1,8 @@
<?php namespace Flarum\Core\Notifications\Types;
interface EmailableNotification
{
public function getEmailView();
public function getEmailSubject();
}

View File

@@ -0,0 +1,36 @@
<?php namespace Flarum\Core\Notifications\Types;
use Flarum\Core\Models\User;
abstract class Notification
{
protected $recipient;
protected $sender;
public function __construct(User $recipient, User $sender)
{
$this->recipient = $recipient;
$this->sender = $sender;
}
public function getRecipient()
{
return $this->recipient;
}
public function getSender()
{
return $this->sender;
}
public static function getType()
{
return null;
}
public static function getSubjectModel()
{
return null;
}
}