124호. 옵트아웃 구현하기 free

2020-04-13

옵트아웃(Opt out)은 수신자가 수신을 거부하면 더이상 메시지를 보내지 않는 방식을 말합니다. 기업이 보내는 메일이라면 거의 다 수신 거부 옵션이 있기 때문에 익숙하실 겁니다. 이를 라라벨로 구현할 때 어떻게 하면 깔끔하게 구현할 수 있을까요? 오늘은 타이튼의 리드 프로그래머 존 보나코시가 Opting Out: A Simple Solution for Conditionally Cancelling Laravel Notifications 에서 제시한 솔루션을 소개해드리고자 합니다.


문제 인식


옵트아웃을 구현하는 가장 기본적인 접근 방식은 조건에 따라 알림을 보내지 않는 것입니다.



if ($some_condition_has_been_met) {
auth()->user()->notify(new ExampleNotification);
}

하지만 이 접근법은 전송 여부를 판단할 알림의 종류가 많아지거나, 알림을 보내는 위치가 많아지면 위와 같은 조건문이 길어지고 코드베이스에 중복 코드가 발생하게 됩니다.


솔루션


아래는 아티즌 커맨드로 생성한 알림 클래스 입니다.



namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class ExampleNotification extends Notification
{
use Queueable;

/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}

/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return ['mail'];
}

/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}

/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

존은 via() 메서드가 빈 배열을 반환하면 알림이 전송되지 않는 것에 주목했습니다. 옵트아웃 방식이 필요한 모든 알림 클래스에서 공유해서 사용할 수 있도록 OptOutable 라는 이름으로 트레이트를 만듭니다.



namespace App;

trait OptOutable
{
public $channels = ['mail'];

public function via($notifiable)
{
if ($this->optOut($notifiable)) {
return [];
}

return $this->channels;
}

public function optOut($notifiable)
{
return false;
}
}

코드는 아주 간단합니다. optOut() 메서드의 반환값이 false면 via() 메서드에서 빈 배열을 반환해서 알림이 전송되지 않게 하는 것입니다.


이제 알림 클래스에 옵트아웃을 적용하기 위해 다음과 같이 합니다.

옵트아웃을 적용할 알림 클래스에 OptOutable 트레이트를 사용한다고 선언하고,

알림 클래스의 via() 메서드를 제거해서 OptOutable 트레이트의 via() 메서드가 사용되도록 합니다.

알림 클래스에 optOut() 메서드를 추가해서 옵트아웃 로직을 넣습니다.



namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class ExampleNotification extends Notification
{
use Queueable, OptOutable;

public $channels = [‘slack’];

/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}

/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}

/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}

public function optOut($notifiable) : bool
{
// 옵트아웃 로직을 작성한다
// 예) return $notifiable->opted_out_of_notifications;
}
}

마치며


트레이트 활용의 진수를 보여주는 솔루션이 아닌가 생각됩니다. 여러분은 어떻게 보셨나요?


1일 1식 라라벨 124호

2020년 4월 13일


이현석

메쉬 코리아 개발자. 바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서를 쓰고, 클린 아키텍처 인 PHP를 번역했습니다. 2020년에 출간될 Laravel Up & Running 2nd Edition을 번역하고 있습니다.