[Laravel] 라라벨에서 Notifications 활용하기
Notification 활용하기
이메일방송 외에도 SMS 혹은 Slack 과 같은 다양한 SNS를 통한 발송등에 사용할 수도 있고 데이타 베이스등에서 저장하여 웹인터페이스용으로도 사용가능합니다.
저는 node socket과 통신을 하기위해 Notification 을 종종 사용하기도 하는데 다양한 예제등을 이곳에서 설명 드리겠습니다.
Notification
Notification 생성
php artisan make:notification InvoicePaid
위와 같은 명령을 입력하면 아래와 같이 InvoicePaid.php가 생성됩니다.
기본적인 형태는 Invoice가 생성되면 메일로 보내는 것인데 우리는 redis로 보내는 기능을 만들려고 합니다.
- app
- Notifications
- InvoicePaid.php
InvoicePaid.php
................
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification
{
use Queueable;
public function __construct()
{
}
public function via($notifiable)
{
................
}
public function toMail($notifiable)
{
................
}
public function toArray($notifiable)
{
................
}
}
Notification 발송
notification을 발송하는 방법에는 두가지가 있습니다.
- Notifiable Trait을 사용하는 방법
- Notification 파사드를 사용하는 방법
Notifiable Trait을 사용하는 방법
trait을 사용하기위해서는 Model에서 Notifiable을 사용한 후 특정 클래스에서 Model을 이용하여 바로 호출 가능합니다.
1. 모델에서 정의
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}
2. 클래스에서 사용하기
선택된 user에서 InvoicePaid() 에 대한 정보를 보냅니다.
use App\Notifications\InvoicePaid;
$user->notify(new InvoicePaid($invoice));
Notification 파사드를 사용하는 방법
Notification 파사드를 사용할때는 별도로 model에서 정의하지 않아도 되므로 좀더 직관적이 되겠지만 소스코드가 늘어날 수 있다는 단점(?)
use Illuminate\Support\Facades\Notification;
Notification::send($users, new InvoicePaid($invoice));
전달할 채널 설정하기
위에서 특정사용자에게 InvoicePaid() 를 보내는 것 까지는 정의해 두었으며 이제는 어떤 채널(mail, database, broadcast, sms, sns..)로 보낼 것인지에 대해서는 설명드리겠습니다.
이부분은 Notification(InvoicePaid.php)에서 via 라는 메소드에서 정의하는데 아래와 같습니다.
public function via($notifiable)
{
return $notifiable->prefers_sms ? ['nexmo'] : ['mail', 'database'];
}
public function toMail($notifiable) { return.....} // via 가 mail일경우 handling
public function toDatabase($notifiable) { return.....} // via 가 database일경우 handling
public function toArray($notifiable) { return.....} // via 가 database일경우 handling (array는 JSON으로 인코딩되고 notifications 테이블의 data 컬럼에 저장됩니다. )
public function toBroadcast($notifiable) { return.....}
public function broadcastOn(){ return.....}
Queueing Notifications
notification을 보낼때 외부채널을 사용한다면 많은 시간이 걸릴 수 있다. 어플리케시션의 반응 속도를 높이기 위해 여러분의 클래스에 ShouldQueue 인터페이스와 Queueable 트래잇을 사용하기를 추천드립니다.
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
}
이방법을 사용할때 저는 route [] not defined 라는 에러메시지를 접했는데 ueue:work 를 새로 시작함으로서 해결되었습니다.
예제
메일 Notification
public function toMail(object $notifiable): MailMessage
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->lineIf($this->amount > 0, "Amount paid: {$this->amount}")
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
Redis 로 보내는 코딩
InvoicePaid.php
................
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Redis;
class InvoicePaid extends Notification
{
use Queueable;
private $messages;
/**
* Create a new notification instance.
* @param $type String add | substract | reset
* @param $flag String users | deposits | withdrawals | settles | qna
* @return void
*/
public function __construct($messages)
{
$this->messages = $messages;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
Redis::publish('InvoiceMessage', json_encode($messages)); // Redis::publish([key], [value]);
}
}
메시지를 받아서 redis로 넣어주는 것까지 프로그램 되었습니다.
라라벨에서 Message 보내기
예제 1 Notification 직접호출
- congtroller
................
use Notification;
use App\Notifications\InvoicePaid;
class InvoiceController extends Controller
{
................
public function create() {
Notification::send(null, new InvoicePaid([]));
}
}
예제 2 Model을 사용하여 호출
Model을 이용하여 사용하는 방식입니다.
app > Models > Invoice.php
................
use Illuminate\Notifications\Notifiable;
class Invoice extends Model
{
use Notifiable;
................
}
- controller
................
use App\Notifications\InvoicePaid;
use App\Models\Invoice;
class InvoiceController extends Controller
{
................
public function create() {
$invoice = new Invoice;
$invoice->notify(new InvoicePaid([]));
}
}
nodeJs를 이용한 subscribe
이것을 설명하기전에 redis의 기본 기능중의 하나인 publish, subscribe의 기능을 간단히 알아야 합니다.
redis는 데이타의 저장/수정/삭제/가져오기 뿐만 아니라 publish, subscribe 기능을 제공하는데 어떤 데이타를 publish로 redis로 전달하면 redis는 즉각 이 데이타를 subscribe하는 어떤 곳으로 내보냅니다.
따라서 이 기능을 잘 활용하면 이종 언어간의 통신도 수월하게 할 수 있습니다.
- node-redis.js
const redis = require('redis');
const client = redis.createClient.....
................
client.subscribe('InvoiceMessage'); // laravel 에서 Redis::publish() 에서 사용한 키값인 message
client.subscribe('other keys'); // subscribe 하고 싶은 다른 키값도 이렇게 계속적으로 정의하시면 됩니다.
// 위의 subscribe에서 특정 키를 정의하게 되면 아래에서 그 특정 키를 계속 리스닝합니다.
client.on('message', (channel, messages) => {
switch (channel) { // 키값이 channel이됩니다.
case 'InvoiceMessage':
console.log(messages); // messages 는 Redis::publish() 의 value 가 됩니다.
break;
case 'other keys':
break;
}
});
여기까지가 laravel에서 redis를 통해 데이타를 보내고 그 데이타를 nodejs에서 redis 를 통해 받는 것을 처리 하였습니다.
[추가] nodejs에 redis로 통해 받은 데이타를 소켓을 이용하여 다시 내 보내기
저 같은 경우는 events라는 패키지를 사용하여 처리합니다.
- events.js
const EventEmitter = require('events');
exports.myEmitter = new EventEmitter();
- node-redis.js
const event = require('./events');
................
client.on('message', (channel, messages) => {
switch (channel) { // 키값이 channel이됩니다.
case 'InvoiceMessage':
event.myEmitter.emit('InvoiceMessage', messages);
break;
case 'other keys':
break;
}
});
- socket.js
................
const event = require('./events');
module.exports = function(io) {
(function() {
event.myEmitter.on('InvoiceMessage', (data) => {
io.in(room).emit('InvoceIssued', data);
});
})();
................