source

php 및 mysql을 사용한 알림 시스템

lovecheck 2022. 12. 28. 21:48
반응형

php 및 mysql을 사용한 알림 시스템

학교에 알림 시스템을 도입하고 싶었지만, 일반인에게 공개되지 않은 php/mysql 웹 앱이기 때문에 트래픽을 많이 받지 않습니다."하루 500-1000 방문자"

1. 초기 접근법은 MYSQL 트리거를 사용하는 것이었습니다.

는 Mysql을 했다.AFTER INSERT triggernotifications아, 아, 아, 아, 아, 아, 아, 아, 아.

'CREATE TRIGGER `notify_new_homwork` AFTER INSERT ON `homeworks`
 FOR EACH ROW INSERT INTO `notifications` 
    ( `from_id`, `note`, `class_id`) 
 VALUES 
    (new.user_id, 
        concat('A New homework Titled: "',left(new.title,'50'),
        '".. was added' )
    ,new.subject_id , 11);'

이러한 블랙 매직은 매우 잘 작동하지만, 이 알림이 "사용자에게 새로운 알림 수를 표시하기 위해" 새로운 알림인지 추적할 수 없어서 알림이라는 페이지를 추가했습니다.

알림은 다음과 같은 방법으로 검색됩니다.

SELECT n.* from notifications n 
JOIN user_class on user_class.class_id = n.class_id where user_class.user_id = X;

주의: 테이블 user_class link user to class "user_id, class_id, subject_id" -subject는 사용자가 교사인 경우를 제외하고 늘입니다.

이제 저의 다음 도전은요.

  1. 사용자별로 새로운 알림과 오래된 알림을 추적하는 방법
  2. 사용자와 유사한 알림을 한 줄로 집약하려면 어떻게 해야 합니까?

예: 2명의 사용자가 코멘트를 한 경우 새 행을 삽입하지 않고 이전 행을 'userx 및 1개의 다른 코멘트를 hw'와 같이 업데이트합니다.

정말 감사해요.

편집

아래 답변과 같이 읽기/읽기 플래그를 행에 설정하려면 학급 전체의 행뿐만 아니라 학생 한 명당 행이 필요합니다.즉, 트리거를 편집해서

insert into notifications (from_id,note,student_id,isread)
select new.user_id,new.note,user_id,'0' from user_class where user_class.class_id = new.class_id group by user_class.user_id

이 질문은 9개월이 지났기 때문에 아직 OP가 답을 필요로 하는지는 모르겠지만, 많은 조회수와 맛있는 현상금(독일어 속담)을 더하고 싶습니다.

이 투고에서는 알림 시스템을 구축하는 방법에 대해 간단한 예를 들어 보겠습니다.

편집: 음, 좋아, 내가 예상했던 것보다 훨씬 더 오래 걸렸어.결국엔 너무 피곤했어요, 미안해요.

WTLDR;

질문 1: 모든 알림에 플래그가 있습니다.

질문 2: 모든 알림을 데이터베이스에 단일 레코드로 저장하고 요청이 있을 때 그룹화합니다.


구조.

알림은 다음과 같이 표시됩니다.

+---------------------------------------------+
| ▣ James has uploaded new Homework: Math 1+1 |
+---------------------------------------------+
| ▣ Jane and John liked your comment: Im s... | 
+---------------------------------------------+
| ▢ The School is closed on independence day. |
+---------------------------------------------+

커튼 뒤에는 이렇게 보일 수 있습니다.

+--------+-----------+--------+-----------------+-------------------------------------------+
| unread | recipient | sender | type            | reference                                 |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true   | me        | James  | homework.create | Math 1 + 1                                |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true   | me        | Jane   | comment.like    | Im sick of school                         |
+--------+-----------+--------+-----------------+-------------------------------------------+
| true   | me        | John   | comment.like    | Im sick of school                         |
+--------+-----------+--------+-----------------+-------------------------------------------+
| false  | me        | system | message         | The School is closed on independence day. |
+--------+-----------+--------+-----------------+-------------------------------------------+

