[Laravel] 라라벨에서 Notifications 활용하기

[Laravel] 라라벨에서 Notifications 활용하기 updated_at: 2023-07-14 17:50

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);
    });
  })();
................
평점을 남겨주세요
평점 : 5.0
총 투표수 : 1

질문 및 답글