주의: 데이터베이스 내에서 알림을 그룹화하는 것은 권장하지 않습니다.실행 시 이를 통해 작업 유연성이 크게 향상됩니다.

  • 않음
    모든 알림에는 수신인이 알림을 이미 열었는지 여부를 나타내는 플래그가 있어야 합니다.

  • 이치노

  • 이치노
  • ★★★
    「 「 」는, 「 」를 참조해 주세요. 하면 의 다양한 타입에 하는 특별한 할 수 .이렇게 하면 백엔드 내에 다양한 알림 유형에 대한 특수 핸들러를 생성할 수 있습니다.데이터베이스 내에 저장되는 데이터의 양을 줄이고 보다 유연하게 알림 번역, 과거 메시지 변경 등을 할 수 있습니다.
  • ★★★
    대부분의 알림에는 데이터베이스 또는 응용 프로그램의 레코드에 대한 참조가 포함됩니다.

지금까지 작업한 모든 시스템은 알림에 대해 1:1단순한 참조 관계를 가지고 있으며, 1:1로 예를 계속 진행한다는 을 명심해야 합니다.또한 참조되는 개체 유형은 알림 유형에 의해 정의되므로 필드를 정의할 필요가 없습니다.

SQL 테이블

이제 SQL의 실제 테이블 구조를 정의할 때 데이터베이스 설계 측면에서 몇 가지 결정을 내립니다.다음과 같은 간단한 솔루션을 사용합니다.

+--------------+--------+---------------------------------------------------------+
| column       | type   | description                                             |
+--------------+--------+---------------------------------------------------------+
| id           | int    | Primary key                                             |
+--------------+--------+---------------------------------------------------------+
| recipient_id | int    | The receivers user id.                                  |
+--------------+--------+---------------------------------------------------------+
| sender_id    | int    | The sender's user id.                                   |
+--------------+--------+---------------------------------------------------------+
| unread       | bool   | Flag if the recipient has already read the notification |
+--------------+--------+---------------------------------------------------------+
| type         | string | The notification type.                                  |
+--------------+--------+---------------------------------------------------------+
| parameters   | array  | Additional data to render different notification types. |
+--------------+--------+---------------------------------------------------------+
| reference_id | int    | The primary key of the referencing object.              |
+--------------+--------+---------------------------------------------------------+
| created_at   | int    | Timestamp of the notification creation date.            |
+--------------+--------+---------------------------------------------------------+

또는 게으른 사람에게는 SQL create table 명령어를 사용하여 다음 예를 제시합니다.

CREATE TABLE `notifications` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `recipient_id` int(11) NOT NULL,
  `sender_id` int(11) NOT NULL,
  `unread` tinyint(1) NOT NULL DEFAULT '1',
  `type` varchar(255) NOT NULL DEFAULT '',
  `parameters` text NOT NULL,
  `reference_id` int(11) NOT NULL,
  `created_at` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

PHP 서비스

이 실장은, 애플리케이션의 요구에 완전하게 의존합니다.주의:이는 PHP에서 알림 시스템을 구축하는 방법에 대한 골든 스탠다드가 아닌 예입니다.

통지 모델

이며, 인 방법만 것은 .messageForNotification ★★★★★★★★★★★★★★★★★」messageForNotifications다양한 알림 유형으로 구현될 것으로 예상했습니다.

abstract class Notification
{
    protected $recipient;
    protected $sender;
    protected $unread;
    protected $type;
    protected $parameters;
    protected $referenceId;
    protected $createdAt;

    /**
     * Message generators that have to be defined in subclasses
     */
    public function messageForNotification(Notification $notification) : string;
    public function messageForNotifications(array $notifications) : string;

    /**
     * Generate message of the current notification.
     */ 
    public function message() : string
    {
        return $this->messageForNotification($this);
    }
}

컨스트럭터, getter, setter 등을 자신의 스타일로 추가해야 하기 때문에 즉시 사용할 수 있는 알림 시스템은 제공하지 않습니다.

통지 유형

새로 수 .Notification서브클래스를 만듭니다.다음 예제에서는 코멘트의 동일한 액션을 처리합니다.

  • Ray는 당신의 코멘트가 마음에 들었습니다.(알림 1개)
  • 존과 제인은 당신의 코멘트가 마음에 들었습니다.(알림 2개)
  • Jane, Johnny, James, Jenny가 당신의 코멘트를 마음에 들었습니다.(알림 4개)
  • 조니, 제임스 등 12명이 당신의 코멘트를 마음에 들었습니다(14통지)

구현 예:

namespace Notification\Comment;

class CommentLikedNotification extends \Notification
{
    /**
     * Generate a message for a single notification
     * 
     * @param Notification              $notification
     * @return string 
     */
    public function messageForNotification(Notification $notification) : string 
    {
        return $this->sender->getName() . 'has liked your comment: ' . substr($this->reference->text, 0, 10) . '...'; 
    }

    /**
     * Generate a message for a multiple notifications
     * 
     * @param array              $notifications
     * @return string 
     */
    public function messageForNotifications(array $notifications, int $realCount = 0) : string 
    {
        if ($realCount === 0) {
            $realCount = count($notifications);
        }

        // when there are two 
        if ($realCount === 2) {
            $names = $this->messageForTwoNotifications($notifications);
        }
        // less than five
        elseif ($realCount < 5) {
            $names = $this->messageForManyNotifications($notifications);
        }
        // to many
        else {
            $names = $this->messageForManyManyNotifications($notifications, $realCount);
        }

        return $names . ' liked your comment: ' . substr($this->reference->text, 0, 10) . '...'; 
    }

    /**
     * Generate a message for two notifications
     *
     *      John and Jane has liked your comment.
     * 
     * @param array              $notifications
     * @return string 
     */
    protected function messageForTwoNotifications(array $notifications) : string 
    {
        list($first, $second) = $notifications;
        return $first->getName() . ' and ' . $second->getName(); // John and Jane
    }

    /**
     * Generate a message many notifications
     *
     *      Jane, Johnny, James and Jenny has liked your comment.
     * 
     * @param array              $notifications
     * @return string 
     */
    protected function messageForManyNotifications(array $notifications) : string 
    {
        $last = array_pop($notifications);

        foreach($notifications as $notification) {
            $names .= $notification->getName() . ', ';
        }

        return substr($names, 0, -2) . ' and ' . $last->getName(); // Jane, Johnny, James and Jenny
    }

    /**
     * Generate a message for many many notifications
     *
     *      Jonny, James and 12 other have liked your comment.
     * 
     * @param array              $notifications
     * @return string 
     */
    protected function messageForManyManyNotifications(array $notifications, int $realCount) : string 
    {
        list($first, $second) = array_slice($notifications, 0, 2);

        return $first->getName() . ', ' . $second->getName() . ' and ' .  $realCount . ' others'; // Jonny, James and 12 other
    }
}

통지 매니저

응용 프로그램 내에서 알림으로 작업하려면 알림 관리자 같은 것을 만듭니다.

class NotificationManager
{
    protected $notificationAdapter;

    public function add(Notification $notification);

    public function markRead(array $notifications);

    public function get(User $user, $limit = 20, $offset = 0) : array;
}

notificationAdapter이 예의 mysql에서는 속성은 데이터 백엔드와 직접 통신하는 로직을 포함해야 합니다.

통지 작성

「」를 사용합니다.mysql트리거는 잘못된 해결책이 없기 때문에 틀린 것이 아닙니다.효과가 있는 것, 효과가 있는 것...그러나 데이터베이스로 애플리케이션 로직을 처리하지 않는 것이 좋습니다.

따라서 알림 관리자 내에서 다음과 같은 작업을 수행할 수 있습니다.

public function add(Notification $notification)
{
    // only save the notification if no possible duplicate is found.
    if (!$this->notificationAdapter->isDoublicate($notification))
    {
        $this->notificationAdapter->add([
            'recipient_id' => $notification->recipient->getId(),
            'sender_id' => $notification->sender->getId()
            'unread' => 1,
            'type' => $notification->type,
            'parameters' => $notification->parameters,
            'reference_id' => $notification->reference->getId(),
            'created_at' => time(),
        ]);
    }
}

add의 of의 notificationAdapterraw mysql insert 명령어일 수 있습니다.이 어댑터 추상화를 사용하면 mysql에서 mongodb와 같은 문서 기반 데이터베이스로 쉽게 전환할 수 있으므로 알림 시스템에 적합합니다.

isDoublicatenotificationAdapter이 이미 만 하면 .recipient,sender,type ★★★★★★★★★★★★★★★★★」reference.


이것은 어디까지나 예시입니다.(또, 이 투고는 터무니없이 길어지고 있습니다--)


따라서 선생님이 숙제를 업로드 할 때 액션이 있는 컨트롤러가 있다고 가정하면:

function uploadHomeworkAction(Request $request)
{
    // handle the homework and have it stored in the var $homework.

    // how you handle your services is up to you...
    $notificationManager = new NotificationManager;

    foreach($homework->teacher->students as $student)
    {
        $notification = new Notification\Homework\HomeworkUploadedNotification;
        $notification->sender = $homework->teacher;
        $notification->recipient = $student;
        $notification->reference = $homework;

        // send the notification
        $notificationManager->add($notification);
    }
}

모든 선생님 학생이 새로운 숙제를 업로드 할 때 알림을 만듭니다.

통지 읽기

이제 어려운 부분이 오네요.PHP 측 그룹화의 문제는 현재 사용자의 모든 알림을 로드해야 올바르게 그룹화할 수 있다는 것입니다.이것은 좋지 않습니다.사용자가 적은 경우에도 문제가 없을 수 있지만, 그렇다고 해서 좋은 것은 아닙니다.

간단한 해결책은 요청된 알림 수를 제한하고 이러한 알림만 그룹화하는 것입니다.비슷한 알림이 별로 없을 때(20개당 3~4개 등) 정상적으로 동작합니다.그러나 사용자/학생의 게시물이 100개 정도의 좋아요를 받고 마지막 20개의 알림만 선택한다고 가정해 보겠습니다.그 후, 유저는 20명의 유저가 그의 투고를 좋아했다고 하는 것만을 알 수 있습니다.

"올바른" 솔루션은 데이터베이스에 이미 있는 알림을 그룹화하고 알림 그룹별로 일부 샘플만 선택하는 것입니다.알림 메시지에 실제 개수를 삽입하기만 하면 됩니다.

아래 텍스트를 읽지 않으셨기 때문에 몇 가지 토막으로 넘어가겠습니다.

select *, count(*) as count from notifications
where recipient_id = 1
group by `type`, `reference_id`
order by created_at desc, unread desc
limit 20

이제 지정된 사용자에 대해 어떤 알림이 있어야 하는지, 그룹에 얼마나 많은 알림이 포함되어 있는지 알게 되었습니다.

그리고 이제 형편없는 부분이야그룹별로 쿼리를 실행하지 않고 그룹별로 제한된 수의 알림을 선택할 수 있는 더 나은 방법을 찾을 수 없었습니다.이곳의 모든 제안은 매우 환영입니다.

그래서 저는 이렇게 합니다.

$notifcationGroups = [];

foreach($results as $notification)
{
    $notifcationGroup = ['count' => $notification['count']];

    // when the group only contains one item we don't 
    // have to select it's children
    if ($notification['count'] == 1)
    {
        $notifcationGroup['items'] = [$notification];
    }
    else
    {
        // example with query builder
        $notifcationGroup['items'] = $this->select('notifications')
            ->where('recipient_id', $recipient_id)
            ->andWehere('type', $notification['type'])
            ->andWhere('reference_id', $notification['reference_id'])
            ->limit(5);
    }

    $notifcationGroups[] = $notifcationGroup;
}

, 그럼 이제 '해 보겠습니다.notificationAdapters get는 이 합니다.

[
    {
        count: 12,
        items: [Note1, Note2, Note3, Note4, Note5] 
    },
    {
        count: 1,
        items: [Note1] 
    },
    {
        count: 3,
        items: [Note1, Note2, Note3] 
    }
]

그룹에는 항상 알림이 1개 이상 있고 주문 시 읽지 않은 알림과 새로 만들기 알림을 선호하기 때문에 렌더링의 샘플로 첫 번째 알림을 사용할 수 있습니다.

따라서 다음과 같은 그룹화된 알림을 사용하려면 새 개체가 필요합니다.

class NotificationGroup
{
    protected $notifications;

    protected $realCount;

    public function __construct(array $notifications, int $count)
    {
        $this->notifications = $notifications;
        $this->realCount = $count;
    }

    public function message()
    {
        return $this->notifications[0]->messageForNotifications($this->notifications, $this->realCount);
    }

    // forward all other calls to the first notification
    public function __call($method, $arguments)
    {
        return call_user_func_array([$this->notifications[0], $method], $arguments);
    }
}

그리고 마지막으로 우리는 실제로 대부분의 것들을 합칠 수 있습니다. '가져다'의 '의 '가져다' 기능을 할 수 있습니다.NotificationManager음음음같 뭇매하다

public function get(User $user, $limit = 20, $offset = 0) : array
{
    $groups = [];

    foreach($this->notificationAdapter->get($user->getId(), $limit, $offset) as $group)
    {
        $groups[] = new NotificationGroup($group['notifications'], $group['count']);
    }

    return $gorups;
}

마지막으로 생각할 수 있는 컨트롤러의 액션에 대해 설명하겠습니다.

public function viewNotificationsAction(Request $request)
{
    $notificationManager = new NotificationManager;

    foreach($notifications = $notificationManager->get($this->getUser()) as $group)
    {
        echo $group->unread . ' | ' . $group->message() . ' - ' . $group->createdAt() . "\n"; 
    }

    // mark them as read 
    $notificationManager->markRead($notifications);
}

답변:

  1. 알림에 읽기/읽지 않은 변수를 도입합니다.그런 다음 다음을 수행하여 읽지 않은 알림만 가져올 수 있습니다.WHERE 상태 = SQL에서 '읽지 않음'입니다.

  2. ★★★★★★★★★★★...알림을 푸시해야 합니다.GROUP BY: 그룹바이당신은 새로운 숙제처럼 뭔가 독특한 것을 그룹화하고 싶을 것이다.★★★★★★★★★★★★★★... BY group grouphomework.id

사용자의 ID와 사용자가 읽은 것으로 표시하려는 알림 ID를 포함하는 NotificationsRead 테이블을 만드는 문제를 해결할 수 있습니다.(이렇게 하면 각 학생과 교사를 분리할 수 있습니다.)그런 다음 해당 테이블을 알림 테이블에 조인할 수 있습니다. 그러면 오래된 것으로 간주할지 새 것으로 간주할지 알 수 있습니다.

부분에서는 게글레토의요, 게글레토의 은 게글레토의 알림으로 할 수 있습니다.SELECT *, COUNT(*) AS counter WHERE ... GROUP BY 'type'그러면 동일한 유형의 제품이 몇 개 있는지 알 수 있으며 'userx 및 hw에 대한 댓글 1개'를 표시할 수 있습니다.

또한 표시할 텍스트 전체를 저장하지 말고 from_id, class_id, type, name 등 필요한 정보를 저장하는 것이 좋습니다.이렇게 하면 나중에 필요에 따라 메커니즘을 쉽게 변경할 수 있고 저장도 줄일 수 있습니다.

앱을 사용하지 않는 방법을 찾고 계신 분은 앱을 사용하지 않고 바닐라 PHP와 MySQL을 이용하실 수 있습니다.숙제를 추가하면 알림을 추가할 수 있습니다.(예, SQL 주입에 개방되어 있지만 단순성을 위해 일반 MySQL을 사용하고 있습니다.) 누군가가 숙제를 추가할 때 사용하는 SQL:

$noti_homework = "INSERT INTO homework(unread, username, recipient, topic) VALUES(true, user_who_added_hw, user_who_receives_notification, homework_name);

그런 다음 통지가 읽지 않았는지 확인할 수 있습니다.

$noti_select = "SELECT FROM homework WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$noti_s_result = $conn->query($noti_select);
$noti_s_row = $noti_s_result = $noti_s_result->fetch_assoc();
if ($noti_s_row['unread'] == true) {
}

마지막으로 알림이 사실일 경우 에코할 수 있습니다.

if ($noti_s_row['unread'] == true) {
  echo $noti_s_row['username'] . " has sent out the homework " . $noti_s_row['homework'] . ".";
}

댓글을 좋아하는 방법은 비슷하고 사실 훨씬 쉽다.

$noti_like = "INSERT INTO notification_like(unread, username, recepient), VALUES(true, user_who_followed, user_who_recieves_notification);

그런 다음 다음과 같이 행을 에코하는 동일한 패턴을 따릅니다.

$noti_like = "INSERT INTO notification_like(unread, username, recipient), VALUES(true, user_who_followed, user_who_receives_notification);
$noti_like_select = "SELECT FROM notification_like WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$noti_l_result = $conn->query($noti_like_select);
$noti_l_row = $noti_s_result = $noti_l_result->fetch_assoc();
if ($noti_l_row['unread'] == true) {
  echo $noti_l_row['username'] . " has liked your topic!";
}

통지량을 취득하려면 , 다음의 순서에 따릅니다.

$count_like = "SELECT COUNT(*) FROM notification_like WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$num_count = $count_like->fetch_row();
$count_hw = "SELECT COUNT(*) FROM homework WHERE recipient='".$_SESSION['username']."' AND unread='true'";
$num_count_hw = $count_hw->fetch_row();

PHP를 사용하면 $num_count와 $num_count_hw의 두 변수를 에코할 수 있습니다.

$num_count_real = $num_count[0];
$num_count_hw_real = $num_count_hw[0];
echo $num_count_real + $num_count_hw_real;

이 코드는 모두 FYI로 테스트되지 않았습니다.도움이 됐으면 좋겠다:)

언급URL : https://stackoverflow.com/questions/32717824/notification-system-using-php-and-mysql

반응형